DWT and IDWT test
=================

Discrete Wavelet Transform
--------------------------

Let's do a Discrete Wavelet Transform of a sample data `x` using the `db2`
wavelet. It's simple..

    >>> import pywt
    >>> x = [3, 7, 1, 1, -2, 5, 4, 6]
    >>> cA, cD = pywt.dwt(x, 'db2')
    
And the approximation and details coefficients are in `cA` and `cD` respectively:
    
    >>> print cA
    [ 5.65685425  7.39923721  0.22414387  3.33677403  7.77817459]
    >>> print cD
    [-2.44948974 -1.60368225 -4.44140056 -0.41361256  1.22474487]

Inverse Discrete Wavelet Transform
----------------------------------

Now let's do an opposite operation - Inverse Discrete Wavelet Transform:
    
    >>> print pywt.idwt(cA, cD, 'db2')
    [ 3.  7.  1.  1. -2.  5.  4.  6.]
    
Violla! That's it!

More Examples
-------------

Now let's experiment with the `dwt` some more. For example let's pass a Wavelet
object instead of the wavelet name and specify signal extension mode
(the default is 'sym') for the border effect handling:

    >>> w = pywt.Wavelet('sym3')
    >>> cA, cD = pywt.dwt(x, wavelet=w, mode='cpd')
    >>> print cA
    [ 4.38354585  3.80302657  7.31813271 -0.58565539  4.09727044  7.81994027]
    >>> print cD
    [-1.33068221 -2.78795192 -3.16825651 -0.67715519 -0.09722957 -0.07045258]

Note that the output coefficients arrays lenght depends not only on the input
data length but also on the Wavelet type (particularly on it's filters lenght
that are used in the transformation).

To find out what will be the output data size use the `dwt_coeff_len` function:

    >>> pywt.dwt_coeff_len(data_len=len(x), filter_len=w.dec_len, mode='sym')
    6
    >>> pywt.dwt_coeff_len(len(x), w, 'sym')
    6
    >>> len(cA)
    6

Looks fine. (And if you expected that the output length would be a half of
the input data length, well, that's the tradeoff that allows for the perfect
reconstruction...).

The third argument of the `dwt_coeff_len` is the already mentioned signal
extension mode (please refer to the PyWavelets' documentation for the
modes description). Currently there are six extension modes available:

    >>> pywt.MODES.modes
    ['zpd', 'cpd', 'sym', 'ppd', 'sp1', 'per']

    >>> [pywt.dwt_coeff_len(len(x), w.dec_len, mode) for mode in pywt.MODES.modes]
    [6, 6, 6, 6, 6, 4]

As you see in the above example, the 'per' (periodization) mode is slightly
different from the others. It's aim when doing the DWT is to output coefficients
arrays that are half of the length of the input data.

Knowing that, you should never mix the periodization mode with other modes
when doing DWT and IDWT. Otherwise, it will give invalid results:

    >>> x
    [3, 7, 1, 1, -2, 5, 4, 6]
    >>> cA, cD = pywt.dwt(x, wavelet=w, mode='per')
    >>> print pywt.idwt(cA, cD, 'sym3', 'sym') # invalid mode
    [ 1.  1. -2.  5.]
    >>> print pywt.idwt(cA, cD, 'sym3', 'per')
    [ 3.  7.  1.  1. -2.  5.  4.  6.]


Tips & tricks
-------------

Passing None instead of coefficients data to `idwt`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Now some tips & tricks. Passing None as one of the coefficient arrays
parameters is similar to passing a zero-filled array. The results are
simply the same:

    >>> print pywt.idwt([1,2,0,1], None, 'db2', 'sym')
    [ 1.19006969  1.54362308  0.44828774 -0.25881905  0.48296291  0.8365163 ]

    >>> print pywt.idwt([1, 2, 0, 1], [0, 0, 0, 0], 'db2', 'sym')
    [ 1.19006969  1.54362308  0.44828774 -0.25881905  0.48296291  0.8365163 ]

    >>> print pywt.idwt(None, [1, 2, 0, 1], 'db2', 'sym')
    [ 0.57769726 -0.93125065  1.67303261 -0.96592583 -0.12940952 -0.22414387]

    >>> print pywt.idwt([0, 0, 0, 0], [1, 2, 0, 1], 'db2', 'sym')
    [ 0.57769726 -0.93125065  1.67303261 -0.96592583 -0.12940952 -0.22414387]

Remember that only one argument at a time can be None:

    >>> print pywt.idwt(None, None, 'db2', 'sym')
    Traceback (most recent call last):
    ...
    ValueError: At least one coefficient parameter must be specified.
    

Coefficients data size in `idwt`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

When doing IDWT, usually the coefficient arrays must have the same size.

    >>> print pywt.idwt([1, 2, 3, 4, 5], [1, 2, 3, 4], 'db2', 'sym')
    Traceback (most recent call last):
    ...
    ValueError: Coefficients arrays must have the same size.

But for some applications like multilevel DWT and IDWT it is sometimes
conveniet to allow for a small departure from this behaviour. When the
correct_size flag is set, the approximation coefficients array can be
larger from the details coefficient array by one element:

    >>> print pywt.idwt([1, 2, 3, 4, 5], [1, 2, 3, 4], 'db2', 'sym', correct_size=True)
    [ 1.76776695  0.61237244  3.18198052  0.61237244  4.59619408  0.61237244]
    
    >>> print pywt.idwt([1, 2, 3, 4], [1, 2, 3, 4, 5], 'db2', 'sym', correct_size=True)
    Traceback (most recent call last):
    ...
    ValueError: Coefficients arrays must satisfy (0 <= len(cA) - len(cD) <= 1).


Not every coefficient array can be used in IDWT. In the following example
the `idwt` will fail because the input arrays are invalid - they couldn't
be created as a result of DWT, beacuse the minimal output length for dwt
using 'db4' wavelet and the 'sym' mode is 4, not 3.

    >>> pywt.idwt([1,2,4], [4,1,3], 'db4', 'sym')
    Traceback (most recent call last):
    ...
    ValueError: Invalid coefficient arrays length for specified wavelet. Wavelet and mode must be the same as used for decomposition.

    >>> pywt.dwt_coeff_len(1, pywt.Wavelet('db4').dec_len, 'sym')
    4

