In o.a.c.m.transform, introduced an enumeration for the type (forward, inverse) of transform asked by the user (MATH-743).

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/math/trunk@1242703 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Sebastien Brisard 2012-02-10 08:46:40 +00:00
parent 49c39e7d1c
commit dee1c0d70b
5 changed files with 307 additions and 514 deletions

View File

@ -25,7 +25,7 @@ import org.apache.commons.math.exception.MathIllegalArgumentException;
import org.apache.commons.math.exception.NonMonotonicSequenceException;
import org.apache.commons.math.exception.NotStrictlyPositiveException;
import org.apache.commons.math.exception.util.LocalizedFormats;
import org.apache.commons.math.transform.FastFourierTransformer.Normalization;
import org.apache.commons.math.transform.FastFourierTransformer.DftNormalization;
import org.apache.commons.math.util.ArithmeticUtils;
import org.apache.commons.math.util.FastMath;
@ -273,8 +273,8 @@ public class FastCosineTransformer implements RealTransformer, Serializable {
t1 += c;
}
FastFourierTransformer transformer;
transformer = new FastFourierTransformer(Normalization.STANDARD);
Complex[] y = transformer.transform(x);
transformer = new FastFourierTransformer(DftNormalization.STANDARD);
Complex[] y = transformer.transform(x, TransformType.FORWARD);
// reconstruct the FCT result for the original array
transformed[0] = y[0].getReal();

View File

