/**
 *  Benchmark #9 - Wavelet transform in memory.
 *   @author  Josef.Pelikan@mff.cuni.cz
 *   @version 0.007 (2001/06/21)
 *   @since   0.007
 */
public class BenchmarkWaveletMemory extends Benchmark {

    /** Maximum array size. */
    protected final static int WAVE_MAX_SIZE = 1 << 22;

    /** Minimum array size. */
    protected final static int WAVE_MIN_SIZE = 1 << 11;

    /** Number of iterations for <code>WAVE_MAX_SIZE</code>. */
    protected final static int WAVE_ITER = 20;

    /**
     *  Initializing constructor.
     */
    public BenchmarkWaveletMemory () {
    }

    /**
     *  Test (benchmark) ordinal number.
     *   @return Ordinal number of the test.
     */
    public int testNumber () {
        return 9;
    }

    /**
     *  Computes forward TS-transform in memory.
     *   @param  n0 Size of the source segment (<code>s0</code>).
     *   @param  a Global array holding all segments.
     *   @param  s0 Start of the source segment.
     *   @param  s1 Start of the smooth destination segment.
     *   @param  d1 Start of the wavelet destination segment.
     */
    protected static void liftMemory ( int n0, int[] a, int s0, int s1, int d1 ) {
        int n1 = n0 >> 1;
        int ps0, ps1, pd1;
        int i;
            // split:
        ps0 = s0;
        ps1 = s1; pd1 = d1;
        for ( i = 0; i++ < n1; ) {
            a[ps1++] = a[ps0++];
            a[pd1++] = a[ps0++];
            }
            // S-transform:
        ps1 = s1; pd1 = d1;
        for ( i = 0; i++ < n1; ) {
            a[pd1]   -= a[ps1];
            a[ps1++] += (a[pd1++] >> 1);
            }
            // predict:
        ps1 = s1; pd1 = d1;
        a[ps1+n1] = a[ps1+n1-1];           // boundary
        a[ps1-1]  = a[ps1];
        for ( i = 0; i++ < n1; ) {
            a[pd1++] += ((a[ps1-1] - a[ps1+1] + 2) >> 2);
            ps1++;
            }
    }

    /**
     *  Computes backward TS-transform in memory.
     *   @param  n0 Size of the destination segment (<code>s0</code>).
     *   @param  a Global array holding all segments.
     *   @param  s0 Start of the destination segment.
     *   @param  s1 Start of the smooth source segment.
     *   @param  d1 Start of the wavelet source segment.
     */
    protected static void unliftMemory ( int n0, int[] a, int s0, int s1, int d1 ) {
        int n1 = n0 >> 1;
        int ps0, ps1, pd1;
        int i;
            // predict*:
        ps1 = s1; pd1 = d1;
        a[ps1+n1] = a[ps1+n1-1];           // boundary
        a[ps1-1]  = a[ps1];
        for ( i = 0; i++ < n1; ) {
            a[pd1++] -= ((a[ps1-1] - a[ps1+1] + 2) >> 2);
            ps1++;
            }
            // S-transform*:
        ps1 = s1; pd1 = d1;
        for ( i = 0; i++ < n1; ) {
            a[ps1]   -= (a[pd1] >> 1);
            a[pd1++] += a[ps1++];
            }
            // merge:
        ps0 = s0;
        ps1 = s1; pd1 = d1;
        for ( i = 0; i++ < n1; ) {
            a[ps0++] = a[ps1++];
            a[ps0++] = a[pd1++];
            }
    }

    /**
     *  The benchmark algorithm itself. Needs not be re-entrant but can be iterated.
     */
    protected void test () {
        int a[] = new int[WAVE_MAX_SIZE+2];
        int total = WAVE_MAX_SIZE;
        int iter = WAVE_ITER;
        int i, s1, d1;
        do {
            total >>= 1;
            s1 = total + 1;
            d1 = s1 + (total >> 1) + 1;
            for ( i = 0; i++ < iter; ) {
                liftMemory(total,a,0,s1,d1);
                unliftMemory(total,a,0,s1,d1);
                }
            iter += iter;
            } while ( total >= WAVE_MIN_SIZE );
    }

    /**
     *  Result string of the test. Should be called after the <code>runTest()</code>
     *  was finished.
     *   @return Result of the test.
     */
    public String testResult () {
        return( "Wavelet T-S transform: arr: " + (WAVE_MAX_SIZE>>18) + "MB-" +
                (WAVE_MIN_SIZE>>8) + "KB, iter: " +
                (WAVE_ITER) + "-" + (WAVE_ITER*(long)WAVE_MAX_SIZE/WAVE_MIN_SIZE) );
    }

}
