import java.io.*;

/**
 *  Benchmark #10 - Wavelet transform on disk.
 *   @author  Josef.Pelikan@mff.cuni.cz
 *   @version 0.007 (2001/06/21)
 *   @since   0.007
 */
public class BenchmarkWaveletDisk extends Benchmark {

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

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

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

    /** File name for S0. */
    protected final static String S0_FILE_NAME = "s0.bin";

    /** File name for S1. */
    protected final static String S1_FILE_NAME = "s1.bin";

    /** File name for D1. */
    protected final static String D1_FILE_NAME = "d1.bin";

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

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

    /**
     *  Computes forward TS-transform on disk files.
     *   @param  n0 Size of the source segment (<code>s0</code>).
     *   @param  s0 File holding the source segment.
     *   @param  s1 File holding the smooth destination segment.
     *   @param  d1 File holding the wavelet destination segment.
     */
    protected static void liftDisk ( int n0, FileOfDouble s0, FileOfDouble s1, FileOfDouble d1 ) {
        int n1 = n0 >> 1;
        int i;
            // split + S-transform + prediction:
        s0.seek(0);
        s1.seek(0);
        d1.seek(0);
        double as0, as1, as2;
        double ad0, ad1, ad2;
        as1 = s0.get();
        ad1 = s0.get();
        ad1 -= as1;
        as1 += ad1 * 0.5;
        as0 = 0.0;
        for ( i = 1; i++ < n1; ) {
            as2 = s0.get();
            ad2 = s0.get();
            ad2 -= as2;
            as2 += ad2 * 0.5;
            ad1 += (as2 + as0) * 0.25;
            s1.put(as1);
            d1.put(ad1);
            as0 = as1;
            as1 = as2;
            ad1 = ad2;
            }
        as2 = 0.0;
        ad1 += (as2 + as0) * 0.25;
        s1.put(as1);
        d1.put(ad1);
    }

    /**
     *  Computes backward TS-transform on disk files.
     *   @param  n0 Size of the destination segment (<code>s0</code>).
     *   @param  s0 File holding the destination segment.
     *   @param  s1 File holding the smooth source segment.
     *   @param  d1 File holding the wavelet source segment.
     */
    protected static void unliftDisk ( int n0, FileOfDouble s0, FileOfDouble s1, FileOfDouble d1 ) {
        int n1 = n0 >> 1;
        int i;
            // predict* + S-transform* + merge:
        s0.seek(0);
        s1.seek(0);
        d1.seek(0);
        double as0, as1, as2;
        double ad0, ad1, ad2;
        as0 = 0.0;
        as1 = s1.get();
        ad1 = d1.get();
        for ( i = 1; i++ < n1; ) {
            as2 = s1.get();
            ad2 = d1.get();
            ad1 -= (as2 + as0) * 0.25;
            double s1act = as1 - ad1 * 0.5;
            ad1 += s1act;
            s0.put(s1act);
            s0.put(ad1);
            as0 = as1;
            as1 = as2;
            ad1 = ad2;
            }
        as2 = 0.0;
        ad1 -= (as2 + as0) * 0.25;
        as1 -= ad1 * 0.5;
        ad1 += as1;
        s0.put(as1);
        s0.put(ad1);
    }

    /**
     *  The benchmark algorithm itself. Needs not be re-entrant but can be iterated.
     */
    protected void test () {
        FileOfDouble s0 = new FileOfDouble(S0_FILE_NAME,true);
        FileOfDouble s1 = new FileOfDouble(S1_FILE_NAME,true);
        FileOfDouble d1 = new FileOfDouble(D1_FILE_NAME,true);
        int total = WAVE_MAX_SIZE;
        int iter = WAVE_ITER;
        int i;
        RandomJames rnd = new RandomJames();
        do {
            s0.rewrite();
            s1.rewrite();
            d1.rewrite();
            i = (total >>= 1);
            do
                s0.put(rnd.uniformNumber());
            while ( --i > 0 );
            for ( i = 0; i++ < iter; ) {
                liftDisk(total,s0,s1,d1);
                unliftDisk(total,s0,s1,d1);
                }
            iter += iter;
            } while ( total >= WAVE_MIN_SIZE );
        s0.close();
        s1.close();
        d1.close();
        File f;
        try {
            f = new File(S0_FILE_NAME);
            f.delete();
            f = new File(S1_FILE_NAME);
            f.delete();
            f = new File(D1_FILE_NAME);
            f.delete();
            }
        catch ( SecurityException e ) {
            }
    }

    /**
     *  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 on disk: arr: " + (WAVE_MAX_SIZE>>17) + "MB-" +
                (WAVE_MIN_SIZE>>17) + "MB, iter: " +
                (WAVE_ITER) + "-" + (WAVE_ITER*(long)WAVE_MAX_SIZE/WAVE_MIN_SIZE) );
    }

}