@ -85,17 +85,22 @@ import org.apache.commons.math.util.MathArrays;
*/
public class FastFourierTransformer implements Serializable {
/** The various types of normalizations that can be applied. */
public static enum Normalization {
/** Standard DFT. */
/**
* The various types of normalizations that can be applied to discrete
* Fourier transforms.
*
* @see FastFourierTransformer
*/
public static enum DftNormalization {
/** The normalization to be specified for standard DFT. */
STANDARD,
/** Unitary DFT. */
/** The normalization to be specified for unitary DFT. */
UNITARY;
}
/** Serializable version identifier. */
static final long serialVersionUID = 20120902L;
static final long serialVersionUID = 20120210L;
/**
* {@code W_SUB_N_R[i]} is the real part of
@ -143,19 +148,18 @@ public class FastFourierTransformer implements Serializable {
, -0x1.921fb54442d18p-54, -0x1.921fb54442d18p-55, -0x1.921fb54442d18p-56, -0x1.921fb54442d18p-57
, -0x1.921fb54442d18p-58, -0x1.921fb54442d18p-59, -0x1.921fb54442d18p-60 };
/**
* The type of DFT to be performed.
*/
private final Normalization type;
/** The type of DFT to be performed. */
private final DftNormalization normalization;
/**
* Creates a new instance of this class, with various normalization
* conventions.
*
* @param type the type of transform to be computed
* @param normalization the type of normalization to be applied to the
* transformed data
*/
public FastFourierTransformer(final Normalization type) {
this.type = type;
public FastFourierTransformer(final DftNormalization normalization) {
this.normalization = normalization;
}
/**
@ -199,21 +203,21 @@ public class FastFourierTransformer implements Serializable {
* Applies the proper normalization to the specified transformed data.
*
* @param dataRI the unscaled transformed data
* @param type the type of transform
* @param inverse {@code true} if normalization should be performed for the
* inverse transform
* @param normalization the normalization to be applied
* @param type the type of transform (forward, inverse) which resulted in the
* specified data
*/
private static void normalizeTransformedData(final double[][] dataRI,
final Normalization type, final boolean inverse) {
final DftNormalization normalization, final TransformType type) {
final double[] dataR = dataRI[0];
final double[] dataI = dataRI[1];
final int n = dataR.length;
assert dataI.length == n;
switch (type) {
switch (normalization) {
case STANDARD:
if (inverse) {
if (type == TransformType.INVERSE) {
final double scaleFactor = 1.0 / ((double) n);
for (int i = 0; i < n; i++) {
dataR[i] *= scaleFactor;
@ -251,18 +255,16 @@ public class FastFourierTransformer implements Serializable {
*
* @param dataRI the two dimensional array of real and imaginary parts of
* the data
* @param type the type of normalization to be applied to the transformed
* @param normalization the normalization to be applied to the transformed
* data
* @param inverse {@code true} if the inverse standard transform must be
* performed
* @param type the type of transform (forward, inverse) to be performed
* @throws DimensionMismatchException if the number of rows of the specified
* array is not two, or the array is not rectangular
* @throws MathIllegalArgumentException if the number of data points is not
* a power of two
*/
public static void transformInPlace(final double[][] dataRI,
final Normalization type, final boolean inverse) throws
DimensionMismatchException, MathIllegalArgumentException {
final DftNormalization normalization, final TransformType type) {
if (dataRI.length != 2) {
throw new DimensionMismatchException(dataRI.length, 2);
@ -295,14 +297,14 @@ public class FastFourierTransformer implements Serializable {
dataR[1] = srcR0 - srcR1;
dataI[1] = srcI0 - srcI1;
normalizeTransformedData(dataRI, type, inverse);
normalizeTransformedData(dataRI, normalization, type);
return;
}
bitReversalShuffle2(dataR, dataI);
// Do 4-term DFT.
if (inverse) {
if (type == TransformType.INVERSE) {
for (int i0 = 0; i0 < n; i0 += 4) {
final int i1 = i0 + 1;
final int i2 = i0 + 2;
@ -369,7 +371,7 @@ public class FastFourierTransformer implements Serializable {
int logN0 = lastLogN0 + 1;
double wSubN0R = W_SUB_N_R[logN0];
double wSubN0I = W_SUB_N_I[logN0];
if (inverse) {
if (type == TransformType.INVERSE) {
wSubN0I = -wSubN0I;
}
@ -405,41 +407,37 @@ public class FastFourierTransformer implements Serializable {
lastLogN0 = logN0;
}
normalizeTransformedData(dataRI, type, inverse);
normalizeTransformedData(dataRI, normalization, type);
}
/**
* Returns the forward transform of the specified real data set.
* Returns the (forward, inverse) transform of the specified real data set.
*
* @param f the real data array to be transformed
* @param type the type of transform (forward, inverse) to be performed
* @return the complex transformed array
* @throws MathIllegalArgumentException if the length of the data array is
* not a power of two
*/
public Complex[] transform(double[] f) {
public Complex[] transform(final double[] f, final TransformType type) {
final double[][] dataRI = new double[][] {
MathArrays.copyOf(f, f.length), new double[f.length]
};
transformInPlace(dataRI, type, false);
// if (unitary) {
// final double s = 1.0 / FastMath.sqrt(f.length);
// TransformUtils.scaleArray(dataRI[0], s);
// TransformUtils.scaleArray(dataRI[1], s);
// }
transformInPlace(dataRI, normalization, type);
return TransformUtils.createComplexArray(dataRI);
}
/**
* Returns the forward transform of the specified real function, sampled on
* the specified interval.
* Returns the (forward, inverse) transform of the specified real function,
* sampled on the specified interval.
*
* @param f the function to be sampled and transformed
* @param min the (inclusive) lower bound for the interval
* @param max the (exclusive) upper bound for the interval
* @param n the number of sample points
* @param type the type of transform (forward, inverse) to be performed
* @return the complex transformed array
* @throws org.apache.commons.math.exception.NumberIsTooLargeException
* if the lower bound is greater than, or equal to the upper bound
@ -448,98 +446,28 @@ public class FastFourierTransformer implements Serializable {
* @throws MathIllegalArgumentException if the number of sample points
* {@code n} is not a power of two
*/
public Complex[] transform(UnivariateFunction f,
double min, double max, int n) {
public Complex[] transform(final UnivariateFunction f,
final double min, final double max, final int n,
final TransformType type) {
final double[] data = FunctionUtils.sample(f, min, max, n);
return transform(data);
return transform(data, type);
}
/**
* Returns the forward transform of the specified complex data set.
* Returns the (forward, inverse) transform of the specified complex data
* set.
*
* @param f the complex data array to be transformed
* @param type the type of transform (forward, inverse) to be performed
* @return the complex transformed array
* @throws MathIllegalArgumentException if the length of the data array is
* not a power of two
*/
public Complex[] transform(Complex[] f) {
public Complex[] transform(final Complex[] f, final TransformType type) {
final double[][] dataRI = TransformUtils.createRealImaginaryArray(f);
transformInPlace(dataRI, type, false);
// if (unitary) {
// final double s = 1.0 / FastMath.sqrt(f.length);
// TransformUtils.scaleArray(dataRI[0], s);
// TransformUtils.scaleArray(dataRI[1], s);
// }
return TransformUtils.createComplexArray(dataRI);
}
/**
* Returns the inverse transform of the specified real data set.
*
* @param f the real data array to be inversely transformed
* @return the complex inversely transformed array
* @throws MathIllegalArgumentException if the length of the data array is
* not a power of two
*/
public Complex[] inverseTransform(double[] f) {
final double[][] dataRI = new double[][] {
MathArrays.copyOf(f, f.length), new double[f.length]
};
transformInPlace(dataRI, type, true);
// if (unitary) {
// final double s = FastMath.sqrt(f.length);
// TransformUtils.scaleArray(dataRI[0], s);
// TransformUtils.scaleArray(dataRI[1], s);
// }
return TransformUtils.createComplexArray(dataRI);
}
/**
* Returns the inverse transform of the specified real function, sampled
* on the given interval.
*
* @param f the function to be sampled and inversely transformed
* @param min the (inclusive) lower bound for the interval
* @param max the (exclusive) upper bound for the interval
* @param n the number of sample points
* @return the complex inversely transformed array
* @throws org.apache.commons.math.exception.NumberIsTooLargeException
* if the lower bound is greater than, or equal to the upper bound
* @throws org.apache.commons.math.exception.NotStrictlyPositiveException
* if the number of sample points {@code n} is negative
* @throws MathIllegalArgumentException if the number of sample points
* {@code n} is not a power of two
*/
public Complex[] inverseTransform(UnivariateFunction f,
double min, double max, int n) {
final double[] data = FunctionUtils.sample(f, min, max, n);
return inverseTransform(data);
}
/**
* Returns the inverse transform of the specified complex data set.
*
* @param f the complex data array to be inversely transformed
* @return the complex inversely transformed array
* @throws MathIllegalArgumentException if the length of the data array is
* not a power of two
*/
public Complex[] inverseTransform(Complex[] f) {
final double[][] dataRI = TransformUtils.createRealImaginaryArray(f);
final double[] dataR = dataRI[0];
final double[] dataI = dataRI[1];
transformInPlace(dataRI, type, true);
// if (unitary) {
// final double s = FastMath.sqrt(f.length);
// TransformUtils.scaleArray(dataR, s);
// TransformUtils.scaleArray(dataI, s);
// }
transformInPlace(dataRI, normalization, type);
return TransformUtils.createComplexArray(dataRI);
}
@ -555,19 +483,20 @@ public class FastFourierTransformer implements Serializable {
*
* @param mdca Multi-Dimensional Complex Array id est
* {@code Complex[][][][]}
* @param forward {@link #inverseTransform} is performed if this is
* {@code false}
* @param type the type of transform (forward, inverse) to be performed
* @return transform of {@code mdca} as a Multi-Dimensional Complex Array
* id est {@code Complex[][][][]}
* @throws IllegalArgumentException if any dimension is not a power of two
* @deprecated see MATH-736
*/
public Object mdfft(Object mdca, boolean forward) {
@Deprecated
public Object mdfft(Object mdca, TransformType type) {
MultiDimensionalComplexMatrix mdcm = (MultiDimensionalComplexMatrix)
new MultiDimensionalComplexMatrix(mdca).clone();
int[] dimensionSize = mdcm.getDimensionSizes();
//cycle through each dimension
for (int i = 0; i < dimensionSize.length; i++) {
mdfft(mdcm, forward, i, new int[0]);
mdfft(mdcm, type, i, new int[0]);
}
return mdcm.getArray();
}
@ -576,14 +505,15 @@ public class FastFourierTransformer implements Serializable {
* Performs one dimension of a multi-dimensional Fourier transform.
*
* @param mdcm input matrix
* @param forward {@link #inverseTransform} is performed if this is
* {@code false}
* @param type the type of transform (forward, inverse) to be performed
* @param d index of the dimension to process
* @param subVector recursion subvector
* @throws IllegalArgumentException if any dimension is not a power of two
* @deprecated see MATH-736
*/
@Deprecated
private void mdfft(MultiDimensionalComplexMatrix mdcm,
boolean forward, int d, int[] subVector) {
TransformType type, int d, int[] subVector) {
int[] dimensionSize = mdcm.getDimensionSizes();
//if done
@ -595,11 +525,7 @@ public class FastFourierTransformer implements Serializable {
temp[i] = mdcm.get(subVector);
}
if (forward) {
temp = transform(temp);
} else {
temp = inverseTransform(temp);
}
temp = transform(temp, type);
for (int i = 0; i < dimensionSize[d]; i++) {
subVector[d] = i;
@ -612,12 +538,12 @@ public class FastFourierTransformer implements Serializable {
//value is not important once the recursion is done.
//then an fft will be applied along the dimension d.
vector[d] = 0;
mdfft(mdcm, forward, d, vector);
mdfft(mdcm, type, d, vector);
} else {
for (int i = 0; i < dimensionSize[subVector.length]; i++) {
vector[subVector.length] = i;
//further split along the next dimension
mdfft(mdcm, forward, d, vector);
mdfft(mdcm, type, d, vector);
}
}
}
@ -629,7 +555,10 @@ public class FastFourierTransformer implements Serializable {
* eventually be replaced by jsr-83 of the java community process
* http://jcp.org/en/jsr/detail?id=83
* may require additional exception throws for other basic requirements.
*
* @deprecated see MATH-736
*/
@Deprecated
private static class MultiDimensionalComplexMatrix
implements Cloneable {

View File

@ -25,7 +25,7 @@ import org.apache.commons.math.exception.MathIllegalArgumentException;
import org.apache.commons.math.exception.NonMonotonicSequenceException;
import org.apache.commons.math.exception.NotStrictlyPositiveException;
import org.apache.commons.math.exception.util.LocalizedFormats;
import org.apache.commons.math.transform.FastFourierTransformer.Normalization;
import org.apache.commons.math.transform.FastFourierTransformer.DftNormalization;
import org.apache.commons.math.util.ArithmeticUtils;
import org.apache.commons.math.util.FastMath;
@ -294,8 +294,8 @@ public class FastSineTransformer implements RealTransformer, Serializable {
x[n - i] = a - b;
}
FastFourierTransformer transformer;
transformer = new FastFourierTransformer(Normalization.STANDARD);
Complex[] y = transformer.transform(x);
transformer = new FastFourierTransformer(DftNormalization.STANDARD);
Complex[] y = transformer.transform(x, TransformType.FORWARD);
// reconstruct the FST result for the original array
transformed[0] = 0.0;

View File

@ -0,0 +1,31 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.math.transform;
/**
* This enumeration defines the type of transform which is to be computed.
*
* @version $Id Revision$
* @since 3.0
*/
public enum TransformType {
/** The type to be specified for forward transforms. */
FORWARD,
/** The type to be specified for inverse transforms. */
INVERSE;
}

View File

@ -26,7 +26,7 @@ import org.apache.commons.math.complex.Complex;
import org.apache.commons.math.exception.MathIllegalArgumentException;
import org.apache.commons.math.exception.NotStrictlyPositiveException;
import org.apache.commons.math.exception.NumberIsTooLargeException;
import org.apache.commons.math.transform.FastFourierTransformer.Normalization;
import org.apache.commons.math.transform.FastFourierTransformer.DftNormalization;
import org.apache.commons.math.util.FastMath;
import org.junit.Assert;
import org.junit.Test;
@ -44,191 +44,123 @@ public final class FastFourierTransformerTest {
private final static long SEED = 20110111L;
/*
* Precondition checks for standard transform.
* Precondition checks.
*/
@Test(expected = MathIllegalArgumentException.class)
public void testStandardTransformComplexSizeNotAPowerOfTwo() {
@Test
public void testTransformComplexSizeNotAPowerOfTwo() {
final int n = 127;
final Complex[] x = createComplexData(n);
final FastFourierTransformer fft;
fft = new FastFourierTransformer(Normalization.STANDARD);
fft.transform(x);
final FastFourierTransformer.DftNormalization[] norm;
norm = FastFourierTransformer.DftNormalization.values();
final TransformType[] type;
type = TransformType.values();
for (int i = 0; i < norm.length; i++) {
for (int j = 0; j < type.length; j++) {
final FastFourierTransformer fft;
fft = new FastFourierTransformer(norm[i]);
try {
fft.transform(x, type[j]);
Assert.fail(norm[i] + ", " + type[j] +
": MathIllegalArgumentException was expected");
} catch (MathIllegalArgumentException e) {
// Expected behaviour
}
}
}
}
@Test(expected = MathIllegalArgumentException.class)
public void testStandardTransformRealSizeNotAPowerOfTwo() {
@Test
public void testTransformRealSizeNotAPowerOfTwo() {
final int n = 127;
final double[] x = createRealData(n);
final FastFourierTransformer fft;
fft = new FastFourierTransformer(Normalization.STANDARD);
fft.transform(x);
final FastFourierTransformer.DftNormalization[] norm;
norm = FastFourierTransformer.DftNormalization.values();
final TransformType[] type;
type = TransformType.values();
for (int i = 0; i < norm.length; i++) {
for (int j = 0; j < type.length; j++) {
final FastFourierTransformer fft;
fft = new FastFourierTransformer(norm[i]);
try {
fft.transform(x, type[j]);
Assert.fail(norm[i] + ", " + type[j] +
": MathIllegalArgumentException was expected");
} catch (MathIllegalArgumentException e) {
// Expected behaviour
}
}
}
}
@Test(expected = MathIllegalArgumentException.class)
public void testStandardTransformFunctionSizeNotAPowerOfTwo() {
@Test
public void testTransformFunctionSizeNotAPowerOfTwo() {
final int n = 127;
final UnivariateFunction f = new Sin();
final FastFourierTransformer fft;
fft = new FastFourierTransformer(Normalization.STANDARD);
fft.transform(f, 0.0, Math.PI, n);
final FastFourierTransformer.DftNormalization[] norm;
norm = FastFourierTransformer.DftNormalization.values();
final TransformType[] type;
type = TransformType.values();
for (int i = 0; i < norm.length; i++) {
for (int j = 0; j < type.length; j++) {
final FastFourierTransformer fft;
fft = new FastFourierTransformer(norm[i]);
try {
fft.transform(f, 0.0, Math.PI, n, type[j]);
Assert.fail(norm[i] + ", " + type[j] +
": MathIllegalArgumentException was expected");
} catch (MathIllegalArgumentException e) {
// Expected behaviour
}
}
}
}
@Test(expected = NotStrictlyPositiveException.class)
public void testStandardTransformFunctionNotStrictlyPositiveNumberOfSamples() {
@Test
public void testTransformFunctionNotStrictlyPositiveNumberOfSamples() {
final int n = -128;
final UnivariateFunction f = new Sin();
final FastFourierTransformer fft;
fft = new FastFourierTransformer(Normalization.STANDARD);
fft.transform(f, 0.0, Math.PI, n);
final FastFourierTransformer.DftNormalization[] norm;
norm = FastFourierTransformer.DftNormalization.values();
final TransformType[] type;
type = TransformType.values();
for (int i = 0; i < norm.length; i++) {
for (int j = 0; j < type.length; j++) {
final FastFourierTransformer fft;
fft = new FastFourierTransformer(norm[i]);
try {
fft.transform(f, 0.0, Math.PI, n, type[j]);
fft.transform(f, 0.0, Math.PI, n, type[j]);
Assert.fail(norm[i] + ", " + type[j] +
": NotStrictlyPositiveException was expected");
} catch (NotStrictlyPositiveException e) {
// Expected behaviour
}
}
}
}
@Test(expected = NumberIsTooLargeException.class)
public void testStandardTransformFunctionInvalidBounds() {
@Test
public void testTransformFunctionInvalidBounds() {
final int n = 128;
final UnivariateFunction f = new Sin();
final FastFourierTransformer fft;
fft = new FastFourierTransformer(Normalization.STANDARD);
fft.transform(f, Math.PI, 0.0, n);
}
@Test(expected = MathIllegalArgumentException.class)
public void testStandardInverseTransformComplexSizeNotAPowerOfTwo() {
final int n = 127;
final Complex[] x = createComplexData(n);
final FastFourierTransformer fft;
fft = new FastFourierTransformer(Normalization.STANDARD);
fft.inverseTransform(x);
}
@Test(expected = MathIllegalArgumentException.class)
public void testStandardInverseTransformRealSizeNotAPowerOfTwo() {
final int n = 127;
final double[] x = createRealData(n);
final FastFourierTransformer fft;
fft = new FastFourierTransformer(Normalization.STANDARD);
fft.inverseTransform(x);
}
@Test(expected = MathIllegalArgumentException.class)
public void testStandardInverseTransformFunctionSizeNotAPowerOfTwo() {
final int n = 127;
final UnivariateFunction f = new Sin();
final FastFourierTransformer fft;
fft = new FastFourierTransformer(Normalization.STANDARD);
fft.inverseTransform(f, 0.0, Math.PI, n);
}
@Test(expected = NotStrictlyPositiveException.class)
public void testStandardInverseTransformFunctionNotStrictlyPositiveNumberOfSamples() {
final int n = -128;
final UnivariateFunction f = new Sin();
final FastFourierTransformer fft;
fft = new FastFourierTransformer(Normalization.STANDARD);
fft.inverseTransform(f, 0.0, Math.PI, n);
}
@Test(expected = NumberIsTooLargeException.class)
public void testStandardInverseTransformFunctionInvalidBounds() {
final int n = 128;
final UnivariateFunction f = new Sin();
final FastFourierTransformer fft;
fft = new FastFourierTransformer(Normalization.STANDARD);
fft.transform(f, Math.PI, 0.0, n);
}
/*
* Precondition checks for unitary transform.
*/
@Test(expected = MathIllegalArgumentException.class)
public void testUnitaryTransformComplexSizeNotAPowerOfTwo() {
final int n = 127;
final Complex[] x = createComplexData(n);
final FastFourierTransformer fft;
fft = new FastFourierTransformer(Normalization.UNITARY);
fft.transform(x);
}
@Test(expected = MathIllegalArgumentException.class)
public void testUnitaryTransformRealSizeNotAPowerOfTwo() {
final int n = 127;
final double[] x = createRealData(n);
final FastFourierTransformer fft;
fft = new FastFourierTransformer(Normalization.UNITARY);
fft.transform(x);
}
@Test(expected = MathIllegalArgumentException.class)
public void testUnitaryTransformFunctionSizeNotAPowerOfTwo() {
final int n = 127;
final UnivariateFunction f = new Sin();
final FastFourierTransformer fft;
fft = new FastFourierTransformer(Normalization.UNITARY);
fft.transform(f, 0.0, Math.PI, n);
}
@Test(expected = NotStrictlyPositiveException.class)
public void testUnitaryTransformFunctionNotStrictlyPositiveNumberOfSamples() {
final int n = -128;
final UnivariateFunction f = new Sin();
final FastFourierTransformer fft;
fft = new FastFourierTransformer(Normalization.UNITARY);
fft.transform(f, 0.0, Math.PI, n);
}
@Test(expected = NumberIsTooLargeException.class)
public void testUnitaryTransformFunctionInvalidBounds() {
final int n = 128;
final UnivariateFunction f = new Sin();
final FastFourierTransformer fft;
fft = new FastFourierTransformer(Normalization.UNITARY);
fft.transform(f, Math.PI, 0.0, n);
}
@Test(expected = MathIllegalArgumentException.class)
public void testUnitaryInverseTransformComplexSizeNotAPowerOfTwo() {
final int n = 127;
final Complex[] x = createComplexData(n);
final FastFourierTransformer fft;
fft = new FastFourierTransformer(Normalization.UNITARY);
fft.inverseTransform(x);
}
@Test(expected = MathIllegalArgumentException.class)
public void testUnitaryInverseTransformRealSizeNotAPowerOfTwo() {
final int n = 127;
final double[] x = createRealData(n);
final FastFourierTransformer fft;
fft = new FastFourierTransformer(Normalization.UNITARY);
fft.inverseTransform(x);
}
@Test(expected = MathIllegalArgumentException.class)
public void testUnitaryInverseTransformFunctionSizeNotAPowerOfTwo() {
final int n = 127;
final UnivariateFunction f = new Sin();
final FastFourierTransformer fft;
fft = new FastFourierTransformer(Normalization.UNITARY);
fft.inverseTransform(f, 0.0, Math.PI, n);
}
@Test(expected = NotStrictlyPositiveException.class)
public void testUnitaryInverseTransformFunctionNotStrictlyPositiveNumberOfSamples() {
final int n = -128;
final UnivariateFunction f = new Sin();
final FastFourierTransformer fft;
fft = new FastFourierTransformer(Normalization.UNITARY);
fft.inverseTransform(f, 0.0, Math.PI, n);
}
@Test(expected = NumberIsTooLargeException.class)
public void testUnitaryInverseTransformFunctionInvalidBounds() {
final int n = 128;
final UnivariateFunction f = new Sin();
final FastFourierTransformer fft;
fft = new FastFourierTransformer(Normalization.UNITARY);
fft.transform(f, Math.PI, 0.0, n);
final FastFourierTransformer.DftNormalization[] norm;
norm = FastFourierTransformer.DftNormalization.values();
final TransformType[] type;
type = TransformType.values();
for (int i = 0; i < norm.length; i++) {
for (int j = 0; j < type.length; j++) {
final FastFourierTransformer fft;
fft = new FastFourierTransformer(norm[i]);
try {
fft.transform(f, Math.PI, 0.0, n, type[j]);
Assert.fail(norm[i] + ", " + type[j] +
": NumberIsTooLargeException was expected");
} catch (NumberIsTooLargeException e) {
// Expected behaviour
}
}
}
}
/*
@ -284,28 +216,32 @@ public final class FastFourierTransformerTest {
}
private static void doTestTransformComplex(final int n, final double tol,
final boolean forward, final boolean standard) {
final FastFourierTransformer.DftNormalization normalization,
final TransformType type) {
final FastFourierTransformer fft;
if (standard) {
fft = new FastFourierTransformer(Normalization.STANDARD);
} else {
fft = new FastFourierTransformer(Normalization.UNITARY);
}
fft = new FastFourierTransformer(normalization);
final Complex[] x = createComplexData(n);
final Complex[] expected;
final Complex[] actual;
final double s;
if (forward) {
if (type==TransformType.FORWARD) {
expected = dft(x, -1);
s = standard ? 1.0 : 1.0 / FastMath.sqrt(n);
actual = fft.transform(x);
if (normalization == FastFourierTransformer.DftNormalization.STANDARD){
s = 1.0;
} else {
s = 1.0 / FastMath.sqrt(n);
}
} else {
expected = dft(x, 1);
s = standard ? 1.0 / n : 1.0 / FastMath.sqrt(n);
actual = fft.inverseTransform(x);
if (normalization == FastFourierTransformer.DftNormalization.STANDARD) {
s = 1.0 / n;
} else {
s = 1.0 / FastMath.sqrt(n);
}
}
final Complex[] actual = fft.transform(x, type);
for (int i = 0; i < n; i++) {
final String msg = String.format("%d, %d", n, i);
final String msg;
msg = String.format("%s, %s, %d, %d", normalization, type, n, i);
final double re = s * expected[i].getReal();
Assert.assertEquals(msg, re, actual[i].getReal(),
tol * FastMath.abs(re));
@ -316,32 +252,36 @@ public final class FastFourierTransformerTest {
}
private static void doTestTransformReal(final int n, final double tol,
final boolean forward, final boolean standard) {
final FastFourierTransformer.DftNormalization normalization,
final TransformType type) {
final FastFourierTransformer fft;
if (standard) {
fft = new FastFourierTransformer(Normalization.STANDARD);
} else {
fft = new FastFourierTransformer(Normalization.UNITARY);
}
fft = new FastFourierTransformer(normalization);
final double[] x = createRealData(n);
final Complex[] xc = new Complex[n];
for (int i = 0; i < n; i++) {
xc[i] = new Complex(x[i], 0.0);
}
final Complex[] expected;
final Complex[] actual;
final double s;
if (forward) {
if (type == TransformType.FORWARD) {
expected = dft(xc, -1);
s = standard ? 1.0 : 1.0 / FastMath.sqrt(n);
actual = fft.transform(x);
if (normalization == FastFourierTransformer.DftNormalization.STANDARD) {
s = 1.0;
} else {
s = 1.0 / FastMath.sqrt(n);
}
} else {
expected = dft(xc, 1);
s = standard ? 1.0 / n : 1.0 / FastMath.sqrt(n);
actual = fft.inverseTransform(x);
if (normalization == FastFourierTransformer.DftNormalization.STANDARD) {
s = 1.0 / n;
} else {
s = 1.0 / FastMath.sqrt(n);
}
}
final Complex[] actual = fft.transform(x, type);
for (int i = 0; i < n; i++) {
final String msg = String.format("%d, %d", n, i);
final String msg;
msg = String.format("%s, %s, %d, %d", normalization, type, n, i);
final double re = s * expected[i].getReal();
Assert.assertEquals(msg, re, actual[i].getReal(),
tol * FastMath.abs(re));
@ -353,30 +293,33 @@ public final class FastFourierTransformerTest {
private static void doTestTransformFunction(final UnivariateFunction f,
final double min, final double max, int n, final double tol,
final boolean forward, final boolean standard) {
final FastFourierTransformer.DftNormalization normalization,
final TransformType type) {
final FastFourierTransformer fft;
if (standard) {
fft = new FastFourierTransformer(Normalization.STANDARD);
} else {
fft = new FastFourierTransformer(Normalization.UNITARY);
}
fft = new FastFourierTransformer(normalization);
final Complex[] x = new Complex[n];
for (int i = 0; i < n; i++) {
final double t = min + i * (max - min) / n;
x[i] = new Complex(f.value(t));
}
final Complex[] expected;
final Complex[] actual;
final double s;
if (forward) {
if (type == TransformType.FORWARD) {
expected = dft(x, -1);
s = standard ? 1.0 : 1.0 / FastMath.sqrt(n);
actual = fft.transform(f, min, max, n);
if (normalization == FastFourierTransformer.DftNormalization.STANDARD) {
s = 1.0;
} else {
s = 1.0 / FastMath.sqrt(n);
}
} else {
expected = dft(x, 1);
s = standard ? 1.0 / n : 1.0 / FastMath.sqrt(n);
actual = fft.inverseTransform(f, min, max, n);
if (normalization == FastFourierTransformer.DftNormalization.STANDARD) {
s = 1.0 / n;
} else {
s = 1.0 / FastMath.sqrt(n);
}
}
final Complex[] actual = fft.transform(f, min, max, n, type);
for (int i = 0; i < n; i++) {
final String msg = String.format("%d, %d", n, i);
final double re = s * expected[i].getReal();
@ -393,29 +336,41 @@ public final class FastFourierTransformerTest {
*/
@Test
public void testStandardTransformComplex() {
final boolean forward = true;
final boolean standard = true;
doTestTransformComplex(2, 1.0E-15, forward, standard);
doTestTransformComplex(4, 1.0E-14, forward, standard);
doTestTransformComplex(8, 1.0E-14, forward, standard);
doTestTransformComplex(16, 1.0E-13, forward, standard);
doTestTransformComplex(32, 1.0E-13, forward, standard);
doTestTransformComplex(64, 1.0E-12, forward, standard);
doTestTransformComplex(128, 1.0E-12, forward, standard);
public void testTransformComplex() {
final FastFourierTransformer.DftNormalization[] norm;
norm = FastFourierTransformer.DftNormalization.values();
final TransformType[] type;
type = TransformType.values();
for (int i = 0; i < norm.length; i++) {
for (int j = 0; j < type.length; j++) {
doTestTransformComplex(2, 1.0E-15, norm[i], type[j]);
doTestTransformComplex(4, 1.0E-14, norm[i], type[j]);
doTestTransformComplex(8, 1.0E-14, norm[i], type[j]);
doTestTransformComplex(16, 1.0E-13, norm[i], type[j]);
doTestTransformComplex(32, 1.0E-13, norm[i], type[j]);
doTestTransformComplex(64, 1.0E-12, norm[i], type[j]);
doTestTransformComplex(128, 1.0E-12, norm[i], type[j]);
}
}
}
@Test
public void testStandardTransformReal() {
final boolean forward = true;
final boolean standard = true;
doTestTransformReal(2, 1.0E-15, forward, standard);
doTestTransformReal(4, 1.0E-14, forward, standard);
doTestTransformReal(8, 1.0E-14, forward, standard);
doTestTransformReal(16, 1.0E-13, forward, standard);
doTestTransformReal(32, 1.0E-13, forward, standard);
doTestTransformReal(64, 1.0E-13, forward, standard);
doTestTransformReal(128, 1.0E-11, forward, standard);
final FastFourierTransformer.DftNormalization[] norm;
norm = FastFourierTransformer.DftNormalization.values();
final TransformType[] type;
type = TransformType.values();
for (int i = 0; i < norm.length; i++) {
for (int j = 0; j < type.length; j++) {
doTestTransformReal(2, 1.0E-15, norm[i], type[j]);
doTestTransformReal(4, 1.0E-14, norm[i], type[j]);
doTestTransformReal(8, 1.0E-14, norm[i], type[j]);
doTestTransformReal(16, 1.0E-13, norm[i], type[j]);
doTestTransformReal(32, 1.0E-13, norm[i], type[j]);
doTestTransformReal(64, 1.0E-13, norm[i], type[j]);
doTestTransformReal(128, 1.0E-11, norm[i], type[j]);
}
}
}
@Test
@ -423,145 +378,21 @@ public final class FastFourierTransformerTest {
final UnivariateFunction f = new Sinc();
final double min = -FastMath.PI;
final double max = FastMath.PI;
final boolean forward = true;
final boolean standard = true;
doTestTransformFunction(f, min, max, 2, 1.0E-15, forward, standard);
doTestTransformFunction(f, min, max, 4, 1.0E-14, forward, standard);
doTestTransformFunction(f, min, max, 8, 1.0E-14, forward, standard);
doTestTransformFunction(f, min, max, 16, 1.0E-13, forward, standard);
doTestTransformFunction(f, min, max, 32, 1.0E-13, forward, standard);
doTestTransformFunction(f, min, max, 64, 1.0E-12, forward, standard);
doTestTransformFunction(f, min, max, 128, 1.0E-11, forward, standard);
}
@Test
public void testStandardInverseTransformComplex() {
final boolean forward = false;
final boolean standard = true;
doTestTransformComplex(2, 1.0E-15, forward, standard);
doTestTransformComplex(4, 1.0E-14, forward, standard);
doTestTransformComplex(8, 1.0E-14, forward, standard);
doTestTransformComplex(16, 1.0E-13, forward, standard);
doTestTransformComplex(32, 1.0E-13, forward, standard);
doTestTransformComplex(64, 1.0E-12, forward, standard);
doTestTransformComplex(128, 1.0E-12, forward, standard);
}
@Test
public void testStandardInverseTransformReal() {
final boolean forward = false;
final boolean standard = true;
doTestTransformReal(2, 1.0E-15, forward, standard);
doTestTransformReal(4, 1.0E-14, forward, standard);
doTestTransformReal(8, 1.0E-14, forward, standard);
doTestTransformReal(16, 1.0E-13, forward, standard);
doTestTransformReal(32, 1.0E-13, forward, standard);
doTestTransformReal(64, 1.0E-12, forward, standard);
doTestTransformReal(128, 1.0E-11, forward, standard);
}
@Test
public void testStandardInverseTransformFunction() {
final UnivariateFunction f = new Sinc();
final double min = -FastMath.PI;
final double max = FastMath.PI;
final boolean forward = false;
final boolean standard = true;
doTestTransformFunction(f, min, max, 2, 1.0E-15, forward, standard);
doTestTransformFunction(f, min, max, 4, 1.0E-14, forward, standard);
doTestTransformFunction(f, min, max, 8, 1.0E-14, forward, standard);
doTestTransformFunction(f, min, max, 16, 1.0E-13, forward, standard);
doTestTransformFunction(f, min, max, 32, 1.0E-13, forward, standard);
doTestTransformFunction(f, min, max, 64, 1.0E-12, forward, standard);
doTestTransformFunction(f, min, max, 128, 1.0E-11, forward, standard);
}
/*
* Tests of unitary transform (when data is valid).
*/
@Test
public void testUnitaryTransformComplex() {
final boolean forward = true;
final boolean standard = false;
doTestTransformComplex(2, 1.0E-15, forward, standard);
doTestTransformComplex(4, 1.0E-14, forward, standard);
doTestTransformComplex(8, 1.0E-14, forward, standard);
doTestTransformComplex(16, 1.0E-13, forward, standard);
doTestTransformComplex(32, 1.0E-13, forward, standard);
doTestTransformComplex(64, 1.0E-12, forward, standard);
doTestTransformComplex(128, 1.0E-12, forward, standard);
}
@Test
public void testUnitaryTransformReal() {
final boolean forward = true;
final boolean standard = false;
doTestTransformReal(2, 1.0E-15, forward, standard);
doTestTransformReal(4, 1.0E-14, forward, standard);
doTestTransformReal(8, 1.0E-14, forward, standard);
doTestTransformReal(16, 1.0E-13, forward, standard);
doTestTransformReal(32, 1.0E-13, forward, standard);
doTestTransformReal(64, 1.0E-13, forward, standard);
doTestTransformReal(128, 1.0E-11, forward, standard);
}
@Test
public void testUnitaryTransformFunction() {
final UnivariateFunction f = new Sinc();
final double min = -FastMath.PI;
final double max = FastMath.PI;
final boolean forward = true;
final boolean standard = false;
doTestTransformFunction(f, min, max, 2, 1.0E-15, forward, standard);
doTestTransformFunction(f, min, max, 4, 1.0E-14, forward, standard);
doTestTransformFunction(f, min, max, 8, 1.0E-14, forward, standard);
doTestTransformFunction(f, min, max, 16, 1.0E-13, forward, standard);
doTestTransformFunction(f, min, max, 32, 1.0E-13, forward, standard);
doTestTransformFunction(f, min, max, 64, 1.0E-12, forward, standard);
doTestTransformFunction(f, min, max, 128, 1.0E-11, forward, standard);
}
@Test
public void testUnitaryInverseTransformComplex() {
final boolean forward = false;
final boolean standard = false;
doTestTransformComplex(2, 1.0E-14, forward, standard);
doTestTransformComplex(4, 1.0E-14, forward, standard);
doTestTransformComplex(8, 1.0E-14, forward, standard);
doTestTransformComplex(16, 1.0E-13, forward, standard);
doTestTransformComplex(32, 1.0E-13, forward, standard);
doTestTransformComplex(64, 1.0E-12, forward, standard);
doTestTransformComplex(128, 1.0E-12, forward, standard);
}
@Test
public void testUnitaryInverseTransformReal() {
final boolean forward = false;
final boolean standard = false;
doTestTransformReal(2, 1.0E-15, forward, standard);
doTestTransformReal(4, 1.0E-14, forward, standard);
doTestTransformReal(8, 1.0E-14, forward, standard);
doTestTransformReal(16, 1.0E-13, forward, standard);
doTestTransformReal(32, 1.0E-13, forward, standard);
doTestTransformReal(64, 1.0E-12, forward, standard);
doTestTransformReal(128, 1.0E-11, forward, standard);
}
@Test
public void testUnitaryInverseTransformFunction() {
final UnivariateFunction f = new Sinc();
final double min = -FastMath.PI;
final double max = FastMath.PI;
final boolean forward = false;
final boolean standard = false;
doTestTransformFunction(f, min, max, 2, 1.0E-15, forward, standard);
doTestTransformFunction(f, min, max, 4, 1.0E-14, forward, standard);
doTestTransformFunction(f, min, max, 8, 1.0E-14, forward, standard);
doTestTransformFunction(f, min, max, 16, 1.0E-13, forward, standard);
doTestTransformFunction(f, min, max, 32, 1.0E-13, forward, standard);
doTestTransformFunction(f, min, max, 64, 1.0E-12, forward, standard);
doTestTransformFunction(f, min, max, 128, 1.0E-11, forward, standard);
final FastFourierTransformer.DftNormalization[] norm;
norm = FastFourierTransformer.DftNormalization.values();
final TransformType[] type;
type = TransformType.values();
for (int i = 0; i < norm.length; i++) {
for (int j = 0; j < type.length; j++) {
doTestTransformFunction(f, min, max, 2, 1.0E-15, norm[i], type[j]);
doTestTransformFunction(f, min, max, 4, 1.0E-14, norm[i], type[j]);
doTestTransformFunction(f, min, max, 8, 1.0E-14, norm[i], type[j]);
doTestTransformFunction(f, min, max, 16, 1.0E-13, norm[i], type[j]);
doTestTransformFunction(f, min, max, 32, 1.0E-13, norm[i], type[j]);
doTestTransformFunction(f, min, max, 64, 1.0E-12, norm[i], type[j]);
doTestTransformFunction(f, min, max, 128, 1.0E-11, norm[i], type[j]);
}
}
}
/*
@ -574,7 +405,7 @@ public final class FastFourierTransformerTest {
@Test
public void testAdHocData() {
FastFourierTransformer transformer;
transformer = new FastFourierTransformer(Normalization.STANDARD);
transformer = new FastFourierTransformer(DftNormalization.STANDARD);
Complex result[]; double tolerance = 1E-12;
double x[] = {1.3, 2.4, 1.7, 4.1, 2.9, 1.7, 5.1, 2.7};
@ -588,13 +419,13 @@ public final class FastFourierTransformerTest {
new Complex(-2.6, -2.7),
new Complex(-2.09497474683058, -1.91507575950825)};
result = transformer.transform(x);
result = transformer.transform(x, TransformType.FORWARD);
for (int i = 0; i < result.length; i++) {
Assert.assertEquals(y[i].getReal(), result[i].getReal(), tolerance);
Assert.assertEquals(y[i].getImaginary(), result[i].getImaginary(), tolerance);
}
result = transformer.inverseTransform(y);
result = transformer.transform(y, TransformType.INVERSE);
for (int i = 0; i < result.length; i++) {
Assert.assertEquals(x[i], result[i].getReal(), tolerance);
Assert.assertEquals(0.0, result[i].getImaginary(), tolerance);
@ -604,14 +435,14 @@ public final class FastFourierTransformerTest {
TransformUtils.scaleArray(x2, 1.0 / FastMath.sqrt(x2.length));
Complex y2[] = y;
transformer = new FastFourierTransformer(Normalization.UNITARY);
result = transformer.transform(y2);
transformer = new FastFourierTransformer(DftNormalization.UNITARY);
result = transformer.transform(y2, TransformType.FORWARD);
for (int i = 0; i < result.length; i++) {
Assert.assertEquals(x2[i], result[i].getReal(), tolerance);
Assert.assertEquals(0.0, result[i].getImaginary(), tolerance);
}
result = transformer.inverseTransform(x2);
result = transformer.transform(x2, TransformType.INVERSE);
for (int i = 0; i < result.length; i++) {
Assert.assertEquals(y2[i].getReal(), result[i].getReal(), tolerance);
Assert.assertEquals(y2[i].getImaginary(), result[i].getImaginary(), tolerance);
@ -625,12 +456,12 @@ public final class FastFourierTransformerTest {
public void testSinFunction() {
UnivariateFunction f = new SinFunction();
FastFourierTransformer transformer;
transformer = new FastFourierTransformer(Normalization.STANDARD);
transformer = new FastFourierTransformer(DftNormalization.STANDARD);
Complex result[]; int N = 1 << 8;
double min, max, tolerance = 1E-12;
min = 0.0; max = 2.0 * FastMath.PI;
result = transformer.transform(f, min, max, N);
result = transformer.transform(f, min, max, N, TransformType.FORWARD);
Assert.assertEquals(0.0, result[1].getReal(), tolerance);
Assert.assertEquals(-(N >> 1), result[1].getImaginary(), tolerance);
Assert.assertEquals(0.0, result[N-1].getReal(), tolerance);
@ -641,7 +472,7 @@ public final class FastFourierTransformerTest {
}
min = -FastMath.PI; max = FastMath.PI;
result = transformer.inverseTransform(f, min, max, N);
result = transformer.transform(f, min, max, N, TransformType.INVERSE);
Assert.assertEquals(0.0, result[1].getReal(), tolerance);
Assert.assertEquals(-0.5, result[1].getImaginary(), tolerance);
Assert.assertEquals(0.0, result[N-1].getReal(), tolerance);
@ -659,7 +490,7 @@ public final class FastFourierTransformerTest {
@Test
public void test2DData() {
FastFourierTransformer transformer;
transformer = new FastFourierTransformer(Normalization.STANDARD);
transformer = new FastFourierTransformer(DftNormalization.STANDARD);
double tolerance = 1E-12;
Complex[][] input = new Complex[][] {new Complex[] {new Complex(1, 0),
@ -675,8 +506,8 @@ public final class FastFourierTransformerTest {
FastMath.sqrt(goodOutput[i].length) *
FastMath.sqrt(goodOutput.length));
}
Complex[][] output = (Complex[][])transformer.mdfft(input, true);
Complex[][] output2 = (Complex[][])transformer.mdfft(output, false);
Complex[][] output = (Complex[][])transformer.mdfft(input, TransformType.FORWARD);
Complex[][] output2 = (Complex[][])transformer.mdfft(output, TransformType.INVERSE);
Assert.assertEquals(input.length, output.length);
Assert.assertEquals(input.length, output2.length);
@ -687,6 +518,8 @@ public final class FastFourierTransformerTest {
for (int i = 0; i < input.length; i++) {
for (int j = 0; j < input[0].length; j++) {
System.out.println(i + ", " + j + ", " + input[i][j] + ", " +
goodOutput[i][j] + ", " + output[i][j] + ", ");
Assert.assertEquals(input[i][j].getImaginary(), output2[i][j].getImaginary(),
tolerance);
Assert.assertEquals(input[i][j].getReal(), output2[i][j].getReal(), tolerance);
@ -700,7 +533,7 @@ public final class FastFourierTransformerTest {
@Test
public void test2DDataUnitary() {
FastFourierTransformer transformer;
transformer = new FastFourierTransformer(Normalization.UNITARY);
transformer = new FastFourierTransformer(DftNormalization.UNITARY);
double tolerance = 1E-12;
Complex[][] input = new Complex[][] {new Complex[] {new Complex(1, 0),
new Complex(2, 0)},
@ -709,8 +542,8 @@ public final class FastFourierTransformerTest {
Complex[][] goodOutput = new Complex[][] {new Complex[] {new Complex(5,
1.5), new Complex(-1, -.5)}, new Complex[] {new Complex(-2,
-1.5), new Complex(0, .5)}};
Complex[][] output = (Complex[][])transformer.mdfft(input, true);
Complex[][] output2 = (Complex[][])transformer.mdfft(output, false);
Complex[][] output = (Complex[][])transformer.mdfft(input, TransformType.FORWARD);
Complex[][] output2 = (Complex[][])transformer.mdfft(output, TransformType.INVERSE);
Assert.assertEquals(input.length, output.length);
Assert.assertEquals(input.length, output2.length);