VAPoR  0.1
Lifting1D.h
Go to the documentation of this file.
1 //
2 // $Id$
3 //
4 
5 #ifndef _Lifting1D_h_
6 #define _Lifting1D_h_
7 
8 #include <iostream>
9 #include <vapor/EasyThreads.h>
10 #include <vapor/MyBase.h>
11 #ifdef WIN32
12 #pragma warning(disable : 4996)
13 #endif
14 namespace VAPoR {
15 
16 //
25 //
26 template <class Data_T> class Lifting1D : public VetsUtil::MyBase {
27 
28 public:
29 
31  static const int MAX_FILTER_COEFF = 32;
32 
38  //
39  Lifting1D(
40  unsigned int n, // # wavelet filter coefficents
41  unsigned int ntilde, // # wavelet lifting coefficients
42  unsigned int width, // # of samples to transform
43  int normalize = 0
44  );
45 
46  ~Lifting1D();
47 
54  //
55  void ForwardTransform(Data_T *data, int stride = 1);
56 
63  //
64  void InverseTransform(Data_T *data, int stride = 1);
65 
66 private:
67 
68  static const double Flt_Epsilon;
69  static const double TINY;
70  int _objInitialized; // has the obj successfully been initialized?
71 
72  unsigned int n_c; // # wavelet filter coefficients
73  unsigned int ntilde_c; // # wavelet lifting coefficients
74  unsigned int max_width_c;
75  unsigned int width_c;
76  double *fwd_filter_c; // forward transform filter coefficients
77  double *inv_filter_c; // inverse transform filter coefficients
78  double *fwd_lifting_c; // forward transform lifting coefficients
79  double *inv_lifting_c; // inverse transform lifting coefficients
80  double _nfactor; // normalization factor;
81 
82  int zero( const double x );
83 
84  double neville ( const double *x, const double *f, const int n, const double xx);
85 
86  void update_moment(
87  double** moment, const double *filter, const int step2,
88  const int noGammas, const int len, const int n, const int ntilde
89  );
90 
91  double** matrix(long nrl, long nrh, long ncl, long nch);
92 
93  void free_matrix(
94  double **m, long nrl, long nrh, long ncl, long nch
95  );
96 
97  void LUdcmp(double **a, int n, int *indx, double *d);
98  void LUbksb (double **a, int n, int *indx, double *b);
99 
100  void update_lifting(
101  double *lifting, const double** moment, const int len,
102  const int step2, const int noGammas, const int ntilde
103  );
104 
105  double *create_fwd_filter (unsigned int);
106  double *create_inv_filter (unsigned int, const double *);
107  double **create_moment(
108  const unsigned int, const unsigned int, const int
109  );
110 
111  double *create_inv_lifting(double *, unsigned int, unsigned int);
112 
113  double *create_fwd_lifting(
114  const double *filter, const unsigned int n,
115  const unsigned int ntilde, const unsigned int width
116  );
117 
118  void FLWT1D_Predict(Data_T*, const long, const long, double *, int stride);
119  void FLWT1D_Update(Data_T *, const long, const long, const double*, int stride);
120 
121  void forward_transform1d_haar(Data_T *data, int width, int stride);
122 
123  void inverse_transform1d_haar(Data_T *data, int width, int stride);
124 
125 
126 };
127 
128 };
129 
130 
131 
132 /*
133  * -*- Mode: ANSI C -*-
134  * $Id$
135  * Author: Gabriel Fernandez, Senthil Periaswamy
136  *
137  * >>> Fast Lifted Wavelet Transform on the Interval <<<
138  *
139  * .-.
140  * / | \
141  * .-. / -+- \ .-.
142  * `-' | `-'
143  *
144  * Using the "Lifting Scheme" and the "Square 2D" method, the coefficients
145  * of a "Biorthogonal Wavelet" or "Second Generation Wavelet" are found for
146  * a two-dimensional data set. The same scheme is used to apply the inverse
147  * operation.
148  */
149 /* do not edit anything above this line */
150 
151 /* System header files */
152 #include <cstdio>
153 #include <cstdlib>
154 #include <cmath>
155 #include <cstring>
156 #include <cerrno>
157 #include <cassert>
158 
159 using namespace VAPoR;
160 using namespace VetsUtil;
161 
162 #ifndef MAX
163 #define MAX(A,B) ((A)>(B)?(A):(B))
164 #endif
165 
166 
167 template <class Data_T> const double Lifting1D<Data_T>::TINY = (double) 1.0e-20;
168 
169 template <class Data_T> Lifting1D<Data_T>::Lifting1D(
170  unsigned int n,
171  unsigned int ntilde,
172  unsigned int width,
173  int normalize
174 ) {
175 
176  _objInitialized = 0;
177  n_c = n;
178  ntilde_c = ntilde;
179  width_c = width;
180  fwd_filter_c = NULL;
181  fwd_lifting_c = NULL;
182  inv_filter_c = NULL;
183  inv_lifting_c = NULL;
184  _nfactor = 1.0;
185 
186  SetClassName("Lifting1D");
187 
188 
189  // compute normalization factor if needed
190  if (normalize) {
191  int j = 0;
192 
193  while (width > 2) {
194  width -= (width>>1);
195  j++;
196  }
197  _nfactor = sqrt(pow(2.0, (double) j));
198  }
199 
200  // Check for haar wavelets which are handled differently
201  //
202  if (n_c == 1 && ntilde_c == 1) {
203  _objInitialized = 1;
204  return;
205  }
206 
207 
208  if (IsOdd(n_c)) {
209  SetErrMsg(
210  "Invalid # lifting coeffs., n=%d, is odd",
211  n_c
212  );
213  return;
214  }
215 
216  if (n_c > MAX_FILTER_COEFF) {
217  SetErrMsg(
218  "Invalid # of lifting coeffs., n=%d, exceeds max=%d",
219  n_c, MAX_FILTER_COEFF
220  );
221  return;
222  }
223  if (ntilde_c > MAX_FILTER_COEFF) {
224  SetErrMsg(
225  "Invalid # of lifting coeffs., ntilde=%d, exceeds max=%d",
226  ntilde_c, MAX_FILTER_COEFF
227  );
228  return;
229  }
230 
231  int maxN = MAX(n_c, ntilde_c) - 1; // max vanishing moments
232  int maxl = (width_c == 1) ? 0 : (int)LogBaseN ((double)(width_c-1)/maxN, (double) 2.0);
233 
234  if (maxl < 1) {
235  SetErrMsg(
236  "Invalid # of samples, width=%d, less than # moments",
237  width
238  );
239  return;
240 
241  }
242 
243 
244  if (! (fwd_filter_c = create_fwd_filter(n_c))) {
245  SetErrMsg("malloc() : %s", strerror(errno));
246  return;
247  }
248  if (! (inv_filter_c = create_inv_filter(n_c, fwd_filter_c))) {
249  SetErrMsg("malloc() : %s", strerror(errno));
250  return;
251  }
252 
253 
254 #ifdef DEBUGGING
255  {
256  int Nrows = (n_c>>1) + 1;
257  filterPtr = filter_c;
258  fprintf (stdout, "\nFilter Coefficients (N=%d)\n", n_c);
259  for (row = 0 ; row < Nrows ; row++) {
260  fprintf (stdout, "For %d in the left and %d in the right\n[ ",
261  row, N-row);
262  for (col = 0 ; col < n_c ; col++)
263  fprintf (stdout, "%.18g ", *(filterPtr++));
264  fprintf (stdout, "]\n");
265  }
266  }
267 #endif
268 
269 
270  fwd_lifting_c = create_fwd_lifting(fwd_filter_c,n_c,ntilde_c,width_c);
271  if (! fwd_lifting_c) {
272  SetErrMsg("malloc() : %s", strerror(errno));
273  return;
274  }
275 
276  inv_lifting_c = create_inv_lifting(fwd_lifting_c, ntilde_c, width_c);
277  if (! inv_lifting_c) {
278  SetErrMsg("malloc() : %s", strerror(errno));
279  return;
280  }
281 
282 
283  _objInitialized = 1;
284 }
285 
286 template <class Data_T> Lifting1D<Data_T>::~Lifting1D()
287 {
288  if (! _objInitialized) return;
289 
290  if (fwd_filter_c) delete [] fwd_filter_c;
291  fwd_filter_c = NULL;
292 
293  if (inv_filter_c) delete [] inv_filter_c;
294  inv_filter_c = NULL;
295 
296  if (fwd_lifting_c) delete [] fwd_lifting_c;
297  fwd_lifting_c = NULL;
298 
299  if (inv_lifting_c) delete [] inv_lifting_c;
300  inv_lifting_c = NULL;
301 
302  _objInitialized = 0;
303 }
304 
305 /* CODE FOR THE IN-PLACE FLWT (INTERPOLATION CASE, N EVEN) */
306 
307 //
308 // ForwardTransform function: This is a 1D Forward Fast Lifted Wavelet
309 // Trasform. Since the Lifting Scheme is used, the final
310 // coefficients are organized in-place in the original
311 // vector Data[]. In file mallat.c there are
312 // functions provided to change this organization to
313 // the Isotropic format originally established by Mallat.
314 //
315 template <class Data_T> void Lifting1D<Data_T>::ForwardTransform(
316  Data_T *data, int stride
317 ) {
318  if (n_c == 1 && ntilde_c == 1) {
319  forward_transform1d_haar(data, width_c, stride);
320  }
321  else {
322  FLWT1D_Predict (data, width_c, n_c, fwd_filter_c, stride);
323  FLWT1D_Update (data, width_c, ntilde_c, fwd_lifting_c, stride);
324  }
325 
326  if (_nfactor != 1.0) {
327  // normalize the detail coefficents
328  for(unsigned int i=1; i<width_c; i+=2) {
329  data[i*stride] /= _nfactor;
330  }
331  }
332 }
333 
334 //
335 // InverseTransform function: This is a 1D Inverse Fast Lifted Wavelet
336 // Trasform. Since the Lifting Scheme is used, the final
337 // coefficients are organized in-place in the original
338 // vector Data[]. In file mallat.c there are
339 // functions provided to change this organization to
340 // the Isotropic format originally established by Mallat.
341 //
342 template <class Data_T> void Lifting1D<Data_T>::InverseTransform(
343  Data_T *data, int stride
344 ) {
345  if (_nfactor != 1.0) {
346  // un-normalize the detail coefficents
347  for(unsigned int i=1; i<width_c; i+=2) {
348  data[i*stride] *= _nfactor;
349  }
350  }
351 
352  if (n_c == 1 && ntilde_c == 1) {
353  inverse_transform1d_haar(data, width_c, stride);
354  }
355  else {
356  FLWT1D_Update (data, width_c, ntilde_c, inv_lifting_c, stride);
357  FLWT1D_Predict (data, width_c, n_c, inv_filter_c, stride);
358  }
359 }
360 
361 template <class Data_T> const double Lifting1D<Data_T>::Flt_Epsilon = (double) 6E-8;
362 template <class Data_T> int Lifting1D<Data_T>::zero( const double x )
363 {
364  const double __negeps_f = -100 * Flt_Epsilon;
365  const double __poseps_f = 100 * Flt_Epsilon;
366 
367  return ( __negeps_f < x ) && ( x < __poseps_f );
368 }
369 
370 /*
371  * -*- Mode: ANSI C -*-
372  * (Polynomial Interpolation)
373  * $Id$
374  * Author: Wim Sweldens, Gabriel Fernandez
375  *
376  * Given n points of the form (x,f), this program uses the Neville algorithm
377  * to find the value at xx of the polynomial of degree (n-1) interpolating
378  * the points (x,f).
379  * Ref: Stoer and Bulirsch, Introduction to Numerical Analysis,
380  * Springer-Verlag.
381  */
382 
383 template <class Data_T> double Lifting1D<Data_T>::neville(
384  const double *x, const double *f, const int n, const double xx
385 ) {
386  register int i,j;
387  double vy[MAX_FILTER_COEFF];
388  double y;
389 
390  for ( i=0; i<n; i++ ) {
391  vy[i] = f[i];
392  for ( j=i-1; j>=0; j--) {
393  double den = x[i] - x[j];
394  assert(! zero(den));
395  vy[j] = vy[j+1] + (vy[j+1] - vy[j]) * (xx - x[i]) / den;
396  }
397  }
398  y = vy[0];
399 
400  return y;
401 }
402 
403 //
404 // UpdateMoment function: calculates the integral-moment tuple for the current
405 // level of calculations.
406 //
407 template <class Data_T> void Lifting1D<Data_T>::update_moment(
408  double** moment,
409  const double *filter,
410  const int step2,
411  const int noGammas,
412  const int len,
413  const int n,
414  const int ntilde
415 ) {
416  int i, j, /* counters */
417  row, col, /* indices of the matrices */
418  idxL, idxG, /* pointers to Lambda & Gamma coeffs, resp. */
419  top1, top2, top3; /* number of iterations for L<ntilde, L=ntilde, L>ntilde */
420  const double *filterPtr; // ptr to filter coefficients
421 
422  /***************************************/
423  /* Update Integral-Moments information */
424  /***************************************/
425 
426  /* Calculate number of iterations for each case */
427  top1 = (n>>1) - 1; /* L < ntilde */
428  top3 = (n>>1) - IsOdd(len); /* L > ntilde */
429  top2 = noGammas - (top1 + top3); /* L = ntilde */
430 
431  /* Cases where nbr. left Lambdas < nbr. right Lambdas */
432  filterPtr = filter; /* initialize pointer to first row */
433  idxG = step2>>1; /* second coefficient is Gamma */
434  for ( row = 1 ; row <= top1 ; row++ ) {
435  idxL = 0; /* first Lambda is always the first coefficient */
436  filterPtr += n; /* go to next filter row */
437  for ( col = 0 ; col < n ; col++ ) {
438  /* Update (int,mom_1,mom_2,...) */
439  for ( j = 0 ; j < ntilde ; j++ ) {
440  moment[idxL][j] += filterPtr[col]*moment[idxG][j];
441  }
442  /* Jump to next Lambda coefficient */
443  idxL += step2;
444  }
445  idxG += step2; /* go to next Gamma coefficient */
446  }
447 
448  /* Cases where nbr. left Lambdas = nbr. right Lambdas */
449  filterPtr += n; /* go to last filter row */
450  for ( i = 0 ; i < top2 ; i++ ) {
451  idxL = i*step2;
452  for ( col = 0 ; col < n ; col++ ) {
453  /* Update (int,mom_1,mom_2,...) */
454  for ( j = 0 ; j < ntilde ; j++ ) {
455  moment[idxL][j] += filterPtr[col]*moment[idxG][j];
456  }
457  /* Jump to next Lambda coefficient */
458  idxL += step2;
459  }
460  idxG += step2; /* go to next Gamma coefficient and stay */
461  /* in the same row of filter coefficients */
462  }
463 
464  /* Cases where nbr. left Lambdas > nbr. right Lambdas */
465  for ( row = top3 ; row >= 1 ; row-- ) {
466  idxL = (top2-1)*step2; // first Lambda is always in this place
467  filterPtr -= n; /* go to previous filter row */
468  for ( col = n-1 ; col >= 0 ; col-- ) {
469  /* Update (int,mom_1,mom_2,...) */
470  for ( j = 0 ; j < ntilde ; j++ ) {
471  moment[idxL][j] += filterPtr[col]*moment[idxG][j];
472  }
473  // Jump to next Lambda coefficient and next filter row
474  idxL += step2;
475  }
476  idxG += step2; /* go to next Gamma coefficient */
477  }
478 }
479 
480 
481 //
482 // allocate a f.p. matrix with subscript range m[nrl..nrh][ncl..nch]
483 //
484 template <class Data_T> double** Lifting1D<Data_T>::matrix(
485  long nrl, long nrh, long ncl, long nch
486 ) {
487  long i;
488  double **m;
489 
490  /* allocate pointers to rows */
491  m = new double* [nrh-nrl+1];
492  if (!m) return NULL;
493  m -= nrl;
494 
495  /* allocate rows and set pointers to them */
496  for ( i=nrl ; i<=nrh ; i++ ) {
497  m[i] = new double[nch-ncl+1];
498  if (!m[i]) return NULL;
499  m[i] -= ncl;
500  }
501  /* return pointer to array of pointers to rows */
502  return m;
503 }
504 
505 /* free a f.p. matrix llocated by matrix() */
506 template <class Data_T> void Lifting1D<Data_T>::free_matrix(
507  double **m, long nrl, long nrh, long ncl, long nch
508 ) {
509  long i;
510 
511  for ( i=nrh ; i>=nrl ; i-- ) {
512  m[i] += ncl;
513  delete [] m[i];
514  }
515  m += nrl;
516  delete [] m;
517 }
518 
519 
520 /*
521  * -*- Mode: ANSI C -*-
522  * $Id$
523  * Author: Gabriel Fernandez
524  *
525  * Definition of the functions used to perform the LU decomposition
526  * of matrix a. Function LUdcmp() performs the LU operations on a[][]
527  * and function LUbksb() performs the backsubstitution giving the
528  * solution in b[];
529  */
530 /* do not edit anything above this line */
531 
532 
533 /* code */
534 
535 /*
536  * LUdcmp function: Given a matrix a [0..n-1][0..n-1], this routine
537  * replaces it by the LU decomposition of a
538  * rowwise permutation of itself. a and n are
539  * input. a is output, arranged with L and U in
540  * the same matrix; indx[0..n-1] is an output vector
541  * that records the row permutation affected by
542  * the partial pivoting; d is output as +/-1
543  * depending on whether the number of row
544  * interchanges was even or odd, respectively.
545  * This routine is used in combination with LUbksb()
546  * to solve linear equations or invert a matrix.
547 */
548 template <class Data_T> void Lifting1D<Data_T>::LUdcmp(
549  double **a, int n, int *indx, double *d
550 ) {
551  int i, imax, j, k;
552  double big, dum, sum, temp;
553  double *vv; /* vv stores the implicit scaling of each row */
554 
555  vv=new double[n];
556  *d=(double)1; /* No row interchanges yet. */
557  for (i=0;i<n;i++) { /* Loop over rows to get the implicit scaling */
558  big=(double)0; /* information. */
559  for (j=0;j<n;j++)
560  if ((temp=(double)fabs((double)a[i][j])) > big)
561  big=temp;
562  assert(big != (double)0.0); // singular matrix
563  /* Nonzero largest element. */
564  vv[i]=(double)1/big; /* Save the scaling. */
565  }
566  for (j=0;j<n;j++) { /* This is the loop over columns of Crout's method. */
567  for (i=0;i<j;i++) { /* Sum form of a triangular matrix except for i=j. */
568  sum=a[i][j];
569  for (k=0;k<i;k++) sum -= a[i][k]*a[k][j];
570  a[i][j]=sum;
571  }
572  big=(double)0; /* Initialize for the search for largest pivot element. */
573  imax = -1; /* Set default value for imax */
574  for (i=j;i<n;i++) { /* This is i=j of previous sum and i=j+1...N */
575  sum=a[i][j]; /* of the rest of the sum. */
576  for (k=0;k<j;k++)
577  sum -= a[i][k]*a[k][j];
578  a[i][j]=sum;
579  if ( (dum=vv[i]*(double)fabs((double)sum)) >= big) {
580  /* Is the figure of merit for the pivot better than the best so far? */
581  big=dum;
582  imax=i;
583  }
584  }
585  if (j != imax) { /* Do we need to interchange rows? */
586  for (k=0;k<n;k++) { /* Yes, do so... */
587  dum=a[imax][k];
588  a[imax][k]=a[j][k];
589  a[j][k]=dum;
590  }
591  *d = -(*d); /* ...and change the parity of d. */
592  vv[imax]=vv[j]; /* Also interchange the scale factor. */
593  }
594  indx[j]=imax;
595  if (a[j][j] == (double)0.0)
596  a[j][j]=(double)TINY;
597  /* If the pivot element is zero the matrix is singular (at least */
598  /* to the precision of the algorithm). For some applications on */
599  /* singular matrices, it is desiderable to substitute TINY for zero. */
600  if (j != n-1) { /* Now, finally divide by pivot element. */
601  dum=(double)1/(a[j][j]);
602  for ( i=j+1 ; i<n ; i++ )
603  a[i][j] *= dum;
604  }
605  } /* Go back for the next column in the reduction. */
606  delete [] vv;
607 }
608 
609 
610 /*
611  * LUbksb function: Solves the set of n linear equations A.X = B.
612  * Here a[1..n][1..n] is input, not as the matrix A
613  * but rather as its LU decomposition, determined
614  * by the routine LUdcmp(). indx[1..n] is input as
615  * the permutation vector returned by LUdcmp().
616  * b[1..n] is input as the right hand side vector B,
617  * and returns with the solution vector X. a, n, and
618  * indx are not modified by this routine and can be
619  * left in place for successive calls with different
620  * right-hand sides b. This routine takes into account
621  * the possibility that b will begin with many zero
622  * elements, so it it efficient for use in matrix
623  * inversion.
624  */
625 template <class Data_T> void Lifting1D<Data_T>::LUbksb(
626  double **a, int n, int *indx, double *b
627 ) {
628  int i,ii=-1,ip,j;
629  double sum;
630 
631  for (i=0;i<n;i++) { /* When ii is set to a positive value, it will */
632  ip=indx[i]; /* become the index of the first nonvanishing */
633  sum=b[ip]; /* element of b. We now do the forward substitution. */
634  b[ip]=b[i]; /* The only new wrinkle is to unscramble the */
635  if (ii>=0) /* permutation as we go. */
636  for (j=ii;j<=i-1;j++) sum -= a[i][j]*b[j];
637  else if (sum) /* A nonzero element was encountered, so from now on */
638  ii=i; /* we will have to do the sums in the loop above */
639  b[i]=sum;
640  }
641  for (i=n-1;i>=0;i--) { /* Now we do the backsubstitution. */
642  sum=b[i];
643  for (j=i+1;j<n;j++) sum -= a[i][j]*b[j];
644  b[i]=sum/a[i][i]; /* Store a component of the solution vector X. */
645  if (zero(b[i])) b[i] = (double)0; /* Verify small numbers. */
646  } /* All done! */
647 }
648 
649 
650 /*
651  * UpdateLifting function: calculates the lifting coefficients using the given
652  * integral-moment tuple.
653  */
654 template <class Data_T> void Lifting1D<Data_T>::update_lifting(
655  double *lifting,
656  const double** moment,
657  const int len,
658  const int step2,
659  const int noGammas,
660  const int ntilde
661 ) {
662  int lcIdx, /* index of lifting vector */
663  i, j, /* counters */
664  row, col, /* indices of the matrices */
665  idxL, idxG, /* pointers to Lambda & Gamma coeffs, resp. */
666  top1, top2, top3; /* number of iterations for L<ntilde, L=ntilde, L>ntilde */
667  double** lift; // used to find the lifting coefficients
668  double *b; // used to find the lifting coefficients
669  int *indx; // used by the LU routines
670  double d; // used by the LU routines
671 
672  /**********************************/
673  /* Calculate Lifting Coefficients */
674  /**********************************/
675 
676  lcIdx = 0; /* first element of lifting vector */
677 
678  /* Allocate space for the indx[] vector */
679  indx = new int[ntilde];
680 
681  /* Allocate memory for the temporary lifting matrix and b */
682  /* temporary matrix to be solved */
683  lift = matrix(0, (long)ntilde-1, 0, (long)ntilde-1);
684  b = new double[ntilde]; /* temporary solution vector */
685 
686  /* Calculate number of iterations for each case */
687  top1 = (ntilde>>1) - 1; /* L < ntilde */
688  top3 = (ntilde>>1) - IsOdd(len); /* L > ntilde */
689  top2 = noGammas - (top1 + top3); /* L = ntilde */
690 
691  /* Cases where nbr. left Lambdas < nbr. right Lambdas */
692  idxG = step2>>1; /* second coefficient is Gamma */
693  for ( i=0 ; i<top1 ; i++ ) {
694  idxL = 0; /* first Lambda is always the first coefficient */
695  for (col=0 ; col<ntilde ; col++ ) {
696  /* Load temporary matrix to be solved */
697  for ( row=0 ; row<ntilde ; row++ ) {
698  lift[row][col] = moment[idxL][row]; //matrix
699  }
700  /* Jump to next Lambda coefficient */
701  idxL += step2;
702  }
703  /* Apply LU decomposition to lift[][] */
704  LUdcmp (lift, ntilde, indx, &d);
705  /* Load independent vector */
706  for ( j=0 ; j<ntilde ; j++) {
707  b[j] = moment[idxG][j]; /* independent vector */
708  }
709  /* Apply back substitution to find lifting coefficients */
710  LUbksb (lift, ntilde, indx, b);
711  for (col=0; col<ntilde; col++) { // save them in lifting vector
712  lifting[lcIdx++] = b[col];
713  }
714 
715  idxG += step2; /* go to next Gamma coefficient */
716  }
717 
718  /* Cases where nbr. left Lambdas = nbr. right Lambdas */
719  for ( i=0 ; i<top2 ; i++ ) {
720  idxL = i*step2;
721  for ( col=0 ; col<ntilde ; col++ ) {
722  /* Load temporary matrix to be solved */
723  for ( row=0 ; row<ntilde ; row++ )
724  lift[row][col] = moment[idxL][row]; /* matrix */
725  /* Jump to next Lambda coefficient */
726  idxL += step2;
727  }
728  /* Apply LU decomposition to lift[][] */
729  LUdcmp (lift, ntilde, indx, &d);
730  /* Load independent vector */
731  for ( j=0 ; j<ntilde ; j++)
732  b[j] = moment[idxG][j]; /* independent vector */
733  /* Apply back substitution to find lifting coefficients */
734  LUbksb (lift, ntilde, indx, b);
735  for ( col=0 ; col<ntilde ; col++ ) /* save them in lifting vector */
736  lifting[lcIdx++] = b[col];
737 
738  idxG += step2; /* go to next Gamma coefficient */
739  }
740 
741  /* Cases where nbr. left Lambdas > nbr. right Lambdas */
742  for ( i=0 ; i<top3 ; i++ ) {
743  idxL = (top2-1)*step2; /* first Lambda is always in this place */
744  for ( col=0 ; col<ntilde ; col++ ) {
745  /* Load temporary matrix to be solved */
746  for ( row=0 ; row<ntilde ; row++ )
747  lift[row][col] = moment[idxL][row]; /* matrix */
748  /* Jump to next Lambda coefficient */
749  idxL += step2;
750  }
751  /* Apply LU decomposition to lift[][] */
752  LUdcmp (lift, ntilde, indx, &d);
753  /* Load independent vector */
754  for ( j=0 ; j<ntilde ; j++)
755  b[j] = moment[idxG][j]; /* independent vector */
756  /* Apply back substitution to find lifting coefficients */
757  LUbksb (lift, ntilde, indx, b);
758  for (col=0;col<ntilde;col++) { // save them in lifting vector
759  lifting[lcIdx++] = b[col];
760  }
761 
762  idxG += step2; /* go to next Gamma coefficient */
763  }
764 
765  /* Free memory */
766  free_matrix(lift, 0, (long)ntilde-1, 0, (long)ntilde-1);
767  delete [] indx;
768  delete [] b;
769 }
770 
771 /*
772  * create_fwd_filter function: finds the filter coefficients used in the
773  * Gamma coefficients prediction routine. The
774  * Neville polynomial interpolation algorithm
775  * is used to find all the possible values for
776  * the filter coefficients. Thanks to this
777  * process, the boundaries are correctly treated
778  * without including artifacts.
779  * Results are ordered in matrix as follows:
780  * 0 in the left and N in the right
781  * 1 in the left and N-1 in the right
782  * 2 in the left and N-2 in the right
783  * .
784  * .
785  * .
786  * N/2 in the left and N/2 in the right
787  * For symmetry, the cases from
788  * N/2+1 in the left and N/2-1
789  * to
790  * N in the left and 0 in the right
791  * are the same as the ones shown above, but with
792  * switched sign.
793  */
794 template <class Data_T> double *Lifting1D<Data_T>::create_fwd_filter(
795  unsigned int n
796 ) {
797  double xa[MAX_FILTER_COEFF], ya[MAX_FILTER_COEFF], x;
798  int row, col, cc, Nrows;
799  double *filter, *ptr;
800 
801 
802  /* Number of cases for filter calculations */
803  Nrows = (n>>1) + 1; /* n/2 + 1 */
804 
805  /* Allocate memory for filter matrix */
806  filter = new double[Nrows*n];
807  if (! filter) return NULL;
808  ptr = filter;
809 
810  /* Generate values of xa */
811  xa[0] = (double)0.5*(double)(1 - (int) n); // -n/2 + 0.5
812  for (col = 1 ; col < (int)n ; col++) {
813  xa[col] = xa[col-1] + (double)1;
814  }
815 
816  /* Find filter coefficient values */
817  filter += ( (Nrows*n) - 1 ); // go to last position in filter matrix
818  for (row = 0 ; row < Nrows ; row++) {
819  x = (double)row;
820  for (col = 0 ; col < (int)n ; col++) {
821  for (cc = 0 ; cc < (int)n ; cc++)
822  ya[cc] = (double)0;
823  ya[col] = (double)1;
824  *(filter--) = neville (xa, ya, n, x);
825  }
826  }
827 
828  return ptr;
829 }
830 
831 template <class Data_T> double *Lifting1D<Data_T>::create_inv_filter(
832  unsigned int n, const double *filter
833 ) {
834  double *inv_filter;
835  int Nrows;
836  int i;
837 
838  /* Number of cases for filter calculations */
839  Nrows = (n>>1) + 1; /* n/2 + 1 */
840 
841  /* Allocate memory for filter matrix */
842  inv_filter = new double[Nrows*n];
843  if (! inv_filter) return NULL;
844 
845  for ( i=0 ; i<(int)(n*(1+(n>>1))) ; i++ ) inv_filter[i] = -filter[i];
846 
847  return(inv_filter);
848 }
849 
850 //
851 // create_moment function: Initializes the values of the Integral-Moments
852 // matrices. The moments are equal to k^i, where
853 // k is the coefficient index and i is the moment
854 // number (0,1,2,...).
855 //
856 template <class Data_T> double **Lifting1D<Data_T>::create_moment(
857  const unsigned int ntilde,
858  const unsigned int width,
859  const int print
860 ) {
861  int row, col;
862 
863  double** moment;
864 
865  /* Allocate memory for the Integral-Moment matrices */
866  moment = matrix( 0, (long)(width-1), 0, (long)(ntilde-1) );
867 
868  /* Initialize Integral and Moments */
869  /* Integral is equal to one at the beginning since all the filter */
870  /* coefficients must add to one for each gamma coefficient. */
871  /* 1st moment = k, 2nd moment = k^3, 3rd moment = k^3, ... */
872  for ( row=0 ; row<(int)width ; row++ ) /* for the rows */
873  for ( col=0 ; col<(int)ntilde ; col++ ) {
874  if ( row==0 && col==0 )
875  moment[row][col] = (double)1.0; /* pow() domain error */
876  else
877  moment[row][col] = (double)pow( (double)row, (double)col );
878  }
879 
880  /* Print Moment Coefficients */
881  if (print) {
882  fprintf (stdout, "Integral-Moments Coefficients for X (ntilde=%2d)\n", ntilde);
883  for ( row=0 ; row<(int)width ; row++ ) {
884  fprintf (stdout, "Coeff[%d] (%.20g", row, moment[row][0]);
885  for ( col=1 ; col<(int)ntilde ; col++ )
886  fprintf (stdout, ",%.20g", moment[row][col]);
887  fprintf (stdout, ")\n");
888  }
889  }
890 
891  return moment;
892 }
893 
894 #define CEIL(num,den) ( ((num)+(den)-1)/(den) )
895 
896 template <class Data_T> double *Lifting1D<Data_T>::create_inv_lifting(
897  double *fwd_lifting,
898  unsigned int ntilde,
899  unsigned int width
900 ) {
901  int noGammas;
902  double *inv_lifting = NULL;
903  int col;
904 
905  /* Allocate lifting coefficient matrices */
906  noGammas = width >> 1; // number of Gammas
907  if (noGammas > 0) {
908  inv_lifting = new double[noGammas*ntilde];
909  for ( col=0 ; col<(int)(noGammas*ntilde) ; col++ ) {
910  inv_lifting[col] = -fwd_lifting[col];
911  }
912  }
913  return(inv_lifting);
914 }
915 
916 //
917 // create_fwd_lifting : Updates corresponding moment matrix (X if dir is FALSE
918 // and Y if dir is TRUE) and calculates the lifting
919 // coefficients using the new moments.
920 // This function is used for the forward transform and
921 // uses the original filter coefficients.
922 //
923 template <class Data_T> double *Lifting1D<Data_T>::create_fwd_lifting(
924  const double *filter,
925  const unsigned int n,
926  const unsigned int ntilde,
927  const unsigned int width
928 ) {
929  double** moment; /* pointer to the Integral-Moments matrix */
930  int len; /* number of coefficients in this level */
931  int step2; /* step size between same coefficients */
932  int noGammas; /* number of Gamma coeffs */
933  double *lifting = NULL;
934 
935  int col;
936 
937  moment = create_moment(ntilde, width, 0);
938  if (! moment) return NULL;
939 
940 
941  /**********************************/
942  /* Initialize important constants */
943  /**********************************/
944 
945  /* Calculate number of coefficients and step size */
946  len = CEIL (width, 1);
947  step2 = 1 << 1;
948 
949  /* Allocate lifting coefficient matrices */
950  noGammas = width >> 1; // number of Gammas
951  if (noGammas > 0) {
952  lifting = new double[noGammas*ntilde];
953  for ( col=0 ; col<(int)(noGammas*ntilde) ; col++ ) {
954  lifting[col] = (double)0;
955  }
956  }
957 
958  update_moment(moment, filter, step2, noGammas, len, n, ntilde );
959  update_lifting(
960  lifting, (const double **) moment, len, step2,
961  noGammas, ntilde
962  );
963 
964 #ifdef DEBUGING
965  fprintf (stdout, "\nLifting Coefficients:\n");
966  liftPtr = lifting;
967  for ( x=0 ; x<(width>>1) ; x++ ) {
968  sprintf (buf, "%.20g", *(liftPtr++));
969  for ( k=1 ; k<nTilde ; k++ )
970  sprintf (buf, "%s,%.20g", buf, *(liftPtr++));
971  fprintf (stdout, "Gamma[%d] (%s)\n", x, buf);
972  }
973 #endif
974 
975  /* Free memory allocated for the moment matrices */
976  free_matrix(moment, 0, (long)(width-1), 0, (long)(ntilde-1) );
977 
978  return(lifting);
979 }
980 
981 
982 
983 
984 /*
985  * FLWT1D_Predict function: The Gamma coefficients are found as an average
986  * interpolation of their neighbors in order to find
987  * the "failure to be linear" or "failure to be
988  * cubic" or the failure to be the order given by
989  * N-1. This process uses the filter coefficients
990  * stored in the filter vector and predicts
991  * the odd samples based on the even ones
992  * storing the difference in the gammas.
993  * By doing so, a Dual Wavelet is created.
994  */
995 template <class Data_T> void Lifting1D<Data_T>::FLWT1D_Predict(
996  Data_T* vect,
997  const long width,
998  const long N,
999  double *filter,
1000  int stride
1001 ) {
1002  register Data_T *lambdaPtr, //pointer to Lambda coeffs
1003  *gammaPtr; // pointer to Gamma coeffs
1004  register double *fP, *filterPtr; // pointers to filter coeffs
1005  register long len, // number of coeffs at current level
1006  j, /* counter for the filter cases */
1007  stepIncr; /* step size between coefficients of the same type */
1008 
1009  long stop1, /* number of cases when L < R */
1010  stop2, /* number of cases when L = R */
1011  stop3, /* number of cases when L > R */
1012  soi; /* increment for the middle cases */
1013 
1014  /************************************************/
1015  /* Calculate values of some important variables */
1016  /************************************************/
1017  len = CEIL(width, 1); /* number of coefficients at current level */
1018  stepIncr = stride << 1; /* step size betweeen coefficients */
1019 
1020  /************************************************/
1021  /* Calculate number of iterations for each case */
1022  /************************************************/
1023  j = IsOdd(len);
1024  stop1 = N >> 1;
1025  stop3 = stop1 - j; /* L > R */
1026  stop2 = (len >> 1) - N + 1 + j; /* L = R */
1027  stop1--; /* L < R */
1028 
1029  /***************************************************/
1030  /* Predict Gamma (wavelet) coefficients (odd guys) */
1031  /***************************************************/
1032 
1033  filterPtr = filter + N; /* position filter pointer */
1034 
1035  /* Cases where nbr. left Lambdas < nbr. right Lambdas */
1036  gammaPtr = vect + (stepIncr >> 1); /* second coefficient is Gamma */
1037  while(stop1--) {
1038  lambdaPtr = vect; /* first coefficient is always first Lambda */
1039  j = N;
1040  do { /* Gamma update (Gamma - predicted value) */
1041  *(gammaPtr) -= (*(lambdaPtr)*(*(filterPtr++)));
1042  lambdaPtr += stepIncr; /* jump to next Lambda coefficient */
1043  } while(--j); /* use all N filter coefficients */
1044  /* Go to next Gamma coefficient */
1045  gammaPtr += stepIncr;
1046  }
1047 
1048  /* Cases where nbr. left Lambdas = nbr. right Lambdas */
1049  soi = 0;
1050  while(stop2--) {
1051  lambdaPtr = vect + soi; /* first Lambda to be read */
1052  fP = filterPtr; /* filter stays in same values for this cases */
1053  j = N;
1054  do { /* Gamma update (Gamma - predicted value) */
1055  *(gammaPtr) -= (*(lambdaPtr)*(*(fP++)));
1056  lambdaPtr += stepIncr; /* jump to next Lambda coefficient */
1057  } while(--j); /* use all N filter coefficients */
1058  /* Move start point for the Lambdas */
1059  soi += stepIncr;
1060  /* Go to next Gamma coefficient */
1061  gammaPtr += stepIncr;
1062  }
1063 
1064  /* Cases where nbr. left Lambdas > nbr. right Lambdas */
1065  fP = filterPtr; /* start going backwards with the filter coefficients */
1066  vect += (soi-stepIncr); /* first Lambda is always in this place */
1067  while (stop3--) {
1068  lambdaPtr = vect; /* position Lambda pointer */
1069  j = N;
1070  do { /* Gamma update (Gamma - predicted value) */
1071  *(gammaPtr) -= (*(lambdaPtr)*(*(--fP)));
1072  lambdaPtr += stepIncr; /* jump to next Lambda coefficient */
1073  } while(--j); /* use all N filter coefficients */
1074  /* Go to next Gamma coefficient */
1075  gammaPtr += stepIncr;
1076  }
1077 }
1078 
1079 /*
1080  * FLWT1D_Update: the Lambda coefficients have to be "lifted" in order
1081  * to find the real wavelet coefficients. The new Lambdas
1082  * are obtained by applying the lifting coeffients stored
1083  * in the lifting vector together with the gammas found in
1084  * the prediction stage. This process assures that the
1085  * moments of the wavelet function are preserved.
1086  */
1087 template <class Data_T> void Lifting1D<Data_T>::FLWT1D_Update(
1088  Data_T* vect,
1089  const long width,
1090  const long nTilde,
1091  const double *lc,
1092  int stride
1093 ) {
1094  const register double * lcPtr; /* pointer to lifting coefficient values */
1095  register Data_T *vL, /* pointer to Lambda values */
1096  *vG; /* pointer to Gamma values */
1097  register long j; /* counter for the lifting cases */
1098 
1099  long len, /* number of coefficietns at current level */
1100  stop1, /* number of cases when L < R */
1101  stop2, /* number of cases when L = R */
1102  stop3, /* number of cases when L > R */
1103  noGammas, /* number of Gamma coefficients at this level */
1104  stepIncr, /* step size between coefficients of the same type */
1105  soi; /* increment for the middle cases */
1106 
1107 
1108  /************************************************/
1109  /* Calculate values of some important variables */
1110  /************************************************/
1111  len = CEIL(width, 1); /* number of coefficients at current level */
1112  stepIncr = stride << 1; /* step size between coefficients */
1113  noGammas = len >> 1 ; /* number of Gamma coefficients */
1114 
1115  /************************************************/
1116  /* Calculate number of iterations for each case */
1117  /************************************************/
1118  j = IsOdd(len);
1119  stop1 = nTilde >> 1;
1120  stop3 = stop1 - j; /* L > R */
1121  stop2 = noGammas - nTilde + 1 + j; /* L = R */
1122  stop1--; /* L < R */
1123 
1124  /**********************************/
1125  /* Lift Lambda values (even guys) */
1126  /**********************************/
1127 
1128  lcPtr = lc; /* position lifting pointer */
1129 
1130  /* Cases where nbr. left Lambdas < nbr. right Lambdas */
1131  vG = vect + (stepIncr >> 1); /* second coefficient is Gamma */
1132  while(stop1--) {
1133  vL = vect; /* lambda starts always in first coefficient */
1134  j = nTilde;
1135  do {
1136  *(vL) += (*(vG)*(*(lcPtr++))); /* lift Lambda (Lambda + lifting value) */
1137  vL += stepIncr; /* jump to next Lambda coefficient */
1138  } while(--j); /* use all nTilde lifting coefficients */
1139  /* Go to next Gamma coefficient */
1140  vG += stepIncr;
1141  }
1142 
1143  /* Cases where nbr. left Lambdas = nbr. right Lambdas */
1144  soi = 0;
1145  while(stop2--) {
1146  vL = vect + soi; /* first Lambda to be read */
1147  j = nTilde;
1148  do {
1149  *(vL) += (*(vG)*(*(lcPtr++))); /* lift Lambda (Lambda + lifting value) */
1150  vL += stepIncr; /* jump to next Lambda coefficient */
1151  } while(--j); /* use all nTilde lifting coefficients */
1152  /* Go to next Gamma coefficient */
1153  vG += stepIncr;
1154  /* Move start point for the Lambdas */
1155  soi += stepIncr;
1156  }
1157 
1158  /* Cases where nbr. left Lambdas = nbr. right Lambdas */
1159  vect += (soi - stepIncr); /* first Lambda is always in this place */
1160  while(stop3--) {
1161  vL = vect; /* position Lambda pointer */
1162  j = nTilde;
1163  do {
1164  *(vL) += (*(vG)*(*(lcPtr++))); /* lift Lambda (Lambda + lifting value) */
1165  vL += stepIncr; /* jump to next Lambda coefficient */
1166  } while(--j); /* use all nTilde lifting coefficients */
1167  /* Go to next Gamma coefficient */
1168  vG += stepIncr;
1169  }
1170 }
1171 
1172 template <class Data_T> void Lifting1D<Data_T>::forward_transform1d_haar(
1173  Data_T *data,
1174  int width,
1175  int stride
1176 ) {
1177  int i;
1178 
1179  int nG; // # gamma coefficients
1180  int nL; // # lambda coefficients
1181  double lsum = 0.0; // sum of lambda values
1182  double lave = 0.0; // average of lambda values
1183  int stepIncr = stride << 1; // step size betweeen coefficients
1184 
1185 
1186  nG = (width >> 1);
1187  nL = width - nG;
1188 
1189  //
1190  // Need to preserve average for odd sizes
1191  //
1192  if (IsOdd(width)) {
1193  double t = 0.0;
1194 
1195  for(i=0;i<width;i++) {
1196  t += data[i*stride];
1197  }
1198  lave = t / (double) width;
1199  }
1200 
1201  for (i=0; i<nG; i++) {
1202  data[stride] = data[stride] - data[0]; // gamma
1203  data[0] = (Data_T)(data[0] + (data[stride] /2.0)); // lambda
1204  lsum += data[0];
1205 
1206  data += stepIncr;
1207  }
1208 
1209  // If IsOdd(width), then we have one additional case for */
1210  // the Lambda calculations. This is a boundary case */
1211  // and, therefore, has different filter values. */
1212  //
1213  if (IsOdd(width)) {
1214  data[0] = (Data_T)((lave * (double) nL) - lsum);
1215  }
1216 }
1217 
1218 
1219 
1220 template <class Data_T> void Lifting1D<Data_T>::inverse_transform1d_haar(
1221  Data_T *data,
1222  int width,
1223  int stride
1224 ) {
1225  int i,j;
1226  int nG; // # gamma coefficients
1227  int nL; // # lambda coefficients
1228  double lsum = 0.0; // sum of lambda values
1229  double lave = 0.0; // average of lambda values
1230 
1231  int stepIncr = stride << 1; // step size betweeen coefficients
1232 
1233  nG = (width >> 1);
1234  nL = width - nG;
1235 
1236  // Odd # of coefficients require special handling at boundary
1237  // Calculate Lambda average
1238  //
1239  if (IsOdd(width) ) {
1240  double t = 0.0;
1241 
1242  for(i=0,j=0;i<nL;i++,j+=stepIncr) {
1243  t += data[j];
1244  }
1245  lave = t/(double)nL; // average we've to maintain
1246  }
1247 
1248  for (i=0; i<nG; i++) {
1249  data[0] = (Data_T)(data[0] - (data[stride] * 0.5));
1250  data[stride] = data[stride] + data[0];
1251  lsum += data[0] + data[stride];
1252 
1253  data += stepIncr;
1254  }
1255 
1256  // If ODD(len), then we have one additional case for */
1257  // the Lambda calculations. This is a boundary case */
1258  // and, therefore, has different filter values. */
1259  //
1260  if (IsOdd(width)) {
1261  *data = (Data_T)((lave * (double) width) - lsum);
1262  }
1263 }
1264 
1265 #endif // _Lifting1D_h_
COMMON_API double LogBaseN(double x, double n)
Definition: MyBase.h:292
Definition: Base64.h:6
void InverseTransform(Data_T *data, int stride=1)
Definition: Lifting1D.h:342
COMMON_API int IsOdd(int x)
Definition: MyBase.h:270
VetsUtil base class.
Definition: MyBase.h:68
void ForwardTransform(Data_T *data, int stride=1)
Definition: Lifting1D.h:315
#define CEIL(num, den)
Definition: Lifting1D.h:894
static const int MAX_FILTER_COEFF
maximum number of filter coefficients
Definition: Lifting1D.h:31
Wrapper for Wim Swelden's Liftpack wavelet transform interface.
Definition: Lifting1D.h:26
Lifting1D(unsigned int n, unsigned int ntilde, unsigned int width, int normalize=0)
Definition: Lifting1D.h:169
#define MAX(A, B)
Definition: Lifting1D.h:163