/*******************************************************************************
 * Copyright (c) 2010 Haifeng Li
 *   
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *  
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *******************************************************************************/
package smile.wavelet;

import java.util.Arrays;
import smile.math.Math;

/**
 * A wavelet is a wave-like oscillation with an amplitude that starts out at
 * zero, increases, and then decreases back to zero. Like the fast Fourier
 * transform (FFT), the discrete wavelet trainsform (DWT) is a fast, linear
 * operation that operates on a data vector whose length is an integer power
 * of 2, transforming it into a numerically different vector of the same length.
 * The wavelet transform is invertible and in fact orthogonal. Both FFT and DWT
 * can be viewed as a rotation in function space.
 * 
 * @author Haifeng Li
 */
public class Wavelet {

    /**
     * The number of coefficients.
     */
    private int ncof;
    /**
     * Centering.
     */
    private int ioff, joff;
    /**
     * Wavelet coefficients.
     */
    private double[] cc;
    private double[] cr;

    /**
     * Workspace.
     */
    private double[] workspace = new double[1024];


    /**
     * Constructor. Create a wavelet with given coefficients.
     */
    public Wavelet(double[] coefficients) {
        if (coefficients != null) {
            ncof = coefficients.length;

            ioff = joff = -(ncof >> 1);
            // ioff = -2; joff = -ncof + 2; // Alternative centering, used by D4.

            cc = coefficients;

            double sig = -1.0;
            cr = new double[ncof];
            for (int i = 0; i < ncof; i++) {
                cr[ncof - 1 - i] = sig * cc[i];
                sig = -sig;
            }
        }
    }

    /**
     * Applies the wavelet filter to a data vector a[0, n-1].
     */
    void forward(double[] a, int n) {
        if (n < 4) {
            return;
        }

        if (n > workspace.length) {
            workspace = new double[n];
        } else {
            Arrays.fill(workspace, 0, n, 0.0);
        }

        int nmod = ncof * n;
        int n1 = n - 1;
        int nh = n >> 1;

        for (int ii = 0, i = 0; i < n; i += 2, ii++) {
            int ni = i + 1 + nmod + ioff;
            int nj = i + 1 + nmod + joff;
            for (int k = 0; k < ncof; k++) {
                int jf = n1 & (ni + k + 1);
                int jr = n1 & (nj + k + 1);
                workspace[ii] += cc[k] * a[jf];
                workspace[ii + nh] += cr[k] * a[jr];
            }
        }

        System.arraycopy(workspace, 0, a, 0, n);
    }

    /**
     * Applies the inverse wavelet filter to a data vector a[0, n-1].
     */
    void backward(double[] a, int n) {
        if (n < 4) {
            return;
        }

        if (n > workspace.length) {
            workspace = new double[n];
        } else {
            Arrays.fill(workspace, 0, n, 0.0);
        }

        int nmod = ncof * n;
        int n1 = n - 1;
        int nh = n >> 1;

        for (int ii = 0, i = 0; i < n; i += 2, ii++) {
            double ai = a[ii];
            double ai1 = a[ii + nh];
            int ni = i + 1 + nmod + ioff;
            int nj = i + 1 + nmod + joff;
            for (int k = 0; k < ncof; k++) {
                int jf = n1 & (ni + k + 1);
                int jr = n1 & (nj + k + 1);
                workspace[jf] += cc[k] * ai;
                workspace[jr] += cr[k] * ai1;
            }
        }

        System.arraycopy(workspace, 0, a, 0, n);
    }

    /**
     * Discrete wavelet transform.
     */
    public void transform(double[] a) {
        int n = a.length;

        if (!Math.isPower2(n)) {
            throw new IllegalArgumentException("The data vector size is not a power of 2.");
        }

        if (n < 4) {
            throw new IllegalArgumentException("The data vector size is less than 4.");
        }

        for (int nn = n; nn >= 4; nn >>= 1) {
            forward(a, nn);
        }
    }

    /**
     * Inverse discrete wavelet transform.
     */
    public void inverse(double[] a) {
        int n = a.length;

        if (!Math.isPower2(n)) {
            throw new IllegalArgumentException("The data vector size is not a power of 2.");
        }

        if (n < 4) {
            throw new IllegalArgumentException("The data vector size is less than 4.");
        }

        for (int nn = 4; nn <= n; nn <<= 1) {
            backward(a, nn);
        }
    }
}

@@ -1026,17 +1026,16 @@
 elet tra
-i
 nsform (

fix typo