Haar.java
package com.morphiqlabs.wavelet.api;
/**
* The Haar wavelet, the simplest possible wavelet.
*
* <p>The Haar wavelet is a step function that represents the simplest
* orthogonal wavelet. It has compact support and is particularly useful
* for educational purposes and applications requiring fast computation.</p>
*
* <p>Properties:
* <ul>
* <li>Orthogonal</li>
* <li>Compact support of width 2</li>
* <li>1 vanishing moment</li>
* <li>Discontinuous</li>
* </ul>
*
* <h2>Mathematical Foundation and History</h2>
* <p>The Haar wavelet was introduced by Alfréd Haar in 1909, making it the first
* wavelet ever described. It predates the formal wavelet theory by many decades.</p>
*
* <h2>Coefficient Sources</h2>
* <p>The Haar wavelet coefficients are derived from the mathematical definition:</p>
* <ul>
* <li>Haar, A. (1910). "Zur Theorie der orthogonalen Funktionensysteme",
* Mathematische Annalen, 69, pp. 331-371.</li>
* <li>Mallat, S. (2008). "A Wavelet Tour of Signal Processing", 3rd edition,
* Academic Press, Section 7.2.</li>
* <li>The coefficients are normalized to satisfy h[0] + h[1] = √2</li>
* </ul>
*
* <p>The normalized Haar scaling function coefficients are:</p>
* <ul>
* <li>h[0] = 1/√2 ≈ 0.7071067811865476</li>
* <li>h[1] = 1/√2 ≈ 0.7071067811865476</li>
* </ul>
*/
public record Haar() implements OrthogonalWavelet {
private static final double SQRT2_INV = 1.0 / Math.sqrt(2);
// Pre-computed filter coefficients to avoid allocations
private static final double[] LOW_PASS_COEFFS = {SQRT2_INV, SQRT2_INV};
private static final double[] HIGH_PASS_COEFFS = {SQRT2_INV, -SQRT2_INV};
// Static instance for consistency with other wavelets
public static final Haar INSTANCE = new Haar();
@Override
public String name() {
return "Haar";
}
@Override
public String description() {
return "Haar wavelet - the simplest orthogonal wavelet";
}
@Override
public double[] lowPassDecomposition() {
return LOW_PASS_COEFFS.clone();
}
@Override
public double[] highPassDecomposition() {
return HIGH_PASS_COEFFS.clone();
}
@Override
public int vanishingMoments() {
return 1;
}
/**
* Verifies that the Haar wavelet coefficients satisfy the required properties.
* This method validates the mathematical correctness of the implementation.
*
* <p>Properties verified:</p>
* <ul>
* <li>Sum of coefficients equals √2</li>
* <li>Sum of squared coefficients equals 1 (normalization)</li>
* <li>Orthogonality between low-pass and high-pass filters</li>
* </ul>
*
* @return true if all properties are satisfied
*/
public boolean verifyCoefficients() {
double tolerance = 1e-15; // Very high precision for simple Haar coefficients
// Check sum = √2
double sum = LOW_PASS_COEFFS[0] + LOW_PASS_COEFFS[1];
if (Math.abs(sum - Math.sqrt(2)) > tolerance) {
return false;
}
// Check normalization: sum of squares = 1
double sumSquares = LOW_PASS_COEFFS[0] * LOW_PASS_COEFFS[0] +
LOW_PASS_COEFFS[1] * LOW_PASS_COEFFS[1];
if (Math.abs(sumSquares - 1.0) > tolerance) {
return false;
}
// Check orthogonality between low-pass and high-pass
double dotProduct = LOW_PASS_COEFFS[0] * HIGH_PASS_COEFFS[0] +
LOW_PASS_COEFFS[1] * HIGH_PASS_COEFFS[1];
return !(Math.abs(dotProduct) > tolerance);
}
}