/home/pclz-02/oschulz/Data/Science/Projects/Gerda/Software/blitzwave/src/WaveletDecomp.h
00001 // Copyright (C) 2003-2013 Oliver Schulz <oliver.schulz@tu-dortmund.de>
00002 
00003 // This program is free software; you can redistribute it and/or modify
00004 // it under the terms of the GNU General Public License as published by
00005 // the Free Software Foundation; either version 2 of the License, or
00006 // (at your option) any later version.
00007 //
00008 // This program is distributed in the hope that it will be useful,
00009 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00010 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00011 // GNU General Public License for more details.
00012 //
00013 // You should have received a copy of the GNU General Public License
00014 // along with this program; if not, write to the Free Software
00015 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
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                 // log(...-0.1) for numerical stability
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                 // Remark: i>=0 specifies phi(i) coeff,
00480                 //          i<0 specifies psi(-i) coeff;
00481                 int n = data.extent(dim);
00482                 
00483                 if (storageMode()==NESTED_COEFFS) {
00484                         // Remark: coefficient location in data(l)
00485                         //         for phi(i):       0 <= l <= n-1, stride = 2^i
00486                         //         for psi(i): 2^(i-1) <= l <= n-1, stride = 2^i
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                         // Remark: coefficient location in data(l)
00492                         //         for phi(i):           0 <= l <= ceil(n/2^i)-1
00493                         //         for psi(i): ceil(n/2^i) <= l <= ceil(n/2^(i-1))-1
00494                         // Remark: ceil(n/2^i) = (n + (1<<i) - 1) >> i;
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 } // namespace bwave
00514 
00515 #endif