package be.tarsos.dsp.wavelet.lift;

/**
 
* <p>
 
* HaarWavelet (flat LineWavelet) wavelet.
 
* </p>
 
*
 
* <p>
 
* As with all Lifting scheme wavelet transform functions, the first stage of a
 
* transform step is the split stage. The split step moves the even element to
 
* the first half of an N element region and the odd elements to the second half
 
* of the N element region.
 
* </p>
 
*
 
* <p>
 
* The Lifting Scheme version of the HaarWavelet transform uses a wavelet
 
* function (predict stage) that "predicts" that an odd element will have the
 
* same value as it preceeding even element. Stated another way, the odd element
 
* is "predicted" to be on a flat (zero slope LineWavelet) shared with the even
 
* point. The difference between this "prediction" and the actual odd value
 
* replaces the odd element.
 
* </p>
 
*
 
* <p>
 
* The wavelet scaling function (a.k.a. smoothing function) used in the update
 
* stage calculates the average between an even and an odd element.
 
* </p>
 
*
 
* <p>
 
* The merge stage at the end of the inverse transform interleaves odd and even
 
* elements from the two halves of the array (e.g., ordering them
 
* even<sub>0</sub>, odd<sub>0</sub>, even<sub>1</sub>, odd<sub>1</sub>, ...)
 
* </p>
 
*
 
* <h4>
 
* Copyright and Use</h4>
 
*
 
* <p>
 
* You may use this source code without limitation and without fee as long as
 
* you include:
 
* </p>
 
* <blockquote> This software was written and is copyrighted by Ian Kaplan, Bear
 
* Products International, www.bearcave.com, 2001. </blockquote>
 
* <p>
 
* This software is provided "as is", without any warrenty or claim as to its
 
* usefulness. Anyone who uses this source code uses it at their own risk. Nor
 
* is any support provided by Ian Kaplan and Bear Products International.
 
* <p>
 
* Please send any bug fixes or suggested source changes to:
 
*
 
* <pre>
 
*
      
iank@bearcave.com
 
* </pre>
 
*
 
* @author Ian Kaplan
 
*/

public class HaarWavelet extends LiftingSchemeBaseWavelet {

	
/**
	 
* HaarWavelet predict step
	 
*/
	
protected void predict(float[] vec, int N, int direction) {
		
int half = N >> 1;

		
for (int i = 0; i < half; i++) {
			
float predictVal = vec[i];
			
int j = i + half;

			
if (direction == forward) {
				
vec[j] = vec[j] - predictVal;
			
} else if (direction == inverse) {
				
vec[j] = vec[j] + predictVal;
			
} else {
				
System.out.println("HaarWavelet::predict: bad direction value");
			
}
		
}
	
}

	
public void forwardTransOne(float[] vec) {
		
final int N = vec.length;

		
split(vec, N);
		
predict(vec, N, forward);
		
update(vec, N, forward);

	
} // forwardTrans

	
/**
	 
* <p>
	 
* Update step of the HaarWavelet wavelet transform.
	 
* </p>
	 
* <p>
	 
* The wavelet transform calculates a set of detail or difference
	 
* coefficients in the predict step. These are stored in the upper half of
	 
* the array. The update step calculates an average from the even-odd
	 
* element pairs. The averages will replace the even elements in the lower
	 
* half of the array.
	 
* </p>
	 
* <p>
	 
* The HaarWavelet wavelet calculation used in the Lifting Scheme is
	 
* </p>
	 
*
 

	 
* <pre>
	 
*
        
d<sub>j+1, i</sub> = odd<sub>j+1, i</sub> = odd<sub>j, i</sub> - even<sub>j, i</sub>
	 
*
        
a<sub>j+1, i</sub> = even<sub>j, i</sub> = (even<sub>j, i</sub> + odd<sub>j, i</sub>)/2
	 
* </pre>
	 
* <p>
	 
* Note that the Lifting Scheme uses an in-place algorithm. The odd elements
	 
* have been replaced by the detail coefficients in the predict step. With a
	 
* little algebra we can substitute the coefficient calculation into the
	 
* average calculation, which gives us
	 
* </p>
	 
*
 

	 
* <pre>
	 
*
        
a<sub>j+1, i</sub> = even<sub>j, i</sub> = even<sub>j, i</sub> + (odd<sub>j, i</sub>/2)
	 
* </pre>
	 
*/

	
protected void update(float[] vec, int N, int direction) {
		
int half = N >> 1;

		
for (int i = 0; i < half; i++) {
			
int j = i + half;
			
float updateVal = vec[j] / 2.0f;

			
if (direction == forward) {
				
vec[i] = vec[i] + updateVal;
			
} else if (direction == inverse) {
				
vec[i] = vec[i] - updateVal;
			
} else {
				
System.out.println("update: bad direction value");
			
}
		
}
	
}

} // HaarWavelet