fixed a forgotten scaling factor in inverse Hadamard transform
added integer Hadamard transform note that the integer transform inverse is not always an integer transform git-svn-id: https://svn.apache.org/repos/asf/commons/proper/math/trunk@729849 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
ed35ae3dee
commit
7e2fad01b3
|
@ -23,16 +23,22 @@ import org.apache.commons.math.analysis.UnivariateRealFunction;
|
|||
/**
|
||||
* Implements the <a href="http://www.archive.chipcenter.com/dsp/DSP000517F1.html">Fast Hadamard Transform</a> (FHT).
|
||||
* Transformation of an input vector x to the output vector y.
|
||||
* <p>In addition to transformation of real vectors, the Hadamard transform can
|
||||
* transform integer vectors into integer vectors. However, this integer transform
|
||||
* cannot be inverted directly. Due to a scaling factor it may lead to rational results.
|
||||
* As an example, the inverse transform of integer vector (0, 1, 0, 1) is rational
|
||||
* vector (1/2, -1/2, 0, 0).</p>
|
||||
* @version $Revision$ $Date$
|
||||
* @since 2.0
|
||||
*/
|
||||
public class FastHadamardTransformer implements RealTransformer {
|
||||
|
||||
/** Serializable version identifier. */
|
||||
private static final long serialVersionUID = -710169279109099264L;
|
||||
private static final long serialVersionUID = -720498949613305350L;
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public double[] transform(double f[]) throws IllegalArgumentException {
|
||||
public double[] transform(double f[])
|
||||
throws IllegalArgumentException {
|
||||
return fht(f);
|
||||
}
|
||||
|
||||
|
@ -46,14 +52,29 @@ public class FastHadamardTransformer implements RealTransformer {
|
|||
/** {@inheritDoc} */
|
||||
public double[] inversetransform(double f[])
|
||||
throws IllegalArgumentException {
|
||||
return fht(f);
|
||||
}
|
||||
return FastFourierTransformer.scaleArray(fht(f), 1.0 / f.length);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public double[] inversetransform(UnivariateRealFunction f,
|
||||
double min, double max, int n)
|
||||
throws FunctionEvaluationException, IllegalArgumentException {
|
||||
return fht(FastFourierTransformer.sample(f, min, max, n));
|
||||
final double[] unscaled =
|
||||
fht(FastFourierTransformer.sample(f, min, max, n));
|
||||
return FastFourierTransformer.scaleArray(unscaled, 1.0 / n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform the given real data set.
|
||||
* <p>The integer transform cannot be inverted directly, due to a scaling
|
||||
* factor it may lead to double results.</p>
|
||||
* @param f the integer data array to be transformed (signal)
|
||||
* @return the integer transformed array (spectrum)
|
||||
* @throws IllegalArgumentException if any parameters are invalid
|
||||
*/
|
||||
public int[] transform(int f[])
|
||||
throws IllegalArgumentException {
|
||||
return fht(f);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -131,7 +152,7 @@ public class FastHadamardTransformer implements RealTransformer {
|
|||
*
|
||||
* @param x input vector
|
||||
* @return y output vector
|
||||
* @throws IllegalArgumentException
|
||||
* @exception IllegalArgumentException if input array is not a poer of 2
|
||||
*/
|
||||
protected double[] fht(double x[]) throws IllegalArgumentException {
|
||||
|
||||
|
@ -177,4 +198,55 @@ public class FastHadamardTransformer implements RealTransformer {
|
|||
return yCurrent;
|
||||
|
||||
}
|
||||
/**
|
||||
* The FHT (Fast Hadamard Transformation) which uses only subtraction and addition.
|
||||
* @param x input vector
|
||||
* @return y output vector
|
||||
* @exception IllegalArgumentException if input array is not a poer of 2
|
||||
*/
|
||||
protected int[] fht(int x[]) throws IllegalArgumentException {
|
||||
|
||||
// n is the row count of the input vector x
|
||||
final int n = x.length;
|
||||
final int halfN = n / 2;
|
||||
|
||||
// n has to be of the form n = 2^p !!
|
||||
if (!FastFourierTransformer.isPowerOf2(n)) {
|
||||
throw MathRuntimeException.createIllegalArgumentException("{0} is not a power of 2",
|
||||
new Object[] { n });
|
||||
}
|
||||
|
||||
// Instead of creating a matrix with p+1 columns and n rows
|
||||
// we will use two single dimension arrays which we will use in an alternating way.
|
||||
int[] yPrevious = new int[n];
|
||||
int[] yCurrent = x.clone();
|
||||
|
||||
// iterate from left to right (column)
|
||||
for (int j = 1; j < n; j <<= 1) {
|
||||
|
||||
// switch columns
|
||||
final int[] yTmp = yCurrent;
|
||||
yCurrent = yPrevious;
|
||||
yPrevious = yTmp;
|
||||
|
||||
// iterate from top to bottom (row)
|
||||
for (int i = 0; i < halfN; ++i) {
|
||||
// D<sub>top</sub>
|
||||
// The top part works with addition
|
||||
final int twoI = 2 * i;
|
||||
yCurrent[i] = yPrevious[twoI] + yPrevious[twoI + 1];
|
||||
}
|
||||
for (int i = halfN; i < n; ++i) {
|
||||
// D<sub>bottom</sub>
|
||||
// The bottom part works with subtraction
|
||||
final int twoI = 2 * i;
|
||||
yCurrent[i] = yPrevious[twoI - n] - yPrevious[twoI - n + 1];
|
||||
}
|
||||
}
|
||||
|
||||
// return the last computed output vector y
|
||||
return yCurrent;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -28,16 +28,28 @@ public final class FastHadamardTransformerTest extends TestCase {
|
|||
* Test of transformer for the a 8-point FHT (means n=8)
|
||||
*/
|
||||
public void test8Points() {
|
||||
checkTransform(new double[] { 1.0, 4.0, -2.0, 3.0, 0.0, 1.0, 4.0, -1.0 },
|
||||
new double[] { 10.0, -4.0, 2.0, -4.0, 2.0, -12.0, 6.0, 8.0 });
|
||||
checkAllTransforms(new int[] { 1, 4, -2, 3, 0, 1, 4, -1 },
|
||||
new int[] { 10, -4, 2, -4, 2, -12, 6, 8 });
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of transformer for the a 4-points FHT (means n=4)
|
||||
*/
|
||||
public void test4Points() {
|
||||
checkTransform(new double[] { 1.0, 2.0, 3.0, 4.0 },
|
||||
new double[] { 10.0, -2.0, -4.0, 0.0 });
|
||||
checkAllTransforms(new int[] { 1, 2, 3, 4 },
|
||||
new int[] { 10, -2, -4, 0 });
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the inverse transform of an integer vector is not always an integer vector
|
||||
*/
|
||||
public void testNoIntInverse() {
|
||||
FastHadamardTransformer transformer = new FastHadamardTransformer();
|
||||
double[] x = transformer.inversetransform(new double[] { 0, 1, 0, 1});
|
||||
assertEquals( 0.5, x[0], 0);
|
||||
assertEquals(-0.5, x[1], 0);
|
||||
assertEquals( 0.0, x[2], 0);
|
||||
assertEquals( 0.0, x[3], 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -52,17 +64,56 @@ public final class FastHadamardTransformerTest extends TestCase {
|
|||
}
|
||||
}
|
||||
|
||||
private void checkTransform(double[]x, double[] y) {
|
||||
private void checkAllTransforms(int[]x, int[] y) {
|
||||
checkDoubleTransform(x, y);
|
||||
checkInverseDoubleTransform(x, y);
|
||||
checkIntTransform(x, y);
|
||||
}
|
||||
|
||||
private void checkDoubleTransform(int[]x, int[] y) {
|
||||
// Initiate the transformer
|
||||
FastHadamardTransformer transformer = new FastHadamardTransformer();
|
||||
|
||||
// transform input vector x to output vector
|
||||
double result[] = transformer.transform(x);
|
||||
|
||||
for (int i=0;i<result.length;i++) {
|
||||
// compare computed results to precomputed results
|
||||
assertEquals(y[i], result[i]);
|
||||
// check double transform
|
||||
double[] dX = new double[x.length];
|
||||
for (int i = 0; i < dX.length; ++i) {
|
||||
dX[i] = (double) x[i];
|
||||
}
|
||||
double dResult[] = transformer.transform(dX);
|
||||
for (int i = 0; i < dResult.length; i++) {
|
||||
// compare computed results to precomputed results
|
||||
assertEquals((double) y[i], dResult[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkIntTransform(int[]x, int[] y) {
|
||||
// Initiate the transformer
|
||||
FastHadamardTransformer transformer = new FastHadamardTransformer();
|
||||
|
||||
// check integer transform
|
||||
int iResult[] = transformer.transform(x);
|
||||
for (int i = 0; i < iResult.length; i++) {
|
||||
// compare computed results to precomputed results
|
||||
assertEquals(y[i], iResult[i]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void checkInverseDoubleTransform(int[]x, int[] y) {
|
||||
// Initiate the transformer
|
||||
FastHadamardTransformer transformer = new FastHadamardTransformer();
|
||||
|
||||
// check double transform
|
||||
double[] dY = new double[y.length];
|
||||
for (int i = 0; i < dY.length; ++i) {
|
||||
dY[i] = (double) y[i];
|
||||
}
|
||||
double dResult[] = transformer.inversetransform(dY);
|
||||
for (int i = 0; i < dResult.length; i++) {
|
||||
// compare computed results to precomputed results
|
||||
assertEquals((double) x[i], dResult[i]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue