00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #ifndef WAVELETDECOMP_H
00019 #define WAVELETDECOMP_H
00020
00021 #include <cassert>
00022 #include <iostream>
00023 #include <blitz/array.h>
00024
00025 #include "Wavelet.h"
00026
00027 namespace bwave {
00028
00029
00035
00036 enum DecompType {
00037 STD_DECOMP=0,
00038 NONSTD_DECOMP=1
00039 };
00040
00041
00057
00058 enum CoeffStorage {
00059 NESTED_COEFFS=0,
00060 SEPARATED_COEFFS=1
00061 };
00062
00063
00071
00072 template<int tp_rank> class WaveletDecomp {
00073 protected:
00074 Wavelet m_wavelet;
00075 DecompType m_decomp;
00076 CoeffStorage m_storageMode;
00077 ExtensionMode m_extMode;
00078 int m_maxLevel;
00079 blitz::TinyVector<bool, tp_rank> m_dimSelect;
00080
00081 template<class tp_Type> inline void trafoStep
00082 (blitz::Array<tp_Type,tp_rank> &data, int targetDim, bool inverse) const;
00083
00084 template<class tp_Type> inline blitz::TinyVector<int, tp_rank> waveletDecompose
00085 (blitz::Array<tp_Type,tp_rank> &data, int maxlevel=0) const;
00086
00087 template<class tp_Type> inline blitz::TinyVector<int, tp_rank> waveletRecompose
00088 (blitz::Array<tp_Type,tp_rank> &data, int maxlevel=0) const;
00089
00090 public:
00092 const Wavelet& wavelet() const { return m_wavelet; }
00093
00096 DecompType decompType() const { return m_decomp; }
00097
00099 int maxLevel() const { return m_maxLevel; }
00100
00104 CoeffStorage storageMode() const { return m_storageMode; }
00105
00113 CoeffStorage storageMode(CoeffStorage newCS)
00114 { return m_storageMode=newCS; }
00115
00119 ExtensionMode extensionMode() const { return m_extMode; }
00120
00125 ExtensionMode extensionMode(ExtensionMode newEM)
00126 { return m_extMode=newEM; }
00127
00129 const blitz::TinyVector<bool, tp_rank>& selectedDims() { return m_dimSelect; }
00130
00132 bool dimSelected(int dim) const { return m_dimSelect(dim); }
00133
00136 blitz::TinyVector<bool, tp_rank> dimSelection() const { return m_dimSelect; }
00137
00144 blitz::TinyVector<bool, tp_rank> dimSelection(blitz::TinyVector<bool, tp_rank> selection)
00145 { return m_dimSelect = selection; }
00146
00158 template<class tp_Type> inline blitz::TinyVector<int, tp_rank> apply
00159 (blitz::Array<tp_Type,tp_rank> &data) const
00160 {
00161 assert(storageMode()==NESTED_COEFFS);
00162 return waveletDecompose(data, m_maxLevel);
00163 }
00164
00174 template<class tp_Type> inline blitz::TinyVector<int, tp_rank> applyInv
00175 (blitz::Array<tp_Type,tp_rank> &data) const
00176 {
00177 assert(storageMode()==NESTED_COEFFS);
00178 return waveletRecompose(data, m_maxLevel);
00179 }
00180
00181
00196 template<class tp_Type>
00197 blitz::Array< blitz::TinyVector<int, tp_rank>, 1> indices(
00198 blitz::Array<tp_Type,tp_rank> &data) const;
00199
00235 template<class tp_Type>
00236 blitz::Array<tp_Type,tp_rank> coeffs(blitz::Array<tp_Type,tp_rank> &data,
00237 blitz::TinyVector<int, tp_rank> indices) const;
00238
00246 double normFactor(blitz::TinyVector<int, tp_rank> indices) const {
00247 blitz::TinyVector<double, 2> baseNF(wavelet().normS(), wavelet().normD());
00248 double norm=1;
00249 for (int i=0; i<tp_rank; ++i) {
00250 norm *= indices(i)>=0 ? pow(baseNF(0), indices(i))
00251 : pow(baseNF(0), -indices(i)-1) * baseNF(1);
00252 }
00253 return norm;
00254 }
00255
00256
00262 WaveletDecomp(WaveletDecomp<tp_rank> other, CoeffStorage cs)
00263 : m_wavelet(other.m_wavelet), m_decomp(other.m_decomp), m_storageMode(cs),
00264 m_extMode(other.m_extMode), m_maxLevel(other.m_maxLevel), m_dimSelect(other.m_dimSelect)
00265 {}
00266
00279 WaveletDecomp(Wavelet wl, DecompType decomp=NONSTD_DECOMP,
00280 int maxlevel=0, CoeffStorage cs=NESTED_COEFFS, ExtensionMode em=CONSTANT_EXT)
00281 : m_wavelet(wl), m_decomp(decomp), m_storageMode(cs), m_extMode(em),
00282 m_maxLevel(maxlevel)
00283 { m_dimSelect = true; }
00284 };
00285
00286
00287 template<int tp_rank> template<class tp_Type>
00288 inline void WaveletDecomp<tp_rank>::trafoStep
00289 (blitz::Array<tp_Type,tp_rank> &data, int targetDim, bool inverse) const
00290 {
00291 using namespace blitz;
00292 assert( targetDim < tp_rank );
00293 TinyVector<int, tp_rank> stride=1, lboundS=data.lbound(), lboundD=data.lbound();
00294 stride(targetDim)=2;
00295 lboundD(targetDim)+=1;
00296
00297 TinyVector<int, tp_rank> uboundS, uboundD;
00298 for (int dim=0; dim<tp_rank; ++dim) {
00299 uboundS(dim) = lboundS(dim) + (data.ubound()(dim)-lboundS(dim)) / stride(dim) * stride(dim);
00300 uboundD(dim) = lboundD(dim) + (data.ubound()(dim)-lboundD(dim)) / stride(dim) * stride(dim);
00301 }
00302
00303 StridedDomain<tp_rank> subsetS(lboundS, uboundS, stride);
00304 StridedDomain<tp_rank> subsetD(lboundD, uboundD, stride);
00305 blitz::Array<tp_Type,tp_rank> s( data(subsetS) );
00306 blitz::Array<tp_Type,tp_rank> d( data(subsetD) );
00307
00308 int n = data.size() / data.extent(targetDim);
00309
00310 TinyVector<int, tp_rank> position = data.lbound();
00311 int lastDim = targetDim!=tp_rank-1 ? tp_rank-1 : tp_rank-2;
00312
00313 for (int i=0; i<n; ++i) {
00314 Array<tp_Type, 1> sliceS( slice(s, targetDim, position) );
00315 Array<tp_Type, 1> sliceD( slice(d, targetDim, position) );
00316 if (!inverse) m_wavelet.lift(sliceS, sliceD, m_extMode);
00317 else m_wavelet.invLift(sliceS, sliceD, m_extMode);
00318
00319 if (i < n-1) {
00320 position(lastDim) += 1;
00321 for (int d=lastDim; d>0; --d) {
00322 if ( (d!=targetDim) && (position(d)>data.ubound(d)) ) {
00323 position(d)=data.lbound(d);
00324 ++position(targetDim!=d-1 ? d-1 : d-2);
00325 }
00326 }
00327 }
00328 }
00329
00330 }
00331
00332
00333 template<int tp_rank> template<class tp_Type>
00334 inline blitz::TinyVector<int, tp_rank>
00335 WaveletDecomp<tp_rank>::waveletDecompose
00336 (blitz::Array<tp_Type,tp_rank> &data, int maxlevel) const
00337 {
00338 using namespace blitz;
00339
00340 TinyVector<int, tp_rank> depth=0;
00341
00342 switch (decompType()) {
00343 case STD_DECOMP: assert(false); break;
00344 case NONSTD_DECOMP: {
00345 for (int dim=0; dim<tp_rank; ++dim)
00346 if ( (data.extent(dim)>1) && dimSelected(dim) ) {
00347 trafoStep(data, dim, false);
00348 depth(dim) += 1;
00349 }
00350
00351 bool descend = false;
00352 for (int dim=0; dim<tp_rank; ++dim)
00353 if ((data.extent(dim)>2) && dimSelected(dim)) descend = true;
00354
00355 if ( descend && ((maxlevel==0) || (maxlevel>1)) ) {
00356 TinyVector<int, tp_rank> stride, lbound, ubound;
00357 for (int dim=0; dim<tp_rank; ++dim) {
00358 stride(dim) = dimSelected(dim) ? 2 : 1;
00359 lbound(dim) = data.lbound()(dim);
00360 ubound(dim) = lbound(dim) + (data.ubound()(dim)-lbound(dim)) / stride(dim) * stride(dim);
00361 }
00362 StridedDomain<tp_rank> subsetS(lbound, ubound, stride);
00363 blitz::Array<tp_Type,tp_rank> sub(data(subsetS));
00364
00365 depth += waveletDecompose(sub, maxlevel>0 ? maxlevel-1 : 0);
00366 }
00367
00368 break;
00369 }
00370 default: assert(false);
00371 }
00372
00373 return depth;
00374 }
00375
00376
00377 template<int tp_rank> template<class tp_Type>
00378 inline blitz::TinyVector<int, tp_rank>
00379 WaveletDecomp<tp_rank>::waveletRecompose
00380 (blitz::Array<tp_Type,tp_rank> &data, int maxlevel) const
00381 {
00382 using namespace blitz;
00383
00384 TinyVector<int, tp_rank> depth=0;
00385
00386 switch (decompType()) {
00387 case STD_DECOMP: assert(false); break;
00388 case NONSTD_DECOMP: {
00389 bool descend = false;
00390 for (int dim=0; dim<tp_rank; ++dim)
00391 if ((data.extent(dim)>2) && dimSelected(dim)) descend = true;
00392
00393 if ( descend && ((maxlevel==0) || (maxlevel>1)) ) {
00394 TinyVector<int, tp_rank> stride, lbound, ubound;
00395 for (int dim=0; dim<tp_rank; ++dim) {
00396 stride(dim) = dimSelected(dim) ? 2 : 1;
00397 lbound(dim) = data.lbound()(dim);
00398 ubound(dim) = lbound(dim) + (data.ubound()(dim)-lbound(dim)) / stride(dim) * stride(dim);
00399 }
00400 StridedDomain<tp_rank> subsetS(lbound, ubound, stride);
00401 blitz::Array<tp_Type,tp_rank> sub(data(subsetS));
00402
00403 depth += waveletRecompose(sub, maxlevel>0 ? maxlevel-1 : 0);
00404 }
00405
00406 for (int dim=tp_rank-1; dim>=0; --dim)
00407 if ( (data.extent(dim)>1) && dimSelected(dim) ) {
00408 trafoStep(data, dim, true);
00409 depth(dim) -= 1;
00410 }
00411
00412 break;
00413 }
00414 default: assert(false);
00415 }
00416
00417 return depth;
00418 }
00419
00420
00421 template<int tp_rank> template<class tp_Type>
00422 blitz::Array< blitz::TinyVector<int, tp_rank>, 1>
00423 WaveletDecomp<tp_rank>::indices(
00424 blitz::Array<tp_Type,tp_rank> &data) const
00425 {
00426 using namespace blitz;
00427 TinyVector<int, tp_rank> decompDepth;
00428 Array< TinyVector<int, tp_rank>, 1> idx;
00429
00430 for (int dim=0; dim<tp_rank; ++dim) {
00431
00432 int val = (int) ceil(log((double)data.extent(dim)-0.1) / log(2.0));
00433 decompDepth(dim) = dimSelected(dim) ?
00434 (m_maxLevel>0 ? min(m_maxLevel, val) : val) : 0;
00435 }
00436
00437 switch (decompType()) {
00438 case STD_DECOMP: assert(false); break;
00439 case NONSTD_DECOMP: {
00440 int maxLevel = max(decompDepth);
00441 idx.resize(max(1, maxLevel*(1<<tp_rank)));
00442 idx(0) = 0;
00443 int begin=0, end=0;
00444 for (int level=1; level<=maxLevel; ++level) {
00445 for (int dim=0; dim<tp_rank; ++dim)
00446 if (decompDepth(dim)>=level)
00447 {
00448 int offset = end-begin+1;
00449 for (int i=begin; i<=end; ++i) {
00450 idx(i+offset) = idx(i);
00451 idx(i)(dim) = -level;
00452 idx(i+offset)(dim) = level;
00453 }
00454 end += offset;
00455 }
00456 begin = end;
00457 }
00458 idx.resizeAndPreserve(end+1);
00459 break;
00460 }
00461 default: assert(false);
00462 }
00463 return idx;
00464 }
00465
00466
00467 template<int tp_rank> template<class tp_Type>
00468 blitz::Array<tp_Type,tp_rank> WaveletDecomp<tp_rank>::coeffs(
00469 blitz::Array<tp_Type,tp_rank> &data,
00470 blitz::TinyVector<int, tp_rank> indices) const
00471 {
00472 using namespace blitz;
00473
00474 Array<tp_Type,tp_rank> c;
00475 TinyVector<int, tp_rank> ubound, lbound, stride;
00476
00477 for (int dim=0; dim<tp_rank; ++dim) {
00478 int i = indices(dim);
00479
00480
00481 int n = data.extent(dim);
00482
00483 if (storageMode()==NESTED_COEFFS) {
00484
00485
00486
00487 stride(dim) = i>=0 ? 1 << i : 1 << -i;
00488 lbound(dim) = data.lbound()(dim) + ( i>=0 ? 0 : 1 << (-i-1) );
00489 ubound(dim) = lbound(dim) + (data.ubound()(dim)-lbound(dim)) / stride(dim) * stride(dim);
00490 } else if (storageMode()==SEPARATED_COEFFS) {
00491
00492
00493
00494
00495 stride(dim) = 1;
00496 lbound(dim) = data.lbound()(dim) + ( i>=0 ? 0 : (n + (1<<-i) - 1) >> -i );
00497 ubound(dim) = data.lbound()(dim) + ( i>=0 ? ( (n + (1<<i) - 1) >> i) - 1
00498 : ( (n + (1<<(-i-1)) - 1) >> (-i-1) ) - 1 );
00499 } else assert(false);
00500
00501 assert( lbound(dim) <= ubound(dim));
00502 assert( lbound(dim) >= data.lbound(dim));
00503 assert( ubound(dim) <= data.ubound(dim));
00504 }
00505
00506 StridedDomain<tp_rank> subset(lbound, ubound, stride);
00507 c.reference(data(subset));
00508
00509 return c;
00510 }
00511
00512
00513 }
00514
00515 #endif