You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by er...@apache.org on 2021/05/23 03:00:03 UTC
[commons-math] 01/04: MATH-1582: Modularization.
This is an automated email from the ASF dual-hosted git repository.
erans pushed a commit to branch modularized_master
in repository https://gitbox.apache.org/repos/asf/commons-math.git
commit 92094a0993015cbdc2be1c0d6553b31ca76f4fe5
Author: Gilles Sadowski <gi...@gmail.com>
AuthorDate: Sun May 23 01:15:57 2021 +0200
MATH-1582: Modularization.
Code moved from "o.a.c.math4.legacy.transform" into a dedicated module.
---
.../math4/legacy/analysis/FunctionUtils.java | 37 --
.../legacy/transform/FastCosineTransformer.java | 183 ---------
.../legacy/transform/FastFourierTransformer.java | 416 -------------------
.../legacy/transform/FastSineTransformer.java | 182 --------
.../math4/legacy/transform/RealTransformer.java | 67 ---
.../math4/legacy/transform/TransformType.java | 30 --
.../math4/legacy/analysis/FunctionUtilsTest.java | 27 --
commons-math-transform/LICENCE | 457 +++++++++++++++++++++
commons-math-transform/NOTICE | 9 +
commons-math-transform/pom.xml | 82 ++++
.../commons/math4/transform/ComplexTransform.java | 66 +++
.../commons/math4}/transform/DctNormalization.java | 12 +-
.../commons/math4}/transform/DftNormalization.java | 4 +-
.../commons/math4}/transform/DstNormalization.java | 12 +-
.../math4/transform/FastCosineTransform.java | 186 +++++++++
.../math4/transform/FastFourierTransform.java | 397 ++++++++++++++++++
.../math4/transform/FastHadamardTransform.java | 149 ++++---
.../commons/math4/transform/FastSineTransform.java | 194 +++++++++
.../commons/math4/transform/RealTransform.java | 51 +++
.../math4/transform/TransformException.java | 52 +++
.../commons/math4}/transform/TransformUtils.java | 116 +++---
.../commons/math4}/transform/package-info.java | 7 +-
.../transform/FastCosineTransformerTest.java | 151 ++++---
.../transform/FastFourierTransformerTest.java | 325 +++++++--------
.../transform/FastHadamardTransformerTest.java | 42 +-
.../math4}/transform/FastSineTransformerTest.java | 160 ++++----
.../transform/RealTransformerAbstractTest.java | 184 ++++-----
.../math4/transform/TransformUtilsTest.java | 59 +++
pom.xml | 1 +
src/changes/changes.xml | 3 +
30 files changed, 2099 insertions(+), 1562 deletions(-)
diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/analysis/FunctionUtils.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/analysis/FunctionUtils.java
index 6f0e550..cd4ff48 100644
--- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/analysis/FunctionUtils.java
+++ b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/analysis/FunctionUtils.java
@@ -302,43 +302,6 @@ public class FunctionUtils {
};
}
- /**
- * Samples the specified univariate real function on the specified interval.
- * <p>
- * The interval is divided equally into {@code n} sections and sample points
- * are taken from {@code min} to {@code max - (max - min) / n}; therefore
- * {@code f} is not sampled at the upper bound {@code max}.</p>
- *
- * @param f Function to be sampled
- * @param min Lower bound of the interval (included).
- * @param max Upper bound of the interval (excluded).
- * @param n Number of sample points.
- * @return the array of samples.
- * @throws NumberIsTooLargeException if the lower bound {@code min} is
- * greater than, or equal to the upper bound {@code max}.
- * @throws NotStrictlyPositiveException if the number of sample points
- * {@code n} is negative.
- */
- public static double[] sample(UnivariateFunction f, double min, double max, int n)
- throws NumberIsTooLargeException, NotStrictlyPositiveException {
-
- if (n <= 0) {
- throw new NotStrictlyPositiveException(
- LocalizedFormats.NOT_POSITIVE_NUMBER_OF_SAMPLES,
- Integer.valueOf(n));
- }
- if (min >= max) {
- throw new NumberIsTooLargeException(min, max, false);
- }
-
- final double[] s = new double[n];
- final double h = (max - min) / n;
- for (int i = 0; i < n; i++) {
- s[i] = f.value(min + i * h);
- }
- return s;
- }
-
/** Convert regular functions to {@link UnivariateDifferentiableFunction}.
* <p>
* This method handle the case with one free parameter and several derivatives.
diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/transform/FastCosineTransformer.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/transform/FastCosineTransformer.java
deleted file mode 100644
index e95d5e4..0000000
--- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/transform/FastCosineTransformer.java
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * 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.math4.legacy.transform;
-
-import java.io.Serializable;
-
-import org.apache.commons.numbers.complex.Complex;
-import org.apache.commons.numbers.core.ArithmeticUtils;
-import org.apache.commons.math4.legacy.analysis.FunctionUtils;
-import org.apache.commons.math4.legacy.analysis.UnivariateFunction;
-import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException;
-import org.apache.commons.math4.legacy.exception.util.LocalizedFormats;
-import org.apache.commons.math4.legacy.util.FastMath;
-
-/**
- * Implements the Fast Cosine Transform for transformation of one-dimensional
- * real data sets. For reference, see James S. Walker, <em>Fast Fourier
- * Transforms</em>, chapter 3 (ISBN 0849371635).
- * <p>
- * There are several variants of the discrete cosine transform. The present
- * implementation corresponds to DCT-I, with various normalization conventions,
- * which are specified by the parameter {@link DctNormalization}.
- * <p>
- * DCT-I is equivalent to DFT of an <em>even extension</em> of the data series.
- * More precisely, if x<sub>0</sub>, …, x<sub>N-1</sub> is the data set
- * to be cosine transformed, the extended data set
- * x<sub>0</sub><sup>#</sup>, …, x<sub>2N-3</sub><sup>#</sup>
- * is defined as follows
- * <ul>
- * <li>x<sub>k</sub><sup>#</sup> = x<sub>k</sub> if 0 ≤ k < N,</li>
- * <li>x<sub>k</sub><sup>#</sup> = x<sub>2N-2-k</sub>
- * if N ≤ k < 2N - 2.</li>
- * </ul>
- * <p>
- * Then, the standard DCT-I y<sub>0</sub>, …, y<sub>N-1</sub> of the real
- * data set x<sub>0</sub>, …, x<sub>N-1</sub> is equal to <em>half</em>
- * of the N first elements of the DFT of the extended data set
- * x<sub>0</sub><sup>#</sup>, …, x<sub>2N-3</sub><sup>#</sup>
- * <br>
- * y<sub>n</sub> = (1 / 2) ∑<sub>k=0</sub><sup>2N-3</sup>
- * x<sub>k</sub><sup>#</sup> exp[-2πi nk / (2N - 2)]
- * k = 0, …, N-1.
- * <p>
- * The present implementation of the discrete cosine transform as a fast cosine
- * transform requires the length of the data set to be a power of two plus one
- * (N = 2<sup>n</sup> + 1). Besides, it implicitly assumes
- * that the sampled function is even.
- *
- * @since 1.2
- */
-public class FastCosineTransformer implements RealTransformer, Serializable {
-
- /** Serializable version identifier. */
- static final long serialVersionUID = 20120212L;
-
- /** The type of DCT to be performed. */
- private final DctNormalization normalization;
-
- /**
- * Creates a new instance of this class, with various normalization
- * conventions.
- *
- * @param normalization the type of normalization to be applied to the
- * transformed data
- */
- public FastCosineTransformer(final DctNormalization normalization) {
- this.normalization = normalization;
- }
-
- /**
- * {@inheritDoc}
- *
- * @throws MathIllegalArgumentException if the length of the data array is
- * not a power of two plus one
- */
- @Override
- public double[] transform(final double[] f, final TransformType type)
- throws MathIllegalArgumentException {
- if (type == TransformType.FORWARD) {
- if (normalization == DctNormalization.ORTHOGONAL_DCT_I) {
- final double s = FastMath.sqrt(2.0 / (f.length - 1));
- return TransformUtils.scaleArray(fct(f), s);
- }
- return fct(f);
- }
- final double s2 = 2.0 / (f.length - 1);
- final double s1;
- if (normalization == DctNormalization.ORTHOGONAL_DCT_I) {
- s1 = FastMath.sqrt(s2);
- } else {
- s1 = s2;
- }
- return TransformUtils.scaleArray(fct(f), s1);
- }
-
- /**
- * {@inheritDoc}
- *
- * @throws org.apache.commons.math4.legacy.exception.NonMonotonicSequenceException
- * if the lower bound is greater than, or equal to the upper bound
- * @throws org.apache.commons.math4.legacy.exception.NotStrictlyPositiveException
- * if the number of sample points is negative
- * @throws MathIllegalArgumentException if the number of sample points is
- * not a power of two plus one
- */
- @Override
- public double[] transform(final UnivariateFunction f,
- final double min, final double max, final int n,
- final TransformType type) throws MathIllegalArgumentException {
-
- final double[] data = FunctionUtils.sample(f, min, max, n);
- return transform(data, type);
- }
-
- /**
- * Perform the FCT algorithm (including inverse).
- *
- * @param f the real data array to be transformed
- * @return the real transformed array
- * @throws MathIllegalArgumentException if the length of the data array is
- * not a power of two plus one
- */
- protected double[] fct(double[] f)
- throws MathIllegalArgumentException {
-
- final double[] transformed = new double[f.length];
-
- final int n = f.length - 1;
- if (!ArithmeticUtils.isPowerOfTwo(n)) {
- throw new MathIllegalArgumentException(
- LocalizedFormats.NOT_POWER_OF_TWO_PLUS_ONE,
- Integer.valueOf(f.length));
- }
- if (n == 1) { // trivial case
- transformed[0] = 0.5 * (f[0] + f[1]);
- transformed[1] = 0.5 * (f[0] - f[1]);
- return transformed;
- }
-
- // construct a new array and perform FFT on it
- final double[] x = new double[n];
- x[0] = 0.5 * (f[0] + f[n]);
- x[n >> 1] = f[n >> 1];
- // temporary variable for transformed[1]
- double t1 = 0.5 * (f[0] - f[n]);
- for (int i = 1; i < (n >> 1); i++) {
- final double a = 0.5 * (f[i] + f[n - i]);
- final double b = FastMath.sin(i * FastMath.PI / n) * (f[i] - f[n - i]);
- final double c = FastMath.cos(i * FastMath.PI / n) * (f[i] - f[n - i]);
- x[i] = a - b;
- x[n - i] = a + b;
- t1 += c;
- }
- FastFourierTransformer transformer;
- 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();
- transformed[1] = t1;
- for (int i = 1; i < (n >> 1); i++) {
- transformed[2 * i] = y[i].getReal();
- transformed[2 * i + 1] = transformed[2 * i - 1] - y[i].getImaginary();
- }
- transformed[n] = y[n >> 1].getReal();
-
- return transformed;
- }
-}
diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/transform/FastFourierTransformer.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/transform/FastFourierTransformer.java
deleted file mode 100644
index 23d10c4..0000000
--- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/transform/FastFourierTransformer.java
+++ /dev/null
@@ -1,416 +0,0 @@
-/*
- * 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.math4.legacy.transform;
-
-import java.io.Serializable;
-import java.util.Arrays;
-import org.apache.commons.numbers.complex.Complex;
-import org.apache.commons.numbers.core.ArithmeticUtils;
-import org.apache.commons.math4.legacy.analysis.FunctionUtils;
-import org.apache.commons.math4.legacy.analysis.UnivariateFunction;
-import org.apache.commons.math4.legacy.exception.DimensionMismatchException;
-import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException;
-import org.apache.commons.math4.legacy.exception.MathIllegalStateException;
-import org.apache.commons.math4.legacy.exception.util.LocalizedFormats;
-import org.apache.commons.math4.legacy.util.FastMath;
-
-/**
- * Implements the Fast Fourier Transform for transformation of one-dimensional
- * real or complex data sets. For reference, see <em>Applied Numerical Linear
- * Algebra</em>, ISBN 0898713897, chapter 6.
- * <p>
- * There are several variants of the discrete Fourier transform, with various
- * normalization conventions, which are specified by the parameter
- * {@link DftNormalization}.
- * <p>
- * The current implementation of the discrete Fourier transform as a fast
- * Fourier transform requires the length of the data set to be a power of 2.
- * This greatly simplifies and speeds up the code. Users can pad the data with
- * zeros to meet this requirement. There are other flavors of FFT, for
- * reference, see S. Winograd,
- * <i>On computing the discrete Fourier transform</i>, Mathematics of
- * Computation, 32 (1978), 175 - 199.
- *
- * @see DftNormalization
- * @since 1.2
- */
-public class FastFourierTransformer implements Serializable {
- /** Serializable version identifier. */
- static final long serialVersionUID = 20120210L;
-
- /**
- * {@code W_SUB_N_R[i]} is the real part of
- * {@code exp(- 2 * i * pi / n)}:
- * {@code W_SUB_N_R[i] = cos(2 * pi/ n)}, where {@code n = 2^i}.
- */
- private static final double[] W_SUB_N_R =
- { 0x1.0p0, -0x1.0p0, 0x1.1a62633145c07p-54, 0x1.6a09e667f3bcdp-1
- , 0x1.d906bcf328d46p-1, 0x1.f6297cff75cbp-1, 0x1.fd88da3d12526p-1, 0x1.ff621e3796d7ep-1
- , 0x1.ffd886084cd0dp-1, 0x1.fff62169b92dbp-1, 0x1.fffd8858e8a92p-1, 0x1.ffff621621d02p-1
- , 0x1.ffffd88586ee6p-1, 0x1.fffff62161a34p-1, 0x1.fffffd8858675p-1, 0x1.ffffff621619cp-1
- , 0x1.ffffffd885867p-1, 0x1.fffffff62161ap-1, 0x1.fffffffd88586p-1, 0x1.ffffffff62162p-1
- , 0x1.ffffffffd8858p-1, 0x1.fffffffff6216p-1, 0x1.fffffffffd886p-1, 0x1.ffffffffff621p-1
- , 0x1.ffffffffffd88p-1, 0x1.fffffffffff62p-1, 0x1.fffffffffffd9p-1, 0x1.ffffffffffff6p-1
- , 0x1.ffffffffffffep-1, 0x1.fffffffffffffp-1, 0x1.0p0, 0x1.0p0
- , 0x1.0p0, 0x1.0p0, 0x1.0p0, 0x1.0p0
- , 0x1.0p0, 0x1.0p0, 0x1.0p0, 0x1.0p0
- , 0x1.0p0, 0x1.0p0, 0x1.0p0, 0x1.0p0
- , 0x1.0p0, 0x1.0p0, 0x1.0p0, 0x1.0p0
- , 0x1.0p0, 0x1.0p0, 0x1.0p0, 0x1.0p0
- , 0x1.0p0, 0x1.0p0, 0x1.0p0, 0x1.0p0
- , 0x1.0p0, 0x1.0p0, 0x1.0p0, 0x1.0p0
- , 0x1.0p0, 0x1.0p0, 0x1.0p0 };
-
- /**
- * {@code W_SUB_N_I[i]} is the imaginary part of
- * {@code exp(- 2 * i * pi / n)}:
- * {@code W_SUB_N_I[i] = -sin(2 * pi/ n)}, where {@code n = 2^i}.
- */
- private static final double[] W_SUB_N_I =
- { 0x1.1a62633145c07p-52, -0x1.1a62633145c07p-53, -0x1.0p0, -0x1.6a09e667f3bccp-1
- , -0x1.87de2a6aea963p-2, -0x1.8f8b83c69a60ap-3, -0x1.917a6bc29b42cp-4, -0x1.91f65f10dd814p-5
- , -0x1.92155f7a3667ep-6, -0x1.921d1fcdec784p-7, -0x1.921f0fe670071p-8, -0x1.921f8becca4bap-9
- , -0x1.921faaee6472dp-10, -0x1.921fb2aecb36p-11, -0x1.921fb49ee4ea6p-12, -0x1.921fb51aeb57bp-13
- , -0x1.921fb539ecf31p-14, -0x1.921fb541ad59ep-15, -0x1.921fb5439d73ap-16, -0x1.921fb544197ap-17
- , -0x1.921fb544387bap-18, -0x1.921fb544403c1p-19, -0x1.921fb544422c2p-20, -0x1.921fb54442a83p-21
- , -0x1.921fb54442c73p-22, -0x1.921fb54442cefp-23, -0x1.921fb54442d0ep-24, -0x1.921fb54442d15p-25
- , -0x1.921fb54442d17p-26, -0x1.921fb54442d18p-27, -0x1.921fb54442d18p-28, -0x1.921fb54442d18p-29
- , -0x1.921fb54442d18p-30, -0x1.921fb54442d18p-31, -0x1.921fb54442d18p-32, -0x1.921fb54442d18p-33
- , -0x1.921fb54442d18p-34, -0x1.921fb54442d18p-35, -0x1.921fb54442d18p-36, -0x1.921fb54442d18p-37
- , -0x1.921fb54442d18p-38, -0x1.921fb54442d18p-39, -0x1.921fb54442d18p-40, -0x1.921fb54442d18p-41
- , -0x1.921fb54442d18p-42, -0x1.921fb54442d18p-43, -0x1.921fb54442d18p-44, -0x1.921fb54442d18p-45
- , -0x1.921fb54442d18p-46, -0x1.921fb54442d18p-47, -0x1.921fb54442d18p-48, -0x1.921fb54442d18p-49
- , -0x1.921fb54442d18p-50, -0x1.921fb54442d18p-51, -0x1.921fb54442d18p-52, -0x1.921fb54442d18p-53
- , -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 DftNormalization normalization;
-
- /**
- * Creates a new instance of this class, with various normalization
- * conventions.
- *
- * @param normalization the type of normalization to be applied to the
- * transformed data
- */
- public FastFourierTransformer(final DftNormalization normalization) {
- this.normalization = normalization;
- }
-
- /**
- * Performs identical index bit reversal shuffles on two arrays of identical
- * size. Each element in the array is swapped with another element based on
- * the bit-reversal of the index. For example, in an array with length 16,
- * item at binary index 0011 (decimal 3) would be swapped with the item at
- * binary index 1100 (decimal 12).
- *
- * @param a the first array to be shuffled
- * @param b the second array to be shuffled
- */
- private static void bitReversalShuffle2(double[] a, double[] b) {
- final int n = a.length;
- assert b.length == n;
- final int halfOfN = n >> 1;
-
- int j = 0;
- for (int i = 0; i < n; i++) {
- if (i < j) {
- // swap indices i & j
- double temp = a[i];
- a[i] = a[j];
- a[j] = temp;
-
- temp = b[i];
- b[i] = b[j];
- b[j] = temp;
- }
-
- int k = halfOfN;
- while (k <= j && k > 0) {
- j -= k;
- k >>= 1;
- }
- j += k;
- }
- }
-
- /**
- * Applies the proper normalization to the specified transformed data.
- *
- * @param dataRI the unscaled transformed data
- * @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 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 (normalization) {
- case STANDARD:
- if (type == TransformType.INVERSE) {
- final double scaleFactor = 1.0 / ((double) n);
- for (int i = 0; i < n; i++) {
- dataR[i] *= scaleFactor;
- dataI[i] *= scaleFactor;
- }
- }
- break;
- case UNITARY:
- final double scaleFactor = 1.0 / FastMath.sqrt(n);
- for (int i = 0; i < n; i++) {
- dataR[i] *= scaleFactor;
- dataI[i] *= scaleFactor;
- }
- break;
- default:
- /*
- * This should never occur in normal conditions. However this
- * clause has been added as a safeguard if other types of
- * normalizations are ever implemented, and the corresponding
- * test is forgotten in the present switch.
- */
- throw new MathIllegalStateException();
- }
- }
-
- /**
- * Computes the standard transform of the specified complex data. The
- * computation is done in place. The input data is laid out as follows
- * <ul>
- * <li>{@code dataRI[0][i]} is the real part of the {@code i}-th data point,</li>
- * <li>{@code dataRI[1][i]} is the imaginary part of the {@code i}-th data point.</li>
- * </ul>
- *
- * @param dataRI the two dimensional array of real and imaginary parts of the data
- * @param normalization the normalization to be applied to the transformed data
- * @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 DftNormalization normalization, final TransformType type) {
-
- if (dataRI.length != 2) {
- throw new DimensionMismatchException(dataRI.length, 2);
- }
- final double[] dataR = dataRI[0];
- final double[] dataI = dataRI[1];
- if (dataR.length != dataI.length) {
- throw new DimensionMismatchException(dataI.length, dataR.length);
- }
-
- final int n = dataR.length;
- if (!ArithmeticUtils.isPowerOfTwo(n)) {
- throw new MathIllegalArgumentException(
- LocalizedFormats.NOT_POWER_OF_TWO_CONSIDER_PADDING,
- Integer.valueOf(n));
- }
-
- if (n == 1) {
- return;
- } else if (n == 2) {
- final double srcR0 = dataR[0];
- final double srcI0 = dataI[0];
- final double srcR1 = dataR[1];
- final double srcI1 = dataI[1];
-
- // X_0 = x_0 + x_1
- dataR[0] = srcR0 + srcR1;
- dataI[0] = srcI0 + srcI1;
- // X_1 = x_0 - x_1
- dataR[1] = srcR0 - srcR1;
- dataI[1] = srcI0 - srcI1;
-
- normalizeTransformedData(dataRI, normalization, type);
- return;
- }
-
- bitReversalShuffle2(dataR, dataI);
-
- // Do 4-term DFT.
- if (type == TransformType.INVERSE) {
- for (int i0 = 0; i0 < n; i0 += 4) {
- final int i1 = i0 + 1;
- final int i2 = i0 + 2;
- final int i3 = i0 + 3;
-
- final double srcR0 = dataR[i0];
- final double srcI0 = dataI[i0];
- final double srcR1 = dataR[i2];
- final double srcI1 = dataI[i2];
- final double srcR2 = dataR[i1];
- final double srcI2 = dataI[i1];
- final double srcR3 = dataR[i3];
- final double srcI3 = dataI[i3];
-
- // 4-term DFT
- // X_0 = x_0 + x_1 + x_2 + x_3
- dataR[i0] = srcR0 + srcR1 + srcR2 + srcR3;
- dataI[i0] = srcI0 + srcI1 + srcI2 + srcI3;
- // X_1 = x_0 - x_2 + j * (x_3 - x_1)
- dataR[i1] = srcR0 - srcR2 + (srcI3 - srcI1);
- dataI[i1] = srcI0 - srcI2 + (srcR1 - srcR3);
- // X_2 = x_0 - x_1 + x_2 - x_3
- dataR[i2] = srcR0 - srcR1 + srcR2 - srcR3;
- dataI[i2] = srcI0 - srcI1 + srcI2 - srcI3;
- // X_3 = x_0 - x_2 + j * (x_1 - x_3)
- dataR[i3] = srcR0 - srcR2 + (srcI1 - srcI3);
- dataI[i3] = srcI0 - srcI2 + (srcR3 - srcR1);
- }
- } else {
- for (int i0 = 0; i0 < n; i0 += 4) {
- final int i1 = i0 + 1;
- final int i2 = i0 + 2;
- final int i3 = i0 + 3;
-
- final double srcR0 = dataR[i0];
- final double srcI0 = dataI[i0];
- final double srcR1 = dataR[i2];
- final double srcI1 = dataI[i2];
- final double srcR2 = dataR[i1];
- final double srcI2 = dataI[i1];
- final double srcR3 = dataR[i3];
- final double srcI3 = dataI[i3];
-
- // 4-term DFT
- // X_0 = x_0 + x_1 + x_2 + x_3
- dataR[i0] = srcR0 + srcR1 + srcR2 + srcR3;
- dataI[i0] = srcI0 + srcI1 + srcI2 + srcI3;
- // X_1 = x_0 - x_2 + j * (x_3 - x_1)
- dataR[i1] = srcR0 - srcR2 + (srcI1 - srcI3);
- dataI[i1] = srcI0 - srcI2 + (srcR3 - srcR1);
- // X_2 = x_0 - x_1 + x_2 - x_3
- dataR[i2] = srcR0 - srcR1 + srcR2 - srcR3;
- dataI[i2] = srcI0 - srcI1 + srcI2 - srcI3;
- // X_3 = x_0 - x_2 + j * (x_1 - x_3)
- dataR[i3] = srcR0 - srcR2 + (srcI3 - srcI1);
- dataI[i3] = srcI0 - srcI2 + (srcR1 - srcR3);
- }
- }
-
- int lastN0 = 4;
- int lastLogN0 = 2;
- while (lastN0 < n) {
- int n0 = lastN0 << 1;
- int logN0 = lastLogN0 + 1;
- double wSubN0R = W_SUB_N_R[logN0];
- double wSubN0I = W_SUB_N_I[logN0];
- if (type == TransformType.INVERSE) {
- wSubN0I = -wSubN0I;
- }
-
- // Combine even/odd transforms of size lastN0 into a transform of size N0 (lastN0 * 2).
- for (int destEvenStartIndex = 0; destEvenStartIndex < n; destEvenStartIndex += n0) {
- int destOddStartIndex = destEvenStartIndex + lastN0;
-
- double wSubN0ToRR = 1;
- double wSubN0ToRI = 0;
-
- for (int r = 0; r < lastN0; r++) {
- double grR = dataR[destEvenStartIndex + r];
- double grI = dataI[destEvenStartIndex + r];
- double hrR = dataR[destOddStartIndex + r];
- double hrI = dataI[destOddStartIndex + r];
-
- // dest[destEvenStartIndex + r] = Gr + WsubN0ToR * Hr
- dataR[destEvenStartIndex + r] = grR + wSubN0ToRR * hrR - wSubN0ToRI * hrI;
- dataI[destEvenStartIndex + r] = grI + wSubN0ToRR * hrI + wSubN0ToRI * hrR;
- // dest[destOddStartIndex + r] = Gr - WsubN0ToR * Hr
- dataR[destOddStartIndex + r] = grR - (wSubN0ToRR * hrR - wSubN0ToRI * hrI);
- dataI[destOddStartIndex + r] = grI - (wSubN0ToRR * hrI + wSubN0ToRI * hrR);
-
- // WsubN0ToR *= WsubN0R
- double nextWsubN0ToRR = wSubN0ToRR * wSubN0R - wSubN0ToRI * wSubN0I;
- double nextWsubN0ToRI = wSubN0ToRR * wSubN0I + wSubN0ToRI * wSubN0R;
- wSubN0ToRR = nextWsubN0ToRR;
- wSubN0ToRI = nextWsubN0ToRI;
- }
- }
-
- lastN0 = n0;
- lastLogN0 = logN0;
- }
-
- normalizeTransformedData(dataRI, normalization, type);
- }
-
- /**
- * 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(final double[] f, final TransformType type) {
- final double[][] dataRI = new double[][] {
- Arrays.copyOf(f, f.length), new double[f.length]
- };
-
- transformInPlace(dataRI, normalization, type);
-
- return TransformUtils.createComplexArray(dataRI);
- }
-
- /**
- * 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.math4.legacy.exception.NumberIsTooLargeException
- * if the lower bound is greater than, or equal to the upper bound
- * @throws org.apache.commons.math4.legacy.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[] 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, type);
- }
-
- /**
- * 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(final Complex[] f, final TransformType type) {
- final double[][] dataRI = TransformUtils.createRealImaginaryArray(f);
-
- transformInPlace(dataRI, normalization, type);
-
- return TransformUtils.createComplexArray(dataRI);
- }
-}
diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/transform/FastSineTransformer.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/transform/FastSineTransformer.java
deleted file mode 100644
index 09707a0..0000000
--- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/transform/FastSineTransformer.java
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * 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.math4.legacy.transform;
-
-import java.io.Serializable;
-
-import org.apache.commons.numbers.complex.Complex;
-import org.apache.commons.numbers.core.ArithmeticUtils;
-import org.apache.commons.math4.legacy.analysis.FunctionUtils;
-import org.apache.commons.math4.legacy.analysis.UnivariateFunction;
-import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException;
-import org.apache.commons.math4.legacy.exception.util.LocalizedFormats;
-import org.apache.commons.math4.legacy.util.FastMath;
-
-/**
- * Implements the Fast Sine Transform for transformation of one-dimensional real
- * data sets. For reference, see James S. Walker, <em>Fast Fourier
- * Transforms</em>, chapter 3 (ISBN 0849371635).
- * <p>
- * There are several variants of the discrete sine transform. The present
- * implementation corresponds to DST-I, with various normalization conventions,
- * which are specified by the parameter {@link DstNormalization}.
- * <strong>It should be noted that regardless to the convention, the first
- * element of the dataset to be transformed must be zero.</strong>
- * <p>
- * DST-I is equivalent to DFT of an <em>odd extension</em> of the data series.
- * More precisely, if x<sub>0</sub>, …, x<sub>N-1</sub> is the data set
- * to be sine transformed, the extended data set x<sub>0</sub><sup>#</sup>,
- * …, x<sub>2N-1</sub><sup>#</sup> is defined as follows
- * <ul>
- * <li>x<sub>0</sub><sup>#</sup> = x<sub>0</sub> = 0,</li>
- * <li>x<sub>k</sub><sup>#</sup> = x<sub>k</sub> if 1 ≤ k < N,</li>
- * <li>x<sub>N</sub><sup>#</sup> = 0,</li>
- * <li>x<sub>k</sub><sup>#</sup> = -x<sub>2N-k</sub> if N + 1 ≤ k <
- * 2N.</li>
- * </ul>
- * <p>
- * Then, the standard DST-I y<sub>0</sub>, …, y<sub>N-1</sub> of the real
- * data set x<sub>0</sub>, …, x<sub>N-1</sub> is equal to <em>half</em>
- * of i (the pure imaginary number) times the N first elements of the DFT of the
- * extended data set x<sub>0</sub><sup>#</sup>, …,
- * x<sub>2N-1</sub><sup>#</sup> <br>
- * y<sub>n</sub> = (i / 2) ∑<sub>k=0</sub><sup>2N-1</sup>
- * x<sub>k</sub><sup>#</sup> exp[-2πi nk / (2N)]
- * k = 0, …, N-1.
- * <p>
- * The present implementation of the discrete sine transform as a fast sine
- * transform requires the length of the data to be a power of two. Besides,
- * it implicitly assumes that the sampled function is odd. In particular, the
- * first element of the data set must be 0, which is enforced in
- * {@link #transform(UnivariateFunction, double, double, int, TransformType)},
- * after sampling.
- *
- * @since 1.2
- */
-public class FastSineTransformer implements RealTransformer, Serializable {
-
- /** Serializable version identifier. */
- static final long serialVersionUID = 20120211L;
-
- /** The type of DST to be performed. */
- private final DstNormalization normalization;
-
- /**
- * Creates a new instance of this class, with various normalization conventions.
- *
- * @param normalization the type of normalization to be applied to the transformed data
- */
- public FastSineTransformer(final DstNormalization normalization) {
- this.normalization = normalization;
- }
-
- /**
- * {@inheritDoc}
- *
- * The first element of the specified data set is required to be {@code 0}.
- *
- * @throws MathIllegalArgumentException if the length of the data array is
- * not a power of two, or the first element of the data array is not zero
- */
- @Override
- public double[] transform(final double[] f, final TransformType type) {
- if (normalization == DstNormalization.ORTHOGONAL_DST_I) {
- final double s = FastMath.sqrt(2.0 / f.length);
- return TransformUtils.scaleArray(fst(f), s);
- }
- if (type == TransformType.FORWARD) {
- return fst(f);
- }
- final double s = 2.0 / f.length;
- return TransformUtils.scaleArray(fst(f), s);
- }
-
- /**
- * {@inheritDoc}
- *
- * This implementation enforces {@code f(x) = 0.0} at {@code x = 0.0}.
- *
- * @throws org.apache.commons.math4.legacy.exception.NonMonotonicSequenceException
- * if the lower bound is greater than, or equal to the upper bound
- * @throws org.apache.commons.math4.legacy.exception.NotStrictlyPositiveException
- * if the number of sample points is negative
- * @throws MathIllegalArgumentException if the number of sample points is not a power of two
- */
- @Override
- public double[] 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);
- data[0] = 0.0;
- return transform(data, type);
- }
-
- /**
- * Perform the FST algorithm (including inverse). The first element of the
- * data set is required to be {@code 0}.
- *
- * @param f the real data array to be transformed
- * @return the real transformed array
- * @throws MathIllegalArgumentException if the length of the data array is
- * not a power of two, or the first element of the data array is not zero
- */
- protected double[] fst(double[] f) throws MathIllegalArgumentException {
-
- final double[] transformed = new double[f.length];
-
- if (!ArithmeticUtils.isPowerOfTwo(f.length)) {
- throw new MathIllegalArgumentException(
- LocalizedFormats.NOT_POWER_OF_TWO_CONSIDER_PADDING,
- Integer.valueOf(f.length));
- }
- if (f[0] != 0.0) {
- throw new MathIllegalArgumentException(
- LocalizedFormats.FIRST_ELEMENT_NOT_ZERO,
- Double.valueOf(f[0]));
- }
- final int n = f.length;
- if (n == 1) { // trivial case
- transformed[0] = 0.0;
- return transformed;
- }
-
- // construct a new array and perform FFT on it
- final double[] x = new double[n];
- x[0] = 0.0;
- x[n >> 1] = 2.0 * f[n >> 1];
- for (int i = 1; i < (n >> 1); i++) {
- final double a = FastMath.sin(i * FastMath.PI / n) * (f[i] + f[n - i]);
- final double b = 0.5 * (f[i] - f[n - i]);
- x[i] = a + b;
- x[n - i] = a - b;
- }
- FastFourierTransformer transformer;
- transformer = new FastFourierTransformer(DftNormalization.STANDARD);
- Complex[] y = transformer.transform(x, TransformType.FORWARD);
-
- // reconstruct the FST result for the original array
- transformed[0] = 0.0;
- transformed[1] = 0.5 * y[0].getReal();
- for (int i = 1; i < (n >> 1); i++) {
- transformed[2 * i] = -y[i].getImaginary();
- transformed[2 * i + 1] = y[i].getReal() + transformed[2 * i - 1];
- }
-
- return transformed;
- }
-}
diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/transform/RealTransformer.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/transform/RealTransformer.java
deleted file mode 100644
index 3009c77..0000000
--- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/transform/RealTransformer.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * 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.math4.legacy.transform;
-
-import org.apache.commons.math4.legacy.analysis.UnivariateFunction;
-import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException;
-import org.apache.commons.math4.legacy.exception.NonMonotonicSequenceException;
-import org.apache.commons.math4.legacy.exception.NotStrictlyPositiveException;
-
-/**
- * Interface for one-dimensional data sets transformations producing real results.
- * <p>
- * Such transforms include {@link FastSineTransformer sine transform},
- * {@link FastCosineTransformer cosine transform} or {@link
- * FastHadamardTransformer Hadamard transform}.
- *
- * @since 2.0
- */
-public interface RealTransformer {
-
- /**
- * Returns the (forward, inverse) transform of the specified real data set.
- *
- * @param f the real data array to be transformed (signal)
- * @param type the type of transform (forward, inverse) to be performed
- * @return the real transformed array (spectrum)
- * @throws MathIllegalArgumentException if the array cannot be transformed
- * with the given type (this may be for example due to array size, which is
- * constrained in some transforms)
- */
- double[] transform(double[] f, TransformType type) throws MathIllegalArgumentException;
-
- /**
- * 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 real transformed array
- * @throws NonMonotonicSequenceException if the lower bound is greater than, or equal to the upper bound
- * @throws NotStrictlyPositiveException if the number of sample points is negative
- * @throws MathIllegalArgumentException if the sample cannot be transformed
- * with the given type (this may be for example due to sample size, which is
- * constrained in some transforms)
- */
- double[] transform(UnivariateFunction f, double min, double max, int n,
- TransformType type)
- throws NonMonotonicSequenceException, NotStrictlyPositiveException, MathIllegalArgumentException;
-
-}
diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/transform/TransformType.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/transform/TransformType.java
deleted file mode 100644
index 9207cbb..0000000
--- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/transform/TransformType.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * 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.math4.legacy.transform;
-
-/**
- * This enumeration defines the type of transform which is to be computed.
- *
- * @since 3.0
- */
-public enum TransformType {
- /** The type to be specified for forward transforms. */
- FORWARD,
-
- /** The type to be specified for inverse transforms. */
- INVERSE;
-}
diff --git a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/analysis/FunctionUtilsTest.java b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/analysis/FunctionUtilsTest.java
index af69078..01ffeb0 100644
--- a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/analysis/FunctionUtilsTest.java
+++ b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/analysis/FunctionUtilsTest.java
@@ -208,33 +208,6 @@ public class FunctionUtilsTest {
}
}
- @Test(expected = NumberIsTooLargeException.class)
- public void testSampleWrongBounds(){
- FunctionUtils.sample(new Sin(), FastMath.PI, 0.0, 10);
- }
-
- @Test(expected = NotStrictlyPositiveException.class)
- public void testSampleNegativeNumberOfPoints(){
- FunctionUtils.sample(new Sin(), 0.0, FastMath.PI, -1);
- }
-
- @Test(expected = NotStrictlyPositiveException.class)
- public void testSampleNullNumberOfPoints(){
- FunctionUtils.sample(new Sin(), 0.0, FastMath.PI, 0);
- }
-
- @Test
- public void testSample() {
- final int n = 11;
- final double min = 0.0;
- final double max = FastMath.PI;
- final double[] actual = FunctionUtils.sample(new Sin(), min, max, n);
- for (int i = 0; i < n; i++) {
- final double x = min + (max - min) / n * i;
- Assert.assertEquals("x = " + x, FastMath.sin(x), actual[i], 0.0);
- }
- }
-
@Test
public void testToDifferentiableUnivariate() {
diff --git a/commons-math-transform/LICENCE b/commons-math-transform/LICENCE
new file mode 100644
index 0000000..d97b49a
--- /dev/null
+++ b/commons-math-transform/LICENCE
@@ -0,0 +1,457 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed 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.
+
+
+Apache Commons Math includes the following code provided to the ASF under the
+Apache License 2.0:
+
+ - The inverse error function implementation in the Erf class is based on CUDA
+ code developed by Mike Giles, Oxford-Man Institute of Quantitative Finance,
+ and published in GPU Computing Gems, volume 2, 2010 (grant received on
+ March 23th 2013)
+ - The LinearConstraint, LinearObjectiveFunction, LinearOptimizer,
+ RelationShip, SimplexSolver and SimplexTableau classes in package
+ org.apache.commons.math3.optimization.linear include software developed by
+ Benjamin McCann (http://www.benmccann.com) and distributed with
+ the following copyright: Copyright 2009 Google Inc. (grant received on
+ March 16th 2009)
+ - The class "org.apache.commons.math3.exception.util.LocalizedFormatsTest" which
+ is an adapted version of "OrekitMessagesTest" test class for the Orekit library
+ - The "org.apache.commons.math3.analysis.interpolation.HermiteInterpolator"
+ has been imported from the Orekit space flight dynamics library.
+
+===============================================================================
+
+
+
+APACHE COMMONS MATH DERIVATIVE WORKS:
+
+The Apache commons-math library includes a number of subcomponents
+whose implementation is derived from original sources written
+in C or Fortran. License terms of the original sources
+are reproduced below.
+
+===============================================================================
+For the lmder, lmpar and qrsolv Fortran routine from minpack and translated in
+the LevenbergMarquardtOptimizer class in package
+org.apache.commons.math3.optimization.general
+Original source copyright and license statement:
+
+Minpack Copyright Notice (1999) University of Chicago. All rights reserved
+
+Redistribution and use in source and binary forms, with or
+without modification, are permitted provided that the
+following conditions are met:
+
+1. Redistributions of source code must retain the above
+copyright notice, this list of conditions and the following
+disclaimer.
+
+2. Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following
+disclaimer in the documentation and/or other materials
+provided with the distribution.
+
+3. The end-user documentation included with the
+redistribution, if any, must include the following
+acknowledgment:
+
+ "This product includes software developed by the
+ University of Chicago, as Operator of Argonne National
+ Laboratory.
+
+Alternately, this acknowledgment may appear in the software
+itself, if and wherever such third-party acknowledgments
+normally appear.
+
+4. WARRANTY DISCLAIMER. THE SOFTWARE IS SUPPLIED "AS IS"
+WITHOUT WARRANTY OF ANY KIND. THE COPYRIGHT HOLDER, THE
+UNITED STATES, THE UNITED STATES DEPARTMENT OF ENERGY, AND
+THEIR EMPLOYEES: (1) DISCLAIM ANY WARRANTIES, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO ANY IMPLIED WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE
+OR NON-INFRINGEMENT, (2) DO NOT ASSUME ANY LEGAL LIABILITY
+OR RESPONSIBILITY FOR THE ACCURACY, COMPLETENESS, OR
+USEFULNESS OF THE SOFTWARE, (3) DO NOT REPRESENT THAT USE OF
+THE SOFTWARE WOULD NOT INFRINGE PRIVATELY OWNED RIGHTS, (4)
+DO NOT WARRANT THAT THE SOFTWARE WILL FUNCTION
+UNINTERRUPTED, THAT IT IS ERROR-FREE OR THAT ANY ERRORS WILL
+BE CORRECTED.
+
+5. LIMITATION OF LIABILITY. IN NO EVENT WILL THE COPYRIGHT
+HOLDER, THE UNITED STATES, THE UNITED STATES DEPARTMENT OF
+ENERGY, OR THEIR EMPLOYEES: BE LIABLE FOR ANY INDIRECT,
+INCIDENTAL, CONSEQUENTIAL, SPECIAL OR PUNITIVE DAMAGES OF
+ANY KIND OR NATURE, INCLUDING BUT NOT LIMITED TO LOSS OF
+PROFITS OR LOSS OF DATA, FOR ANY REASON WHATSOEVER, WHETHER
+SUCH LIABILITY IS ASSERTED ON THE BASIS OF CONTRACT, TORT
+(INCLUDING NEGLIGENCE OR STRICT LIABILITY), OR OTHERWISE,
+EVEN IF ANY OF SAID PARTIES HAS BEEN WARNED OF THE
+POSSIBILITY OF SUCH LOSS OR DAMAGES.
+===============================================================================
+
+Copyright and license statement for the odex Fortran routine developed by
+E. Hairer and G. Wanner and translated in GraggBulirschStoerIntegrator class
+in package org.apache.commons.math3.ode.nonstiff:
+
+
+Copyright (c) 2004, Ernst Hairer
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+- Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+===============================================================================
+
+Copyright and license statement for the original Mersenne twister C
+routines translated in MersenneTwister class in package
+org.apache.commons.math3.random:
+
+ Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. The names of its contributors may not be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+===============================================================================
+
+The initial code for shuffling an array (originally in class
+"org.apache.commons.math3.random.RandomDataGenerator", now replaced by
+a method in class "org.apache.commons.math3.util.MathArrays") was
+inspired from the algorithm description provided in
+"Algorithms", by Ian Craw and John Pulham (University of Aberdeen 1999).
+The textbook (containing a proof that the shuffle is uniformly random) is
+available here:
+ http://citeseerx.ist.psu.edu/viewdoc/download;?doi=10.1.1.173.1898&rep=rep1&type=pdf
+
+===============================================================================
+License statement for the direction numbers in the resource files for Sobol sequences.
+
+-----------------------------------------------------------------------------
+Licence pertaining to sobol.cc and the accompanying sets of direction numbers
+
+-----------------------------------------------------------------------------
+Copyright (c) 2008, Frances Y. Kuo and Stephen Joe
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the names of the copyright holders nor the names of the
+ University of New South Wales and the University of Waikato
+ and its contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+===============================================================================
+
+The initial commit of package "org.apache.commons.math3.ml.neuralnet" is
+an adapted version of code developed in the context of the Data Processing
+and Analysis Consortium (DPAC) of the "Gaia" project of the European Space
+Agency (ESA).
+===============================================================================
+
+The initial commit of the class "org.apache.commons.math3.special.BesselJ" is
+an adapted version of code translated from the netlib Fortran program, rjbesl
+http://www.netlib.org/specfun/rjbesl by R.J. Cody at Argonne National
+Laboratory (USA). There is no license or copyright statement included with the
+original Fortran sources.
+===============================================================================
+
+
+The BracketFinder (package org.apache.commons.math3.optimization.univariate)
+and PowellOptimizer (package org.apache.commons.math3.optimization.general)
+classes are based on the Python code in module "optimize.py" (version 0.5)
+developed by Travis E. Oliphant for the SciPy library (http://www.scipy.org/)
+Copyright © 2003-2009 SciPy Developers.
+
+SciPy license
+Copyright © 2001, 2002 Enthought, Inc.
+All rights reserved.
+
+Copyright © 2003-2013 SciPy Developers.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of Enthought nor the names of the SciPy Developers may
+ be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+===============================================================================
+
diff --git a/commons-math-transform/NOTICE b/commons-math-transform/NOTICE
new file mode 100644
index 0000000..587cd7f
--- /dev/null
+++ b/commons-math-transform/NOTICE
@@ -0,0 +1,9 @@
+Apache Commons Math
+Copyright 2001-2020 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+
+This product includes software developed for Orekit by
+CS Systèmes d'Information (http://www.c-s.fr/)
+Copyright 2010-2012 CS Systèmes d'Information
diff --git a/commons-math-transform/pom.xml b/commons-math-transform/pom.xml
new file mode 100644
index 0000000..632ab2c
--- /dev/null
+++ b/commons-math-transform/pom.xml
@@ -0,0 +1,82 @@
+<?xml version="1.0"?>
+<!--
+ 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.
+-->
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
+ xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-math-parent</artifactId>
+ <version>4.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>commons-math4-transform</artifactId>
+ <name>Transforms</name>
+
+ <description>Fourier, Sine, Cosine, Hadamard.</description>
+
+ <properties>
+ <!-- The Java Module System Name -->
+ <commons.module.name>org.apache.commons.math4.transform</commons.module.name>
+ <!-- This value must reflect the current name of the base package. -->
+ <commons.osgi.symbolicName>org.apache.commons.math4.transform</commons.osgi.symbolicName>
+ <!-- OSGi -->
+ <commons.osgi.export>org.apache.commons.math4.transform</commons.osgi.export>
+ <!-- Workaround to avoid duplicating config files. -->
+ <math.parent.dir>${basedir}/..</math.parent.dir>
+ </properties>
+
+ <dependencies>
+
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-numbers-core</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-numbers-complex</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-rng-simple</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-math3</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <rerunFailingTestsCount>3</rerunFailingTestsCount>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/commons-math-transform/src/main/java/org/apache/commons/math4/transform/ComplexTransform.java b/commons-math-transform/src/main/java/org/apache/commons/math4/transform/ComplexTransform.java
new file mode 100644
index 0000000..68697da
--- /dev/null
+++ b/commons-math-transform/src/main/java/org/apache/commons/math4/transform/ComplexTransform.java
@@ -0,0 +1,66 @@
+/*
+ * 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.math4.transform;
+
+import java.util.function.DoubleUnaryOperator;
+import java.util.function.UnaryOperator;
+
+import org.apache.commons.numbers.complex.Complex;
+
+/**
+ * {@link Complex} transform.
+ * <p>
+ * Such transforms include {@link FastSineTransform sine transform},
+ * {@link FastCosineTransform cosine transform} or {@link
+ * FastHadamardTransform Hadamard transform}.
+ */
+public interface ComplexTransform extends UnaryOperator<Complex[]> {
+ /**
+ * Returns the transform of the specified data set.
+ *
+ * @param f the data array to be transformed (signal).
+ * @return the transformed array (spectrum).
+ * @throws IllegalArgumentException if the transform cannot be performed.
+ */
+ Complex[] apply(Complex[] f);
+
+ /**
+ * Returns the transform of the specified data set.
+ *
+ * @param f the data array to be transformed (signal).
+ * @return the transformed array (spectrum).
+ * @throws IllegalArgumentException if the transform cannot be performed.
+ */
+ Complex[] apply(double[] f);
+
+ /**
+ * Returns the transform of the specified function.
+ *
+ * @param f Function to be sampled and transformed.
+ * @param min Lower bound (inclusive) of the interval.
+ * @param max Upper bound (exclusive) of the interval.
+ * @param n Number of sample points.
+ * @return the result.
+ * @throws IllegalArgumentException if the transform cannot be performed.
+ */
+ default Complex[] apply(DoubleUnaryOperator f,
+ double min,
+ double max,
+ int n) {
+ return apply(TransformUtils.sample(f, min, max, n));
+ }
+}
diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/transform/DctNormalization.java b/commons-math-transform/src/main/java/org/apache/commons/math4/transform/DctNormalization.java
similarity index 91%
rename from commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/transform/DctNormalization.java
rename to commons-math-transform/src/main/java/org/apache/commons/math4/transform/DctNormalization.java
index cddc688..fa77fae 100644
--- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/transform/DctNormalization.java
+++ b/commons-math-transform/src/main/java/org/apache/commons/math4/transform/DctNormalization.java
@@ -14,19 +14,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.commons.math4.legacy.transform;
+package org.apache.commons.math4.transform;
/**
* This enumeration defines the various types of normalizations that can be
- * applied to discrete cosine transforms (DCT). The exact definition of these
- * normalizations is detailed below.
- *
- * @see FastCosineTransformer
- * @since 3.0
+ * applied to discrete cosine transforms (DCT).
*/
public enum DctNormalization {
/**
- * Should be passed to the constructor of {@link FastCosineTransformer}
+ * Should be passed to the constructor of {@link FastCosineTransform}
* to use the <em>standard</em> normalization convention. The standard
* DCT-I normalization convention is defined as follows
* <ul>
@@ -45,7 +41,7 @@ public enum DctNormalization {
STANDARD_DCT_I,
/**
- * Should be passed to the constructor of {@link FastCosineTransformer}
+ * Should be passed to the constructor of {@link FastCosineTransform}
* to use the <em>orthogonal</em> normalization convention. The orthogonal
* DCT-I normalization convention is defined as follows
* <ul>
diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/transform/DftNormalization.java b/commons-math-transform/src/main/java/org/apache/commons/math4/transform/DftNormalization.java
similarity index 96%
rename from commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/transform/DftNormalization.java
rename to commons-math-transform/src/main/java/org/apache/commons/math4/transform/DftNormalization.java
index 695feb9..1198860 100644
--- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/transform/DftNormalization.java
+++ b/commons-math-transform/src/main/java/org/apache/commons/math4/transform/DftNormalization.java
@@ -14,14 +14,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.commons.math4.legacy.transform;
+package org.apache.commons.math4.transform;
/**
* This enumeration defines the various types of normalizations that can be
* applied to discrete Fourier transforms (DFT). The exact definition of these
* normalizations is detailed below.
*
- * @see FastFourierTransformer
+ * @see FastFourierTransform
* @since 3.0
*/
public enum DftNormalization {
diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/transform/DstNormalization.java b/commons-math-transform/src/main/java/org/apache/commons/math4/transform/DstNormalization.java
similarity index 90%
rename from commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/transform/DstNormalization.java
rename to commons-math-transform/src/main/java/org/apache/commons/math4/transform/DstNormalization.java
index e8dcab7..4e9ab03 100644
--- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/transform/DstNormalization.java
+++ b/commons-math-transform/src/main/java/org/apache/commons/math4/transform/DstNormalization.java
@@ -14,19 +14,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.commons.math4.legacy.transform;
+package org.apache.commons.math4.transform;
/**
* This enumeration defines the various types of normalizations that can be
- * applied to discrete sine transforms (DST). The exact definition of these
- * normalizations is detailed below.
- *
- * @see FastSineTransformer
- * @since 3.0
+ * applied to discrete sine transforms (DST).
*/
public enum DstNormalization {
/**
- * Should be passed to the constructor of {@link FastSineTransformer} to
+ * Should be passed to the constructor of {@link FastSineTransform} to
* use the <em>standard</em> normalization convention. The standard DST-I
* normalization convention is defined as follows
* <ul>
@@ -40,7 +36,7 @@ public enum DstNormalization {
STANDARD_DST_I,
/**
- * Should be passed to the constructor of {@link FastSineTransformer} to
+ * Should be passed to the constructor of {@link FastSineTransform} to
* use the <em>orthogonal</em> normalization convention. The orthogonal
* DCT-I normalization convention is defined as follows
* <ul>
diff --git a/commons-math-transform/src/main/java/org/apache/commons/math4/transform/FastCosineTransform.java b/commons-math-transform/src/main/java/org/apache/commons/math4/transform/FastCosineTransform.java
new file mode 100644
index 0000000..0aa2863
--- /dev/null
+++ b/commons-math-transform/src/main/java/org/apache/commons/math4/transform/FastCosineTransform.java
@@ -0,0 +1,186 @@
+/*
+ * 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.math4.transform;
+
+import java.util.function.UnaryOperator;
+import java.util.function.DoubleUnaryOperator;
+
+import org.apache.commons.numbers.complex.Complex;
+import org.apache.commons.numbers.core.ArithmeticUtils;
+
+/**
+ * Implements the Fast Cosine Transform for transformation of one-dimensional
+ * real data sets. For reference, see James S. Walker, <em>Fast Fourier
+ * Transforms</em>, chapter 3 (ISBN 0849371635).
+ * <p>
+ * There are several variants of the discrete cosine transform. The present
+ * implementation corresponds to DCT-I, with various normalization conventions,
+ * which are specified by the parameter {@link DctNormalization}.
+ * <p>
+ * DCT-I is equivalent to DFT of an <em>even extension</em> of the data series.
+ * More precisely, if x<sub>0</sub>, …, x<sub>N-1</sub> is the data set
+ * to be cosine transformed, the extended data set
+ * x<sub>0</sub><sup>#</sup>, …, x<sub>2N-3</sub><sup>#</sup>
+ * is defined as follows
+ * <ul>
+ * <li>x<sub>k</sub><sup>#</sup> = x<sub>k</sub> if 0 ≤ k < N,</li>
+ * <li>x<sub>k</sub><sup>#</sup> = x<sub>2N-2-k</sub>
+ * if N ≤ k < 2N - 2.</li>
+ * </ul>
+ * <p>
+ * Then, the standard DCT-I y<sub>0</sub>, …, y<sub>N-1</sub> of the real
+ * data set x<sub>0</sub>, …, x<sub>N-1</sub> is equal to <em>half</em>
+ * of the N first elements of the DFT of the extended data set
+ * x<sub>0</sub><sup>#</sup>, …, x<sub>2N-3</sub><sup>#</sup>
+ * <br>
+ * y<sub>n</sub> = (1 / 2) ∑<sub>k=0</sub><sup>2N-3</sup>
+ * x<sub>k</sub><sup>#</sup> exp[-2πi nk / (2N - 2)]
+ * k = 0, …, N-1.
+ * <p>
+ * The present implementation of the discrete cosine transform as a fast cosine
+ * transform requires the length of the data set to be a power of two plus one
+ * (N = 2<sup>n</sup> + 1). Besides, it implicitly assumes
+ * that the sampled function is even.
+ */
+public class FastCosineTransform implements RealTransform {
+ /** Operation to be performed. */
+ private final UnaryOperator<double[]> op;
+
+ /**
+ * @param normalization Normalization to be applied to the
+ * transformed data.
+ * @param inverse Whether to perform the inverse transform.
+ */
+ public FastCosineTransform(final DctNormalization normalization,
+ final boolean inverse) {
+ op = create(normalization, inverse);
+ }
+
+ /**
+ * @param normalization Normalization to be applied to the
+ * transformed data.
+ */
+ public FastCosineTransform(final DctNormalization normalization) {
+ this(normalization, false);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @throws IllegalArgumentException if the length of the data array is
+ * not a power of two plus one.
+ */
+ @Override
+ public double[] apply(final double[] f) {
+ return op.apply(f);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @throws IllegalArgumentException if the number of sample points is
+ * not a power of two plus one, if the lower bound is greater than or
+ * equal to the upper bound, if the number of sample points is negative.
+ */
+ @Override
+ public double[] apply(final DoubleUnaryOperator f,
+ final double min,
+ final double max,
+ final int n) {
+ return apply(TransformUtils.sample(f, min, max, n));
+ }
+
+ /**
+ * Perform the FCT algorithm (including inverse).
+ *
+ * @param f Data to be transformed.
+ * @return the transformed array.
+ * @throws IllegalArgumentException if the length of the data array is
+ * not a power of two plus one.
+ */
+ private double[] fct(double[] f) {
+ final double[] transformed = new double[f.length];
+
+ final int n = f.length - 1;
+ if (!ArithmeticUtils.isPowerOfTwo(n)) {
+ throw new TransformException(TransformException.NOT_POWER_OF_TWO_PLUS_ONE,
+ Integer.valueOf(f.length));
+ }
+ if (n == 1) { // trivial case
+ transformed[0] = 0.5 * (f[0] + f[1]);
+ transformed[1] = 0.5 * (f[0] - f[1]);
+ return transformed;
+ }
+
+ // construct a new array and perform FFT on it
+ final double[] x = new double[n];
+ x[0] = 0.5 * (f[0] + f[n]);
+ final int nShifted = n >> 1;
+ x[nShifted] = f[nShifted];
+ // temporary variable for transformed[1]
+ double t1 = 0.5 * (f[0] - f[n]);
+ final double piOverN = Math.PI / n;
+ for (int i = 1; i < nShifted; i++) {
+ final int nMi = n - i;
+ final double fi = f[i];
+ final double fnMi = f[nMi];
+ final double a = 0.5 * (fi + fnMi);
+ final double arg = i * piOverN;
+ final double b = Math.sin(arg) * (fi - fnMi);
+ final double c = Math.cos(arg) * (fi - fnMi);
+ x[i] = a - b;
+ x[nMi] = a + b;
+ t1 += c;
+ }
+ final FastFourierTransform transformer = new FastFourierTransform(DftNormalization.STANDARD,
+ false);
+ final Complex[] y = transformer.apply(x);
+
+ // reconstruct the FCT result for the original array
+ transformed[0] = y[0].getReal();
+ transformed[1] = t1;
+ for (int i = 1; i < nShifted; i++) {
+ final int i2 = 2 * i;
+ transformed[i2] = y[i].getReal();
+ transformed[i2 + 1] = transformed[i2 - 1] - y[i].getImaginary();
+ }
+ transformed[n] = y[nShifted].getReal();
+
+ return transformed;
+ }
+
+ /**
+ * Factory method.
+ *
+ * @param normalization Normalization to be applied to the
+ * transformed data.
+ * @param inverse Whether to perform the inverse transform.
+ * @return the transform operator.
+ */
+ private UnaryOperator<double[]> create(final DctNormalization normalization,
+ final boolean inverse) {
+ if (inverse) {
+ return normalization == DctNormalization.ORTHOGONAL_DCT_I ?
+ (f) -> TransformUtils.scaleInPlace(fct(f), Math.sqrt(2d / (f.length - 1))) :
+ (f) -> TransformUtils.scaleInPlace(fct(f), 2d / (f.length - 1));
+ } else {
+ return normalization == DctNormalization.ORTHOGONAL_DCT_I ?
+ (f) -> TransformUtils.scaleInPlace(fct(f), Math.sqrt(2d / (f.length - 1))) :
+ (f) -> fct(f);
+ }
+ }
+}
diff --git a/commons-math-transform/src/main/java/org/apache/commons/math4/transform/FastFourierTransform.java b/commons-math-transform/src/main/java/org/apache/commons/math4/transform/FastFourierTransform.java
new file mode 100644
index 0000000..be704af
--- /dev/null
+++ b/commons-math-transform/src/main/java/org/apache/commons/math4/transform/FastFourierTransform.java
@@ -0,0 +1,397 @@
+/*
+ * 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.math4.transform;
+
+import java.util.Arrays;
+import java.util.function.DoubleUnaryOperator;
+
+import org.apache.commons.numbers.core.ArithmeticUtils;
+import org.apache.commons.numbers.complex.Complex;
+
+/**
+ * Implements the Fast Fourier Transform for transformation of one-dimensional
+ * real or complex data sets. For reference, see <em>Applied Numerical Linear
+ * Algebra</em>, ISBN 0898713897, chapter 6.
+ * <p>
+ * There are several variants of the discrete Fourier transform, with various
+ * normalization conventions, which are specified by the parameter
+ * {@link DftNormalization}.
+ * <p>
+ * The current implementation of the discrete Fourier transform as a fast
+ * Fourier transform requires the length of the data set to be a power of 2.
+ * This greatly simplifies and speeds up the code. Users can pad the data with
+ * zeros to meet this requirement. There are other flavors of FFT, for
+ * reference, see S. Winograd,
+ * <i>On computing the discrete Fourier transform</i>, Mathematics of
+ * Computation, 32 (1978), 175 - 199.
+ *
+ * @see DftNormalization
+ */
+public class FastFourierTransform implements ComplexTransform {
+ /**
+ * {@code W_SUB_N_R[i]} is the real part of
+ * {@code exp(- 2 * i * pi / n)}:
+ * {@code W_SUB_N_R[i] = cos(2 * pi/ n)}, where {@code n = 2^i}.
+ */
+ private static final double[] W_SUB_N_R = {
+ 0x1.0p0, -0x1.0p0, 0x1.1a62633145c07p-54, 0x1.6a09e667f3bcdp-1,
+ 0x1.d906bcf328d46p-1, 0x1.f6297cff75cbp-1, 0x1.fd88da3d12526p-1, 0x1.ff621e3796d7ep-1,
+ 0x1.ffd886084cd0dp-1, 0x1.fff62169b92dbp-1, 0x1.fffd8858e8a92p-1, 0x1.ffff621621d02p-1,
+ 0x1.ffffd88586ee6p-1, 0x1.fffff62161a34p-1, 0x1.fffffd8858675p-1, 0x1.ffffff621619cp-1,
+ 0x1.ffffffd885867p-1, 0x1.fffffff62161ap-1, 0x1.fffffffd88586p-1, 0x1.ffffffff62162p-1,
+ 0x1.ffffffffd8858p-1, 0x1.fffffffff6216p-1, 0x1.fffffffffd886p-1, 0x1.ffffffffff621p-1,
+ 0x1.ffffffffffd88p-1, 0x1.fffffffffff62p-1, 0x1.fffffffffffd9p-1, 0x1.ffffffffffff6p-1,
+ 0x1.ffffffffffffep-1, 0x1.fffffffffffffp-1, 0x1.0p0, 0x1.0p0,
+ 0x1.0p0, 0x1.0p0, 0x1.0p0, 0x1.0p0,
+ 0x1.0p0, 0x1.0p0, 0x1.0p0, 0x1.0p0,
+ 0x1.0p0, 0x1.0p0, 0x1.0p0, 0x1.0p0,
+ 0x1.0p0, 0x1.0p0, 0x1.0p0, 0x1.0p0,
+ 0x1.0p0, 0x1.0p0, 0x1.0p0, 0x1.0p0,
+ 0x1.0p0, 0x1.0p0, 0x1.0p0, 0x1.0p0,
+ 0x1.0p0, 0x1.0p0, 0x1.0p0, 0x1.0p0,
+ 0x1.0p0, 0x1.0p0, 0x1.0p0 };
+
+ /**
+ * {@code W_SUB_N_I[i]} is the imaginary part of
+ * {@code exp(- 2 * i * pi / n)}:
+ * {@code W_SUB_N_I[i] = -sin(2 * pi/ n)}, where {@code n = 2^i}.
+ */
+ private static final double[] W_SUB_N_I = {
+ 0x1.1a62633145c07p-52, -0x1.1a62633145c07p-53, -0x1.0p0, -0x1.6a09e667f3bccp-1,
+ -0x1.87de2a6aea963p-2, -0x1.8f8b83c69a60ap-3, -0x1.917a6bc29b42cp-4, -0x1.91f65f10dd814p-5,
+ -0x1.92155f7a3667ep-6, -0x1.921d1fcdec784p-7, -0x1.921f0fe670071p-8, -0x1.921f8becca4bap-9,
+ -0x1.921faaee6472dp-10, -0x1.921fb2aecb36p-11, -0x1.921fb49ee4ea6p-12, -0x1.921fb51aeb57bp-13,
+ -0x1.921fb539ecf31p-14, -0x1.921fb541ad59ep-15, -0x1.921fb5439d73ap-16, -0x1.921fb544197ap-17,
+ -0x1.921fb544387bap-18, -0x1.921fb544403c1p-19, -0x1.921fb544422c2p-20, -0x1.921fb54442a83p-21,
+ -0x1.921fb54442c73p-22, -0x1.921fb54442cefp-23, -0x1.921fb54442d0ep-24, -0x1.921fb54442d15p-25,
+ -0x1.921fb54442d17p-26, -0x1.921fb54442d18p-27, -0x1.921fb54442d18p-28, -0x1.921fb54442d18p-29,
+ -0x1.921fb54442d18p-30, -0x1.921fb54442d18p-31, -0x1.921fb54442d18p-32, -0x1.921fb54442d18p-33,
+ -0x1.921fb54442d18p-34, -0x1.921fb54442d18p-35, -0x1.921fb54442d18p-36, -0x1.921fb54442d18p-37,
+ -0x1.921fb54442d18p-38, -0x1.921fb54442d18p-39, -0x1.921fb54442d18p-40, -0x1.921fb54442d18p-41,
+ -0x1.921fb54442d18p-42, -0x1.921fb54442d18p-43, -0x1.921fb54442d18p-44, -0x1.921fb54442d18p-45,
+ -0x1.921fb54442d18p-46, -0x1.921fb54442d18p-47, -0x1.921fb54442d18p-48, -0x1.921fb54442d18p-49,
+ -0x1.921fb54442d18p-50, -0x1.921fb54442d18p-51, -0x1.921fb54442d18p-52, -0x1.921fb54442d18p-53,
+ -0x1.921fb54442d18p-54, -0x1.921fb54442d18p-55, -0x1.921fb54442d18p-56, -0x1.921fb54442d18p-57,
+ -0x1.921fb54442d18p-58, -0x1.921fb54442d18p-59, -0x1.921fb54442d18p-60 };
+
+ /** Type of DFT. */
+ private final DftNormalization normalization;
+ /** Inverse or forward. */
+ private final boolean inverse;
+
+ /**
+ * @param normalization Normalization to be applied to the
+ * transformed data.
+ * @param inverse Whether to perform the inverse transform.
+ */
+ public FastFourierTransform(final DftNormalization normalization,
+ final boolean inverse) {
+ this.normalization = normalization;
+ this.inverse = inverse;
+ }
+
+ /**
+ * @param normalization Normalization to be applied to the
+ * transformed data.
+ */
+ public FastFourierTransform(final DftNormalization normalization) {
+ this(normalization, false);
+ }
+
+ /**
+ * Computes the standard transform of the data.
+ * Computation is done in place.
+ * Assumed layout of the input data:
+ * <ul>
+ * <li>{@code dataRI[0][i]}: Real part of the {@code i}-th data point,</li>
+ * <li>{@code dataRI[1][i]}: Imaginary part of the {@code i}-th data point.</li>
+ * </ul>
+ *
+ * @param dataRI Two-dimensional array of real and imaginary parts of the data.
+ * @throws IllegalArgumentException if the number of data points is not
+ * a power of two, if the number of rows of the specified array is not two,
+ * or the array is not rectangular.
+ */
+ public void transformInPlace(final double[][] dataRI) {
+ if (dataRI.length != 2) {
+ throw new TransformException(TransformException.SIZE_MISMATCH,
+ dataRI.length, 2);
+ }
+ final double[] dataR = dataRI[0];
+ final double[] dataI = dataRI[1];
+ if (dataR.length != dataI.length) {
+ throw new TransformException(TransformException.SIZE_MISMATCH,
+ dataI.length, dataR.length);
+ }
+
+ final int n = dataR.length;
+ if (!ArithmeticUtils.isPowerOfTwo(n)) {
+ throw new TransformException(TransformException.NOT_POWER_OF_TWO,
+ Integer.valueOf(n));
+ }
+
+ if (n == 1) {
+ return;
+ } else if (n == 2) {
+ final double srcR0 = dataR[0];
+ final double srcI0 = dataI[0];
+ final double srcR1 = dataR[1];
+ final double srcI1 = dataI[1];
+
+ // X_0 = x_0 + x_1
+ dataR[0] = srcR0 + srcR1;
+ dataI[0] = srcI0 + srcI1;
+ // X_1 = x_0 - x_1
+ dataR[1] = srcR0 - srcR1;
+ dataI[1] = srcI0 - srcI1;
+
+ normalizeTransformedData(dataRI);
+ return;
+ }
+
+ bitReversalShuffle2(dataR, dataI);
+
+ // Do 4-term DFT.
+ if (inverse) {
+ for (int i0 = 0; i0 < n; i0 += 4) {
+ final int i1 = i0 + 1;
+ final int i2 = i0 + 2;
+ final int i3 = i0 + 3;
+
+ final double srcR0 = dataR[i0];
+ final double srcI0 = dataI[i0];
+ final double srcR1 = dataR[i2];
+ final double srcI1 = dataI[i2];
+ final double srcR2 = dataR[i1];
+ final double srcI2 = dataI[i1];
+ final double srcR3 = dataR[i3];
+ final double srcI3 = dataI[i3];
+
+ // 4-term DFT
+ // X_0 = x_0 + x_1 + x_2 + x_3
+ dataR[i0] = srcR0 + srcR1 + srcR2 + srcR3;
+ dataI[i0] = srcI0 + srcI1 + srcI2 + srcI3;
+ // X_1 = x_0 - x_2 + j * (x_3 - x_1)
+ dataR[i1] = srcR0 - srcR2 + (srcI3 - srcI1);
+ dataI[i1] = srcI0 - srcI2 + (srcR1 - srcR3);
+ // X_2 = x_0 - x_1 + x_2 - x_3
+ dataR[i2] = srcR0 - srcR1 + srcR2 - srcR3;
+ dataI[i2] = srcI0 - srcI1 + srcI2 - srcI3;
+ // X_3 = x_0 - x_2 + j * (x_1 - x_3)
+ dataR[i3] = srcR0 - srcR2 + (srcI1 - srcI3);
+ dataI[i3] = srcI0 - srcI2 + (srcR3 - srcR1);
+ }
+ } else {
+ for (int i0 = 0; i0 < n; i0 += 4) {
+ final int i1 = i0 + 1;
+ final int i2 = i0 + 2;
+ final int i3 = i0 + 3;
+
+ final double srcR0 = dataR[i0];
+ final double srcI0 = dataI[i0];
+ final double srcR1 = dataR[i2];
+ final double srcI1 = dataI[i2];
+ final double srcR2 = dataR[i1];
+ final double srcI2 = dataI[i1];
+ final double srcR3 = dataR[i3];
+ final double srcI3 = dataI[i3];
+
+ // 4-term DFT
+ // X_0 = x_0 + x_1 + x_2 + x_3
+ dataR[i0] = srcR0 + srcR1 + srcR2 + srcR3;
+ dataI[i0] = srcI0 + srcI1 + srcI2 + srcI3;
+ // X_1 = x_0 - x_2 + j * (x_3 - x_1)
+ dataR[i1] = srcR0 - srcR2 + (srcI1 - srcI3);
+ dataI[i1] = srcI0 - srcI2 + (srcR3 - srcR1);
+ // X_2 = x_0 - x_1 + x_2 - x_3
+ dataR[i2] = srcR0 - srcR1 + srcR2 - srcR3;
+ dataI[i2] = srcI0 - srcI1 + srcI2 - srcI3;
+ // X_3 = x_0 - x_2 + j * (x_1 - x_3)
+ dataR[i3] = srcR0 - srcR2 + (srcI3 - srcI1);
+ dataI[i3] = srcI0 - srcI2 + (srcR1 - srcR3);
+ }
+ }
+
+ int lastN0 = 4;
+ int lastLogN0 = 2;
+ while (lastN0 < n) {
+ int n0 = lastN0 << 1;
+ int logN0 = lastLogN0 + 1;
+ double wSubN0R = W_SUB_N_R[logN0];
+ double wSubN0I = W_SUB_N_I[logN0];
+ if (inverse) {
+ wSubN0I = -wSubN0I;
+ }
+
+ // Combine even/odd transforms of size lastN0 into a transform of size N0 (lastN0 * 2).
+ for (int destEvenStartIndex = 0;
+ destEvenStartIndex < n;
+ destEvenStartIndex += n0) {
+ final int destOddStartIndex = destEvenStartIndex + lastN0;
+
+ double wSubN0ToRR = 1;
+ double wSubN0ToRI = 0;
+
+ for (int r = 0; r < lastN0; r++) {
+ final int destEvenStartIndexPlusR = destEvenStartIndex + r;
+ final int destOddStartIndexPlusR = destOddStartIndex + r;
+
+ final double grR = dataR[destEvenStartIndexPlusR];
+ final double grI = dataI[destEvenStartIndexPlusR];
+ final double hrR = dataR[destOddStartIndexPlusR];
+ final double hrI = dataI[destOddStartIndexPlusR];
+
+ // dest[destEvenStartIndex + r] = Gr + WsubN0ToR * Hr
+ dataR[destEvenStartIndexPlusR] = grR + wSubN0ToRR * hrR - wSubN0ToRI * hrI;
+ dataI[destEvenStartIndexPlusR] = grI + wSubN0ToRR * hrI + wSubN0ToRI * hrR;
+ // dest[destOddStartIndex + r] = Gr - WsubN0ToR * Hr
+ dataR[destOddStartIndexPlusR] = grR - (wSubN0ToRR * hrR - wSubN0ToRI * hrI);
+ dataI[destOddStartIndexPlusR] = grI - (wSubN0ToRR * hrI + wSubN0ToRI * hrR);
+
+ // WsubN0ToR *= WsubN0R
+ final double nextWsubN0ToRR = wSubN0ToRR * wSubN0R - wSubN0ToRI * wSubN0I;
+ final double nextWsubN0ToRI = wSubN0ToRR * wSubN0I + wSubN0ToRI * wSubN0R;
+ wSubN0ToRR = nextWsubN0ToRR;
+ wSubN0ToRI = nextWsubN0ToRI;
+ }
+ }
+
+ lastN0 = n0;
+ lastLogN0 = logN0;
+ }
+
+ normalizeTransformedData(dataRI);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @throws IllegalArgumentException if the length of the data array is not a power of two.
+ */
+ public Complex[] apply(final double[] f) {
+ final double[][] dataRI = new double[][] {
+ Arrays.copyOf(f, f.length),
+ new double[f.length]
+ };
+ transformInPlace(dataRI);
+ return TransformUtils.createComplex(dataRI);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @throws IllegalArgumentException if the number of sample points
+ * {@code n} is not a power of two, if the lower bound is greater than,
+ * or equal to the upper bound, if the number of sample points {@code n}
+ * is negative
+ */
+ @Override
+ public Complex[] apply(final DoubleUnaryOperator f,
+ final double min,
+ final double max,
+ final int n) {
+ return apply(TransformUtils.sample(f, min, max, n));
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @throws IllegalArgumentException if the length of the data array is
+ * not a power of two.
+ */
+ @Override
+ public Complex[] apply(final Complex[] f) {
+ final double[][] dataRI = TransformUtils.createRealImaginary(f);
+ transformInPlace(dataRI);
+ return TransformUtils.createComplex(dataRI);
+ }
+
+ /**
+ * Applies normalization to the transformed data.
+ *
+ * @param dataRI Unscaled transformed data.
+ */
+ private void normalizeTransformedData(final double[][] dataRI) {
+ final double[] dataR = dataRI[0];
+ final double[] dataI = dataRI[1];
+ final int n = dataR.length;
+
+ switch (normalization) {
+ case STANDARD:
+ if (inverse) {
+ final double scaleFactor = 1d / n;
+ for (int i = 0; i < n; i++) {
+ dataR[i] *= scaleFactor;
+ dataI[i] *= scaleFactor;
+ }
+ }
+
+ break;
+
+ case UNITARY:
+ final double scaleFactor = 1d / Math.sqrt(n);
+ for (int i = 0; i < n; i++) {
+ dataR[i] *= scaleFactor;
+ dataI[i] *= scaleFactor;
+ }
+
+ break;
+
+ default:
+ throw new IllegalStateException(); // Should never happen.
+ }
+ }
+
+ /**
+ * Performs identical index bit reversal shuffles on two arrays of
+ * identical size.
+ * Each element in the array is swapped with another element based
+ * on the bit-reversal of the index.
+ * For example, in an array with length 16, item at binary index 0011
+ * (decimal 3) would be swapped with the item at binary index 1100
+ * (decimal 12).
+ *
+ * @param a Array to be shuffled.
+ * @param b Array to be shuffled.
+ */
+ private static void bitReversalShuffle2(double[] a,
+ double[] b) {
+ final int n = a.length;
+ final int halfOfN = n >> 1;
+
+ int j = 0;
+ for (int i = 0; i < n; i++) {
+ if (i < j) {
+ // swap indices i & j
+ double temp = a[i];
+ a[i] = a[j];
+ a[j] = temp;
+
+ temp = b[i];
+ b[i] = b[j];
+ b[j] = temp;
+ }
+
+ int k = halfOfN;
+ while (k <= j && k > 0) {
+ j -= k;
+ k >>= 1;
+ }
+ j += k;
+ }
+ }
+}
diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/transform/FastHadamardTransformer.java b/commons-math-transform/src/main/java/org/apache/commons/math4/transform/FastHadamardTransform.java
similarity index 67%
rename from commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/transform/FastHadamardTransformer.java
rename to commons-math-transform/src/main/java/org/apache/commons/math4/transform/FastHadamardTransform.java
index 90a3aa8..ab37285 100644
--- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/transform/FastHadamardTransformer.java
+++ b/commons-math-transform/src/main/java/org/apache/commons/math4/transform/FastHadamardTransform.java
@@ -14,80 +14,66 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.commons.math4.legacy.transform;
+package org.apache.commons.math4.transform;
-import java.io.Serializable;
+import java.util.function.UnaryOperator;
-import org.apache.commons.math4.legacy.analysis.FunctionUtils;
-import org.apache.commons.math4.legacy.analysis.UnivariateFunction;
-import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException;
-import org.apache.commons.math4.legacy.exception.util.LocalizedFormats;
import org.apache.commons.numbers.core.ArithmeticUtils;
/**
- * 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.
+ * <a href="http://www.archive.chipcenter.com/dsp/DSP000517F1.html">Fast Hadamard Transform</a> (FHT).
* <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).
- *
- * @since 2.0
+ * The FHT can also transform integer vectors into integer vectors.
+ * However, this transform cannot be inverted directly, due to a scaling
+ * factor that may lead to rational results (for example, the inverse
+ * transform of integer vector (0, 1, 0, 1) is vector (1/2, -1/2, 0, 0).
*/
-public class FastHadamardTransformer implements RealTransformer, Serializable {
+public class FastHadamardTransform implements RealTransform {
+ /** Operation to be performed. */
+ private final UnaryOperator<double[]> op;
- /** Serializable version identifier. */
- static final long serialVersionUID = 20120211L;
+ /**
+ * Default constructor.
+ */
+ public FastHadamardTransform() {
+ this(false);
+ }
/**
- * {@inheritDoc}
- *
- * @throws MathIllegalArgumentException if the length of the data array is
- * not a power of two
+ * @param inverse Whether to perform the inverse transform.
*/
- @Override
- public double[] transform(final double[] f, final TransformType type) {
- if (type == TransformType.FORWARD) {
- return fht(f);
- }
- return TransformUtils.scaleArray(fht(f), 1.0 / f.length);
+ public FastHadamardTransform(final boolean inverse) {
+ op = create(inverse);
}
/**
* {@inheritDoc}
*
- * @throws org.apache.commons.math4.legacy.exception.NonMonotonicSequenceException
- * if the lower bound is greater than, or equal to the upper bound
- * @throws org.apache.commons.math4.legacy.exception.NotStrictlyPositiveException
- * if the number of sample points is negative
- * @throws MathIllegalArgumentException if the number of sample points is not a power of two
+ * @throws IllegalArgumentException if the length of the data array is
+ * not a power of two.
*/
@Override
- public double[] transform(final UnivariateFunction f,
- final double min, final double max, final int n,
- final TransformType type) {
-
- return transform(FunctionUtils.sample(f, min, max, n), type);
+ public double[] apply(final double[] f) {
+ return op.apply(f);
}
/**
- * Returns the forward transform of the specified integer data set.The
- * integer transform cannot be inverted directly, due to a scaling factor
- * which may lead to double results.
+ * Returns the forward transform of the given data set.
+ * The integer transform cannot be inverted directly, due to a scaling
+ * factor which may lead to double results.
*
- * @param f the integer data array to be transformed (signal)
- * @return the integer transformed array (spectrum)
- * @throws MathIllegalArgumentException if the length of the data array is not a power of two
+ * @param f Data array to be transformed (signal).
+ * @return the transformed array (spectrum).
+ * @throws IllegalArgumentException if the length of the data array is
+ * not a power of two.
*/
- public int[] transform(final int[] f) {
+ public int[] apply(final int[] f) {
return fht(f);
}
/**
- * The FHT (Fast Hadamard Transformation) which uses only subtraction and
- * addition. Requires {@code N * log2(N) = n * 2^n} additions.
+ * FHT uses only subtraction and addition.
+ * It requires {@code N * log2(N) = n * 2^n} additions.
*
* <h3>Short Table of manual calculation for N=8</h3>
* <ol>
@@ -180,7 +166,7 @@ public class FastHadamardTransformer implements RealTransformer, Serializable {
* of the previous column.</li>
* </ul>
* </li>
- * <li>The consputation of {@code D_top} and {@code D_bottom} are best
+ * <li>The computation of {@code D_top} and {@code D_bottom} are best
* understood with the above example (for {@code N = 8}).
* <li>The output vector {@code y} is now in the last column of
* {@code hadm}.</li>
@@ -223,25 +209,22 @@ public class FastHadamardTransformer implements RealTransformer, Serializable {
* </tbody>
* </table>
*
- * @param x the real data array to be transformed
- * @return the real transformed array, {@code y}
- * @throws MathIllegalArgumentException if the length of the data array is not a power of two
+ * @param x Data to be transformed.
+ * @return the transformed array.
+ * @throws IllegalArgumentException if the length of the data array is
+ * not a power of two.
*/
- protected double[] fht(double[] x) throws MathIllegalArgumentException {
-
- final int n = x.length;
+ private double[] fht(double[] x) {
+ final int n = x.length;
final int halfN = n / 2;
if (!ArithmeticUtils.isPowerOfTwo(n)) {
- throw new MathIllegalArgumentException(
- LocalizedFormats.NOT_POWER_OF_TWO,
- Integer.valueOf(n));
+ throw new TransformException(TransformException.NOT_POWER_OF_TWO,
+ n);
}
- /*
- * Instead of creating a matrix with p+1 columns and n rows, we use two
- * one dimension arrays which we are used in an alternating way.
- */
+ // Instead of creating a matrix with p+1 columns and n rows, we use two
+ // one dimension arrays which we are used in an alternating way.
double[] yPrevious = new double[n];
double[] yCurrent = x.clone();
@@ -267,38 +250,34 @@ public class FastHadamardTransformer implements RealTransformer, Serializable {
}
return yCurrent;
-
}
/**
- * Returns the forward transform of the specified integer data set. The FHT
- * (Fast Hadamard Transform) uses only subtraction and addition.
+ * Returns the forward transform of the specified integer data set.
+ * FHT only uses subtraction and addition.
*
- * @param x the integer data array to be transformed
- * @return the integer transformed array, {@code y}
- * @throws MathIllegalArgumentException if the length of the data array is not a power of two
+ * @param x Data to be transformed.
+ * @return the transformed array.
+ * @throws IllegalArgumentException if the length of the data array is
+ * not a power of two.
*/
- protected int[] fht(int[] x) throws MathIllegalArgumentException {
-
- final int n = x.length;
+ private int[] fht(int[] x) {
+ final int n = x.length;
final int halfN = n / 2;
if (!ArithmeticUtils.isPowerOfTwo(n)) {
- throw new MathIllegalArgumentException(
- LocalizedFormats.NOT_POWER_OF_TWO,
- Integer.valueOf(n));
+ throw new TransformException(TransformException.NOT_POWER_OF_TWO,
+ n);
}
- /*
- * Instead of creating a matrix with p+1 columns and n rows, we use two
- * one dimension arrays which we are used in an alternating way.
- */
+ // Instead of creating a matrix with p+1 columns and n rows, we use two
+ // one dimension arrays which we are used 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;
@@ -319,7 +298,19 @@ public class FastHadamardTransformer implements RealTransformer, Serializable {
// return the last computed output vector y
return yCurrent;
-
}
+ /**
+ * Factory method.
+ *
+ * @param inverse Whether to perform the inverse transform.
+ * @return the transform operator.
+ */
+ private UnaryOperator<double[]> create(final boolean inverse) {
+ if (inverse) {
+ return (f) -> TransformUtils.scaleInPlace(fht(f), 1d / f.length);
+ } else {
+ return (f) -> fht(f);
+ }
+ }
}
diff --git a/commons-math-transform/src/main/java/org/apache/commons/math4/transform/FastSineTransform.java b/commons-math-transform/src/main/java/org/apache/commons/math4/transform/FastSineTransform.java
new file mode 100644
index 0000000..da3c63b
--- /dev/null
+++ b/commons-math-transform/src/main/java/org/apache/commons/math4/transform/FastSineTransform.java
@@ -0,0 +1,194 @@
+/*
+ * 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.math4.transform;
+
+import java.util.function.UnaryOperator;
+import java.util.function.DoubleUnaryOperator;
+
+import org.apache.commons.numbers.complex.Complex;
+import org.apache.commons.numbers.core.ArithmeticUtils;
+
+/**
+ * Implements the Fast Sine Transform for transformation of one-dimensional real
+ * data sets. For reference, see James S. Walker, <em>Fast Fourier
+ * Transforms</em>, chapter 3 (ISBN 0849371635).
+ * <p>
+ * There are several variants of the discrete sine transform. The present
+ * implementation corresponds to DST-I, with various normalization conventions,
+ * which are specified by the parameter {@link DstNormalization}.
+ * <strong>It should be noted that regardless to the convention, the first
+ * element of the dataset to be transformed must be zero.</strong>
+ * <p>
+ * DST-I is equivalent to DFT of an <em>odd extension</em> of the data series.
+ * More precisely, if x<sub>0</sub>, …, x<sub>N-1</sub> is the data set
+ * to be sine transformed, the extended data set x<sub>0</sub><sup>#</sup>,
+ * …, x<sub>2N-1</sub><sup>#</sup> is defined as follows
+ * <ul>
+ * <li>x<sub>0</sub><sup>#</sup> = x<sub>0</sub> = 0,</li>
+ * <li>x<sub>k</sub><sup>#</sup> = x<sub>k</sub> if 1 ≤ k < N,</li>
+ * <li>x<sub>N</sub><sup>#</sup> = 0,</li>
+ * <li>x<sub>k</sub><sup>#</sup> = -x<sub>2N-k</sub> if N + 1 ≤ k <
+ * 2N.</li>
+ * </ul>
+ * <p>
+ * Then, the standard DST-I y<sub>0</sub>, …, y<sub>N-1</sub> of the real
+ * data set x<sub>0</sub>, …, x<sub>N-1</sub> is equal to <em>half</em>
+ * of i (the pure imaginary number) times the N first elements of the DFT of the
+ * extended data set x<sub>0</sub><sup>#</sup>, …,
+ * x<sub>2N-1</sub><sup>#</sup> <br>
+ * y<sub>n</sub> = (i / 2) ∑<sub>k=0</sub><sup>2N-1</sup>
+ * x<sub>k</sub><sup>#</sup> exp[-2πi nk / (2N)]
+ * k = 0, …, N-1.
+ * <p>
+ * The present implementation of the discrete sine transform as a fast sine
+ * transform requires the length of the data to be a power of two. Besides,
+ * it implicitly assumes that the sampled function is odd. In particular, the
+ * first element of the data set must be 0, which is enforced in
+ * {@link #apply(DoubleUnaryOperator, double, double, int)},
+ * after sampling.
+ */
+public class FastSineTransform implements RealTransform {
+ /** Operation to be performed. */
+ private final UnaryOperator<double[]> op;
+
+ /**
+ * @param normalization Normalization to be applied to the transformed data.
+ * @param inverse Whether to perform the inverse transform.
+ */
+ public FastSineTransform(final DstNormalization normalization,
+ final boolean inverse) {
+ op = create(normalization, inverse);
+ }
+
+ /**
+ * @param normalization Normalization to be applied to the
+ * transformed data.
+ */
+ public FastSineTransform(final DstNormalization normalization) {
+ this(normalization, false);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * The first element of the specified data set is required to be {@code 0}.
+ *
+ * @throws MathIllegalArgumentException if the length of the data array is
+ * not a power of two, or the first element of the data array is not zero.
+ */
+ @Override
+ public double[] apply(final double[] f) {
+ return op.apply(f);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * The implementation enforces {@code f(x) = 0} at {@code x = 0}.
+ *
+ * @throws IllegalArgumentException if the number of sample points is not a
+ * power of two, if the lower bound is greater than, or equal to the upper bound,
+ * if the number of sample points is negative.
+ */
+ @Override
+ public double[] apply(final DoubleUnaryOperator f,
+ final double min,
+ final double max,
+ final int n) {
+ final double[] data = TransformUtils.sample(f, min, max, n);
+ data[0] = 0;
+ return apply(data);
+ }
+
+ /**
+ * Perform the FST algorithm (including inverse).
+ * The first element of the data set is required to be {@code 0}.
+ *
+ * @param f Data array to be transformed.
+ * @return the transformed array.
+ * @throws IllegalArgumentException if the length of the data array is
+ * not a power of two, or the first element of the data array is not zero.
+ */
+ private double[] fst(double[] f) {
+ if (!ArithmeticUtils.isPowerOfTwo(f.length)) {
+ throw new TransformException(TransformException.NOT_POWER_OF_TWO,
+ f.length);
+ }
+ if (f[0] != 0) {
+ throw new TransformException(TransformException.FIRST_ELEMENT_NOT_ZERO,
+ f[0]);
+ }
+
+ final double[] transformed = new double[f.length];
+ final int n = f.length;
+ if (n == 1) {
+ transformed[0] = 0;
+ return transformed;
+ }
+
+ // construct a new array and perform FFT on it
+ final double[] x = new double[n];
+ x[0] = 0;
+ final int nShifted = n >> 1;
+ x[nShifted] = 2 * f[nShifted];
+ final double piOverN = Math.PI / n;
+ for (int i = 1; i < nShifted; i++) {
+ final int nMi = n - i;
+ final double fi = f[i];
+ final double fnMi = f[nMi];
+ final double a = Math.sin(i * piOverN) * (fi + fnMi);
+ final double b = 0.5 * (fi - fnMi);
+ x[i] = a + b;
+ x[nMi] = a - b;
+ }
+
+ final FastFourierTransform transform = new FastFourierTransform(DftNormalization.STANDARD);
+ final Complex[] y = transform.apply(x);
+
+ // reconstruct the FST result for the original array
+ transformed[0] = 0;
+ transformed[1] = 0.5 * y[0].getReal();
+ for (int i = 1; i < nShifted; i++) {
+ final int i2 = 2 * i;
+ transformed[i2] = -y[i].getImaginary();
+ transformed[i2 + 1] = y[i].getReal() + transformed[i2 - 1];
+ }
+
+ return transformed;
+ }
+
+ /**
+ * Factory method.
+ *
+ * @param normalization Normalization to be applied to the
+ * transformed data.
+ * @param inverse Whether to perform the inverse transform.
+ * @return the transform operator.
+ */
+ private UnaryOperator<double[]> create(final DstNormalization normalization,
+ final boolean inverse) {
+ if (inverse) {
+ return normalization == DstNormalization.ORTHOGONAL_DST_I ?
+ (f) -> TransformUtils.scaleInPlace(fst(f), Math.sqrt(2d / f.length)) :
+ (f) -> TransformUtils.scaleInPlace(fst(f), 2d / f.length);
+ } else {
+ return normalization == DstNormalization.ORTHOGONAL_DST_I ?
+ (f) -> TransformUtils.scaleInPlace(fst(f), Math.sqrt(2d / f.length)) :
+ (f) -> fst(f);
+ }
+ }
+}
diff --git a/commons-math-transform/src/main/java/org/apache/commons/math4/transform/RealTransform.java b/commons-math-transform/src/main/java/org/apache/commons/math4/transform/RealTransform.java
new file mode 100644
index 0000000..8f8f6af
--- /dev/null
+++ b/commons-math-transform/src/main/java/org/apache/commons/math4/transform/RealTransform.java
@@ -0,0 +1,51 @@
+/*
+ * 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.math4.transform;
+
+import java.util.function.DoubleUnaryOperator;
+import java.util.function.UnaryOperator;
+
+/**
+ * Real transforms.
+ */
+public interface RealTransform extends UnaryOperator<double[]> {
+ /**
+ * Returns the transform of the specified data set.
+ *
+ * @param f the data array to be transformed (signal).
+ * @return the transformed array (spectrum).
+ * @throws IllegalArgumentException if the transform cannot be performed.
+ */
+ double[] apply(double[] f);
+
+ /**
+ * Returns the transform of the specified function.
+ *
+ * @param f Function to be sampled and transformed.
+ * @param min Lower bound (inclusive) of the interval.
+ * @param max Upper bound (exclusive) of the interval.
+ * @param n Number of sample points.
+ * @return the result.
+ * @throws IllegalArgumentException if the transform cannot be performed.
+ */
+ default double[] apply(DoubleUnaryOperator f,
+ double min,
+ double max,
+ int n) {
+ return apply(TransformUtils.sample(f, min, max, n));
+ }
+}
diff --git a/commons-math-transform/src/main/java/org/apache/commons/math4/transform/TransformException.java b/commons-math-transform/src/main/java/org/apache/commons/math4/transform/TransformException.java
new file mode 100644
index 0000000..0c298ee
--- /dev/null
+++ b/commons-math-transform/src/main/java/org/apache/commons/math4/transform/TransformException.java
@@ -0,0 +1,52 @@
+/*
+ * 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.math4.transform;
+
+import java.text.MessageFormat;
+
+/**
+ * Exception class with constants for frequently used messages.
+ * Class is package-private (for internal use only).
+ */
+class TransformException extends IllegalArgumentException {
+ /** Error message for "out of range" condition. */
+ public static final String FIRST_ELEMENT_NOT_ZERO = "First element ({0}) must be 0";
+ /** Error message for "not strictly positive" condition. */
+ public static final String NOT_STRICTLY_POSITIVE = "Number {0} is not strictly positive";
+ /** Error message for "too large" condition. */
+ public static final String TOO_LARGE = "Number {0} is larger than {1}";
+ /** Error message for "size mismatch" condition. */
+ public static final String SIZE_MISMATCH = "Size mismatch: {0} != {1}";
+ /** Error message for "pow(2, n) + 1". */
+ public static final String NOT_POWER_OF_TWO_PLUS_ONE = "{0} is not equal to 1 + pow(2, n), for some n";
+ /** Error message for "pow(2, n)". */
+ public static final String NOT_POWER_OF_TWO = "{0} is not equal to pow(2, n), for some n";
+
+ /** Serializable version identifier. */
+ private static final long serialVersionUID = 20210522L;
+
+ /**
+ * Create an exception where the message is constructed by applying
+ * the {@code format()} method from {@code java.text.MessageFormat}.
+ *
+ * @param message Message format (with replaceable parameters).
+ * @param formatArguments Actual arguments to be displayed in the message.
+ */
+ public TransformException(String message, Object... formatArguments) {
+ super(MessageFormat.format(message, formatArguments));
+ }
+}
diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/transform/TransformUtils.java b/commons-math-transform/src/main/java/org/apache/commons/math4/transform/TransformUtils.java
similarity index 52%
rename from commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/transform/TransformUtils.java
rename to commons-math-transform/src/main/java/org/apache/commons/math4/transform/TransformUtils.java
index 09d4e8a..bf1fa5e 100644
--- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/transform/TransformUtils.java
+++ b/commons-math-transform/src/main/java/org/apache/commons/math4/transform/TransformUtils.java
@@ -14,50 +14,30 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.commons.math4.legacy.transform;
+package org.apache.commons.math4.transform;
import java.util.Arrays;
+import java.util.function.DoubleUnaryOperator;
import org.apache.commons.numbers.complex.Complex;
-import org.apache.commons.math4.legacy.exception.DimensionMismatchException;
-import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException;
-import org.apache.commons.math4.legacy.exception.util.LocalizedFormats;
/**
* Useful functions for the implementation of various transforms.
- *
- * @since 3.0
+ * Class is package-private (for internal use only).
*/
-public class TransformUtils {
- /**
- * Table of the powers of 2 to facilitate binary search lookup.
- *
- * @see #exactLog2(int)
- */
- private static final int[] POWERS_OF_TWO = {
- 0x00000001, 0x00000002, 0x00000004, 0x00000008, 0x00000010, 0x00000020,
- 0x00000040, 0x00000080, 0x00000100, 0x00000200, 0x00000400, 0x00000800,
- 0x00001000, 0x00002000, 0x00004000, 0x00008000, 0x00010000, 0x00020000,
- 0x00040000, 0x00080000, 0x00100000, 0x00200000, 0x00400000, 0x00800000,
- 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000,
- 0x40000000
- };
-
- /** Private constructor. */
- private TransformUtils() {
- super();
- }
+class TransformUtils {
+ /** Utility class. */
+ private TransformUtils() {}
/**
* Multiply every component in the given real array by the
* given real number. The change is made in place.
*
- * @param f the real array to be scaled
- * @param d the real scaling coefficient
- * @return a reference to the scaled array
+ * @param f Array to be scaled.
+ * @param d Scaling coefficient.
+ * @return a reference to the scaled array.
*/
- public static double[] scaleArray(double[] f, double d) {
-
+ static double[] scaleInPlace(double[] f, double d) {
for (int i = 0; i < f.length; i++) {
f[i] *= d;
}
@@ -68,12 +48,11 @@ public class TransformUtils {
* Multiply every component in the given complex array by the
* given real number. The change is made in place.
*
- * @param f the complex array to be scaled
- * @param d the real scaling coefficient
- * @return a reference to the scaled array
+ * @param f Array to be scaled.
+ * @param d Scaling coefficient.
+ * @return the scaled array.
*/
- public static Complex[] scaleArray(Complex[] f, double d) {
-
+ static Complex[] scaleInPlace(Complex[] f, double d) {
for (int i = 0; i < f.length; i++) {
f[i] = Complex.ofCartesian(d * f[i].getReal(), d * f[i].getImaginary());
}
@@ -90,11 +69,11 @@ public class TransformUtils {
* <li>{@code dataRI[1][i] = dataC[i].getImaginary()}.</li>
* </ul>
*
- * @param dataC the array of {@link Complex} data to be transformed
+ * @param dataC Array of {@link Complex} data to be transformed.
* @return a two dimensional array filled with the real and imaginary parts
- * of the specified complex input
+ * of the specified complex input.
*/
- public static double[][] createRealImaginaryArray(final Complex[] dataC) {
+ static double[][] createRealImaginary(final Complex[] dataC) {
final double[][] dataRI = new double[2][dataC.length];
final double[] dataR = dataRI[0];
final double[] dataI = dataRI[1];
@@ -115,21 +94,21 @@ public class TransformUtils {
* <li>{@code dataC[i].getImaginary() = dataRI[1][i]}.</li>
* </ul>
*
- * @param dataRI the array of real and imaginary parts to be transformed
- * @return an array of {@link Complex} with specified real and imaginary parts.
- * @throws DimensionMismatchException if the number of rows of the specified
- * array is not two, or the array is not rectangular
+ * @param dataRI Array of real and imaginary parts to be transformed.
+ * @return a {@link Complex} array.
+ * @throws IllegalArgumentException if the number of rows of the specified
+ * array is not two, or the array is not rectangular.
*/
- public static Complex[] createComplexArray(final double[][] dataRI)
- throws DimensionMismatchException{
-
+ static Complex[] createComplex(final double[][] dataRI) {
if (dataRI.length != 2) {
- throw new DimensionMismatchException(dataRI.length, 2);
+ throw new TransformException(TransformException.SIZE_MISMATCH,
+ dataRI.length, 2);
}
final double[] dataR = dataRI[0];
final double[] dataI = dataRI[1];
if (dataR.length != dataI.length) {
- throw new DimensionMismatchException(dataI.length, dataR.length);
+ throw new TransformException(TransformException.SIZE_MISMATCH,
+ dataI.length, dataR.length);
}
final int n = dataR.length;
@@ -140,24 +119,39 @@ public class TransformUtils {
return c;
}
-
/**
- * Returns the base-2 logarithm of the specified {@code int}. Throws an
- * exception if {@code n} is not a power of two.
+ * Samples the specified univariate real function on the specified interval.
+ * <p>
+ * The interval is divided equally into {@code n} sections and sample points
+ * are taken from {@code min} to {@code max - (max - min) / n}; therefore
+ * {@code f} is not sampled at the upper bound {@code max}.</p>
*
- * @param n the {@code int} whose base-2 logarithm is to be evaluated
- * @return the base-2 logarithm of {@code n}
- * @throws MathIllegalArgumentException if {@code n} is not a power of two
+ * @param f Function to be sampled
+ * @param min Lower bound of the interval (included).
+ * @param max Upper bound of the interval (excluded).
+ * @param n Number of sample points.
+ * @return the array of samples.
+ * @throws IllegalArgumentException if the lower bound {@code min} is
+ * greater than, or equal to the upper bound {@code max}, if the number
+ * of sample points {@code n} is negative.
*/
- public static int exactLog2(final int n)
- throws MathIllegalArgumentException {
+ static double[] sample(DoubleUnaryOperator f,
+ double min,
+ double max,
+ int n) {
+ if (n <= 0) {
+ throw new TransformException(TransformException.NOT_STRICTLY_POSITIVE,
+ Integer.valueOf(n));
+ }
+ if (min >= max) {
+ throw new TransformException(TransformException.TOO_LARGE, min, max);
+ }
- int index = Arrays.binarySearch(TransformUtils.POWERS_OF_TWO, n);
- if (index < 0) {
- throw new MathIllegalArgumentException(
- LocalizedFormats.NOT_POWER_OF_TWO_CONSIDER_PADDING,
- Integer.valueOf(n));
+ final double[] s = new double[n];
+ final double h = (max - min) / n;
+ for (int i = 0; i < n; i++) {
+ s[i] = f.applyAsDouble(min + i * h);
}
- return index;
+ return s;
}
}
diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/transform/package-info.java b/commons-math-transform/src/main/java/org/apache/commons/math4/transform/package-info.java
similarity index 85%
rename from commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/transform/package-info.java
rename to commons-math-transform/src/main/java/org/apache/commons/math4/transform/package-info.java
index dfe1eed..5febfd4 100644
--- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/transform/package-info.java
+++ b/commons-math-transform/src/main/java/org/apache/commons/math4/transform/package-info.java
@@ -14,9 +14,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
/**
- *
- * Implementations of transform methods, including Fast Fourier transforms.
- *
+ * Implementations of transform methods.
*/
-package org.apache.commons.math4.legacy.transform;
+package org.apache.commons.math4.transform;
diff --git a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/transform/FastCosineTransformerTest.java b/commons-math-transform/src/test/java/org/apache/commons/math4/transform/FastCosineTransformerTest.java
similarity index 57%
rename from commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/transform/FastCosineTransformerTest.java
rename to commons-math-transform/src/test/java/org/apache/commons/math4/transform/FastCosineTransformerTest.java
index 0543f6f..41212a4 100644
--- a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/transform/FastCosineTransformerTest.java
+++ b/commons-math-transform/src/test/java/org/apache/commons/math4/transform/FastCosineTransformerTest.java
@@ -14,29 +14,27 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.commons.math4.legacy.transform;
+package org.apache.commons.math4.transform;
import java.util.Arrays;
import java.util.Collection;
+import java.util.function.DoubleUnaryOperator;
-import org.apache.commons.math4.legacy.analysis.UnivariateFunction;
-import org.apache.commons.math4.legacy.analysis.function.Sin;
-import org.apache.commons.math4.legacy.analysis.function.Sinc;
-import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException;
-import org.apache.commons.math4.legacy.exception.MathIllegalStateException;
-import org.apache.commons.math4.legacy.util.FastMath;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
+import org.apache.commons.math3.analysis.UnivariateFunction;
+import org.apache.commons.math3.analysis.function.Sin;
+import org.apache.commons.math3.analysis.function.Sinc;
+
/**
- * Test case for fast cosine transformer.
+ * Test case for {@link FastCosineTransform}.
* <p>
* FCT algorithm is exact, the small tolerance number is used only to account
* for round-off errors.
- *
*/
@RunWith(value = Parameterized.class)
public final class FastCosineTransformerTest
@@ -59,13 +57,13 @@ public final class FastCosineTransformerTest
128
};
this.relativeTolerance = new double[] {
- 1E-15, 1E-15, 1E-14, 1E-13, 1E-13, 1E-12, 1E-11, 1E-10
+ 1e-15, 1e-15, 1e-14, 1e-13, 1e-13, 1e-12, 1e-11, 1e-10
};
}
/**
- * Returns an array containing {@code true, false} in order to check both
- * standard and orthogonal DCTs.
+ * Returns an array containing {@code true, false} in order to
+ * check both standard and orthogonal DCTs.
*
* @return an array of parameters for this parameterized test
*/
@@ -80,8 +78,8 @@ public final class FastCosineTransformerTest
}
@Override
- RealTransformer createRealTransformer() {
- return new FastCosineTransformer(normalization);
+ RealTransform createRealTransformer(boolean inverse) {
+ return new FastCosineTransform(normalization, inverse);
}
@Override
@@ -110,8 +108,9 @@ public final class FastCosineTransformerTest
}
@Override
- UnivariateFunction getValidFunction() {
- return new Sinc();
+ DoubleUnaryOperator getValidFunction() {
+ final UnivariateFunction sinc = new Sinc();
+ return (x) -> sinc.value(x);
}
@Override
@@ -121,16 +120,17 @@ public final class FastCosineTransformerTest
@Override
double getValidUpperBound() {
- return FastMath.PI;
+ return Math.PI;
}
@Override
- double[] transform(final double[] x, final TransformType type) {
+ double[] transform(final double[] x,
+ final boolean inverse) {
final int n = x.length;
final double[] y = new double[n];
final double[] cos = new double[2 * (n - 1)];
for (int i = 0; i < cos.length; i++) {
- cos[i] = FastMath.cos(FastMath.PI * i / (n - 1.0));
+ cos[i] = Math.cos(Math.PI * i / (n - 1.0));
}
int sgn = 1;
for (int j = 0; j < n; j++) {
@@ -142,73 +142,66 @@ public final class FastCosineTransformerTest
sgn *= -1;
}
final double s;
- if (type == TransformType.FORWARD) {
+ if (!inverse) {
if (normalization == DctNormalization.STANDARD_DCT_I) {
s = 1.0;
} else if (normalization == DctNormalization.ORTHOGONAL_DCT_I) {
- s = FastMath.sqrt(2.0 / (n - 1.0));
+ s = Math.sqrt(2.0 / (n - 1.0));
} else {
- throw new MathIllegalStateException();
+ throw new IllegalStateException();
}
- } else if (type == TransformType.INVERSE) {
+ } else {
if (normalization == DctNormalization.STANDARD_DCT_I) {
s = 2.0 / (n - 1.0);
} else if (normalization == DctNormalization.ORTHOGONAL_DCT_I) {
- s = FastMath.sqrt(2.0 / (n - 1.0));
+ s = Math.sqrt(2.0 / (n - 1.0));
} else {
- throw new MathIllegalStateException();
+ throw new IllegalStateException();
}
- } else {
- /*
- * Should never occur. This clause is a safeguard in case other
- * types are used to TransformType (which should not be done).
- */
- throw new MathIllegalStateException();
}
- TransformUtils.scaleArray(y, s);
+ TransformUtils.scaleInPlace(y, s);
return y;
}
- /*
- * Additional tests.
- */
+ // Additional tests.
/** Test of transformer for the ad hoc data. */
@Test
public void testAdHocData() {
- FastCosineTransformer transformer;
- transformer = new FastCosineTransformer(DctNormalization.STANDARD_DCT_I);
- double result[], tolerance = 1E-12;
+ FastCosineTransform transformer;
+ double result[], tolerance = 1e-12;
- double x[] = {
+ final double x[] = {
0.0, 1.0, 4.0, 9.0, 16.0, 25.0, 36.0, 49.0, 64.0
};
- double y[] =
- {
- 172.0, -105.096569476353, 27.3137084989848, -12.9593152353742,
- 8.0, -5.78585076868676, 4.68629150101524, -4.15826451958632,
- 4.0
- };
-
- result = transformer.transform(x, TransformType.FORWARD);
+ final double y[] = {
+ 172.0, -105.096569476353, 27.3137084989848, -12.9593152353742,
+ 8.0, -5.78585076868676, 4.68629150101524, -4.15826451958632,
+ 4.0
+ };
+
+ transformer = new FastCosineTransform(DctNormalization.STANDARD_DCT_I);
+ result = transformer.apply(x);
for (int i = 0; i < result.length; i++) {
Assert.assertEquals(y[i], result[i], tolerance);
}
- result = transformer.transform(y, TransformType.INVERSE);
+ transformer = new FastCosineTransform(DctNormalization.STANDARD_DCT_I, true);
+ result = transformer.apply(y);
for (int i = 0; i < result.length; i++) {
Assert.assertEquals(x[i], result[i], tolerance);
}
- TransformUtils.scaleArray(x, FastMath.sqrt(0.5 * (x.length - 1)));
+ TransformUtils.scaleInPlace(x, Math.sqrt(0.5 * (x.length - 1)));
- transformer = new FastCosineTransformer(DctNormalization.ORTHOGONAL_DCT_I);
- result = transformer.transform(y, TransformType.FORWARD);
+ transformer = new FastCosineTransform(DctNormalization.ORTHOGONAL_DCT_I);
+ result = transformer.apply(y);
for (int i = 0; i < result.length; i++) {
Assert.assertEquals(x[i], result[i], tolerance);
}
- result = transformer.transform(x, TransformType.INVERSE);
+ transformer = new FastCosineTransform(DctNormalization.ORTHOGONAL_DCT_I, true);
+ result = transformer.apply(x);
for (int i = 0; i < result.length; i++) {
Assert.assertEquals(y[i], result[i], tolerance);
}
@@ -216,31 +209,30 @@ public final class FastCosineTransformerTest
/** Test of parameters for the transformer. */
@Test
- public void testParameters()
- throws Exception {
- UnivariateFunction f = new Sin();
- FastCosineTransformer transformer;
- transformer = new FastCosineTransformer(DctNormalization.STANDARD_DCT_I);
+ public void testParameters() throws Exception {
+ final UnivariateFunction sinFunction = new Sin();
+ final DoubleUnaryOperator f = (x) -> sinFunction.value(x);
+ final FastCosineTransform transformer = new FastCosineTransform(DctNormalization.STANDARD_DCT_I);
try {
// bad interval
- transformer.transform(f, 1, -1, 65, TransformType.FORWARD);
- Assert.fail("Expecting MathIllegalArgumentException - bad interval");
- } catch (MathIllegalArgumentException ex) {
+ transformer.apply(f, 1, -1, 65);
+ Assert.fail("Expecting IllegalArgumentException - bad interval");
+ } catch (IllegalArgumentException ex) {
// expected
}
try {
// bad samples number
- transformer.transform(f, -1, 1, 1, TransformType.FORWARD);
- Assert.fail("Expecting MathIllegalArgumentException - bad samples number");
- } catch (MathIllegalArgumentException ex) {
+ transformer.apply(f, -1, 1, 1);
+ Assert.fail("Expecting IllegalArgumentException - bad samples number");
+ } catch (IllegalArgumentException ex) {
// expected
}
try {
// bad samples number
- transformer.transform(f, -1, 1, 64, TransformType.FORWARD);
- Assert.fail("Expecting MathIllegalArgumentException - bad samples number");
- } catch (MathIllegalArgumentException ex) {
+ transformer.apply(f, -1, 1, 64);
+ Assert.fail("Expecting IllegalArgumentException - bad samples number");
+ } catch (IllegalArgumentException ex) {
// expected
}
}
@@ -248,27 +240,26 @@ public final class FastCosineTransformerTest
/** Test of transformer for the sine function. */
@Test
public void testSinFunction() {
- UnivariateFunction f = new Sin();
- FastCosineTransformer transformer;
- transformer = new FastCosineTransformer(DctNormalization.STANDARD_DCT_I);
- double min, max, result[], tolerance = 1E-12;
+ final UnivariateFunction sinFunction = new Sin();
+ final DoubleUnaryOperator f = (x) -> sinFunction.value(x);
+ final FastCosineTransform transformer = new FastCosineTransform(DctNormalization.STANDARD_DCT_I);
+ double min, max, result[], tolerance = 1e-12;
int N = 9;
- double expected[] =
- {
- 0.0, 3.26197262739567, 0.0, -2.17958042710327, 0.0,
- -0.648846697642915, 0.0, -0.433545502649478, 0.0
- };
+ final double expected[] = {
+ 0.0, 3.26197262739567, 0.0, -2.17958042710327, 0.0,
+ -0.648846697642915, 0.0, -0.433545502649478, 0.0
+ };
min = 0.0;
- max = 2.0 * FastMath.PI * N / (N - 1);
- result = transformer.transform(f, min, max, N, TransformType.FORWARD);
+ max = 2.0 * Math.PI * N / (N - 1);
+ result = transformer.apply(f, min, max, N);
for (int i = 0; i < N; i++) {
Assert.assertEquals(expected[i], result[i], tolerance);
}
- min = -FastMath.PI;
- max = FastMath.PI * (N + 1) / (N - 1);
- result = transformer.transform(f, min, max, N, TransformType.FORWARD);
+ min = -Math.PI;
+ max = Math.PI * (N + 1) / (N - 1);
+ result = transformer.apply(f, min, max, N);
for (int i = 0; i < N; i++) {
Assert.assertEquals(-expected[i], result[i], tolerance);
}
diff --git a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/transform/FastFourierTransformerTest.java b/commons-math-transform/src/test/java/org/apache/commons/math4/transform/FastFourierTransformerTest.java
similarity index 53%
rename from commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/transform/FastFourierTransformerTest.java
rename to commons-math-transform/src/test/java/org/apache/commons/math4/transform/FastFourierTransformerTest.java
index 3b964bd..4653d02 100644
--- a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/transform/FastFourierTransformerTest.java
+++ b/commons-math-transform/src/test/java/org/apache/commons/math4/transform/FastFourierTransformerTest.java
@@ -14,35 +14,35 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.commons.math4.legacy.transform;
+package org.apache.commons.math4.transform;
-import java.util.Random;
+import java.util.function.DoubleUnaryOperator;
-import org.apache.commons.numbers.complex.Complex;
-import org.apache.commons.math4.legacy.analysis.UnivariateFunction;
-import org.apache.commons.math4.legacy.analysis.function.Sin;
-import org.apache.commons.math4.legacy.analysis.function.Sinc;
-import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException;
-import org.apache.commons.math4.legacy.exception.NotStrictlyPositiveException;
-import org.apache.commons.math4.legacy.exception.NumberIsTooLargeException;
-import org.apache.commons.math4.legacy.util.FastMath;
import org.junit.Assert;
import org.junit.Test;
+import org.apache.commons.rng.UniformRandomProvider;
+import org.apache.commons.rng.simple.RandomSource;
+import org.apache.commons.numbers.complex.Complex;
+
+import org.apache.commons.math3.analysis.UnivariateFunction;
+import org.apache.commons.math3.analysis.function.Sin;
+import org.apache.commons.math3.analysis.function.Sinc;
+
/**
- * Test case for fast Fourier transformer.
+ * Test case for {@link FastFourierTransform}.
* <p>
* FFT algorithm is exact, the small tolerance number is used only
* to account for round-off errors.
- *
*/
public final class FastFourierTransformerTest {
- /** The common seed of all random number generators used in this test. */
- private final static long SEED = 20110111L;
+ private static final Sin SIN_FUNCTION = new Sin();
+ private static final DoubleUnaryOperator SIN = (x) -> SIN_FUNCTION.value(x);
- /*
- * Precondition checks.
- */
+ /** RNG. */
+ private static final UniformRandomProvider RNG = RandomSource.create(RandomSource.MWC_256);
+
+ // Precondition checks.
@Test
public void testTransformComplexSizeNotAPowerOfTwo() {
@@ -50,17 +50,14 @@ public final class FastFourierTransformerTest {
final Complex[] x = createComplexData(n);
final DftNormalization[] norm;
norm = 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]);
+ for (boolean type : new boolean[] { true, false }) {
+ final FastFourierTransform fft = new FastFourierTransform(norm[i], type);
try {
- fft.transform(x, type[j]);
- Assert.fail(norm[i] + ", " + type[j] +
- ": MathIllegalArgumentException was expected");
- } catch (MathIllegalArgumentException e) {
+ fft.apply(x);
+ Assert.fail(norm[i] + ", " + type +
+ ": IllegalArgumentException was expected");
+ } catch (IllegalArgumentException e) {
// Expected behaviour
}
}
@@ -73,17 +70,14 @@ public final class FastFourierTransformerTest {
final double[] x = createRealData(n);
final DftNormalization[] norm;
norm = 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]);
+ for (boolean type : new boolean[] { true, false }) {
+ final FastFourierTransform fft = new FastFourierTransform(norm[i], type);
try {
- fft.transform(x, type[j]);
- Assert.fail(norm[i] + ", " + type[j] +
- ": MathIllegalArgumentException was expected");
- } catch (MathIllegalArgumentException e) {
+ fft.apply(x);
+ Assert.fail(norm[i] + ", " + type +
+ ": IllegalArgumentException was expected");
+ } catch (IllegalArgumentException e) {
// Expected behaviour
}
}
@@ -93,20 +87,16 @@ public final class FastFourierTransformerTest {
@Test
public void testTransformFunctionSizeNotAPowerOfTwo() {
final int n = 127;
- final UnivariateFunction f = new Sin();
final DftNormalization[] norm;
norm = 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]);
+ for (boolean type : new boolean[] { true, false }) {
+ final FastFourierTransform fft = new FastFourierTransform(norm[i], type);
try {
- fft.transform(f, 0.0, Math.PI, n, type[j]);
- Assert.fail(norm[i] + ", " + type[j] +
- ": MathIllegalArgumentException was expected");
- } catch (MathIllegalArgumentException e) {
+ fft.apply(SIN, 0.0, Math.PI, n);
+ Assert.fail(norm[i] + ", " + type +
+ ": IllegalArgumentException was expected");
+ } catch (IllegalArgumentException e) {
// Expected behaviour
}
}
@@ -116,21 +106,17 @@ public final class FastFourierTransformerTest {
@Test
public void testTransformFunctionNotStrictlyPositiveNumberOfSamples() {
final int n = -128;
- final UnivariateFunction f = new Sin();
final DftNormalization[] norm;
norm = 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]);
+ for (boolean type : new boolean[] { true, false }) {
+ final FastFourierTransform fft = new FastFourierTransform(norm[i], type);
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) {
+ fft.apply(SIN, 0.0, Math.PI, n);
+ fft.apply(SIN, 0.0, Math.PI, n);
+ Assert.fail(norm[i] + ", " + type +
+ ": IllegalArgumentException was expected");
+ } catch (IllegalArgumentException e) {
// Expected behaviour
}
}
@@ -140,46 +126,38 @@ public final class FastFourierTransformerTest {
@Test
public void testTransformFunctionInvalidBounds() {
final int n = 128;
- final UnivariateFunction f = new Sin();
final DftNormalization[] norm;
norm = 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]);
+ for (boolean type : new boolean[] { true, false }) {
+ final FastFourierTransform fft = new FastFourierTransform(norm[i], type);
try {
- fft.transform(f, Math.PI, 0.0, n, type[j]);
- Assert.fail(norm[i] + ", " + type[j] +
- ": NumberIsTooLargeException was expected");
- } catch (NumberIsTooLargeException e) {
+ fft.apply(SIN, Math.PI, 0.0, n);
+ Assert.fail(norm[i] + ", " + type +
+ ": IllegalArgumentException was expected");
+ } catch (IllegalArgumentException e) {
// Expected behaviour
}
}
}
}
- /*
- * Utility methods for checking (successful) transforms.
- */
+ // Utility methods for checking (successful) transforms.
private static Complex[] createComplexData(final int n) {
- final Random random = new Random(SEED);
final Complex[] data = new Complex[n];
for (int i = 0; i < n; i++) {
- final double re = 2.0 * random.nextDouble() - 1.0;
- final double im = 2.0 * random.nextDouble() - 1.0;
+ final double re = 2 * RNG.nextDouble() - 1;
+ final double im = 2 * RNG.nextDouble() - 1;
data[i] = Complex.ofCartesian(re, im);
}
return data;
}
private static double[] createRealData(final int n) {
- final Random random = new Random(SEED);
final double[] data = new double[n];
for (int i = 0; i < n; i++) {
- data[i] = 2.0 * random.nextDouble() - 1.0;
+ data[i] = 2 * RNG.nextDouble() - 1;
}
return data;
}
@@ -191,9 +169,9 @@ public final class FastFourierTransformerTest {
final double[] sin = new double[n];
final Complex[] y = new Complex[n];
for (int i = 0; i < n; i++) {
- final double arg = 2.0 * FastMath.PI * i / n;
- cos[i] = FastMath.cos(arg);
- sin[i] = FastMath.sin(arg);
+ final double arg = 2.0 * Math.PI * i / n;
+ cos[i] = Math.cos(arg);
+ sin[i] = Math.sin(arg);
}
for (int i = 0; i < n; i++) {
double yr = 0.0;
@@ -212,47 +190,47 @@ public final class FastFourierTransformerTest {
return y;
}
- private static void doTestTransformComplex(final int n, final double tol,
- final DftNormalization normalization,
- final TransformType type) {
- final FastFourierTransformer fft;
- fft = new FastFourierTransformer(normalization);
+ private static void doTestTransformComplex(final int n,
+ final double tol,
+ final DftNormalization normalization,
+ boolean inverse) {
+ final FastFourierTransform fft = new FastFourierTransform(normalization, inverse);
final Complex[] x = createComplexData(n);
final Complex[] expected;
final double s;
- if (type==TransformType.FORWARD) {
+ if (!inverse) {
expected = dft(x, -1);
if (normalization == DftNormalization.STANDARD){
s = 1.0;
} else {
- s = 1.0 / FastMath.sqrt(n);
+ s = 1.0 / Math.sqrt(n);
}
} else {
expected = dft(x, 1);
if (normalization == DftNormalization.STANDARD) {
s = 1.0 / n;
} else {
- s = 1.0 / FastMath.sqrt(n);
+ s = 1.0 / Math.sqrt(n);
}
}
- final Complex[] actual = fft.transform(x, type);
+ final Complex[] actual = fft.apply(x);
for (int i = 0; i < n; i++) {
final String msg;
- msg = String.format("%s, %s, %d, %d", normalization, type, n, i);
+ msg = String.format("%s, %s, %d, %d", normalization, inverse, n, i);
final double re = s * expected[i].getReal();
Assert.assertEquals(msg, re, actual[i].getReal(),
- tol * FastMath.abs(re));
+ tol * Math.abs(re));
final double im = s * expected[i].getImaginary();
- Assert.assertEquals(msg, im, actual[i].getImaginary(), tol *
- FastMath.abs(re));
+ Assert.assertEquals(msg, im, actual[i].getImaginary(),
+ tol * Math.abs(re));
}
}
- private static void doTestTransformReal(final int n, final double tol,
- final DftNormalization normalization,
- final TransformType type) {
- final FastFourierTransformer fft;
- fft = new FastFourierTransformer(normalization);
+ private static void doTestTransformReal(final int n,
+ final double tol,
+ final DftNormalization normalization,
+ final boolean inverse) {
+ final FastFourierTransform fft = new FastFourierTransform(normalization, inverse);
final double[] x = createRealData(n);
final Complex[] xc = new Complex[n];
for (int i = 0; i < n; i++) {
@@ -260,93 +238,91 @@ public final class FastFourierTransformerTest {
}
final Complex[] expected;
final double s;
- if (type == TransformType.FORWARD) {
+ if (!inverse) {
expected = dft(xc, -1);
if (normalization == DftNormalization.STANDARD) {
s = 1.0;
} else {
- s = 1.0 / FastMath.sqrt(n);
+ s = 1.0 / Math.sqrt(n);
}
} else {
expected = dft(xc, 1);
if (normalization == DftNormalization.STANDARD) {
s = 1.0 / n;
} else {
- s = 1.0 / FastMath.sqrt(n);
+ s = 1.0 / Math.sqrt(n);
}
}
- final Complex[] actual = fft.transform(x, type);
+ final Complex[] actual = fft.apply(x);
for (int i = 0; i < n; i++) {
final String msg;
- msg = String.format("%s, %s, %d, %d", normalization, type, n, i);
+ msg = String.format("%s, %s, %d, %d", normalization, inverse, n, i);
final double re = s * expected[i].getReal();
Assert.assertEquals(msg, re, actual[i].getReal(),
- tol * FastMath.abs(re));
+ tol * Math.abs(re));
final double im = s * expected[i].getImaginary();
- Assert.assertEquals(msg, im, actual[i].getImaginary(), tol *
- FastMath.abs(re));
+ Assert.assertEquals(msg, im, actual[i].getImaginary(),
+ tol * Math.abs(re));
}
}
- private static void doTestTransformFunction(final UnivariateFunction f,
- final double min, final double max, int n, final double tol,
- final DftNormalization normalization,
- final TransformType type) {
- final FastFourierTransformer fft;
- fft = new FastFourierTransformer(normalization);
+ private static void doTestTransformFunction(final DoubleUnaryOperator f,
+ final double min,
+ final double max,
+ int n,
+ final double tol,
+ final DftNormalization normalization,
+ final boolean inverse) {
+ final FastFourierTransform fft = new FastFourierTransform(normalization, inverse);
final Complex[] x = new Complex[n];
for (int i = 0; i < n; i++) {
final double t = min + i * (max - min) / n;
- x[i] = Complex.ofCartesian(f.value(t), 0);
+ x[i] = Complex.ofCartesian(f.applyAsDouble(t), 0);
}
final Complex[] expected;
final double s;
- if (type == TransformType.FORWARD) {
+ if (!inverse) {
expected = dft(x, -1);
if (normalization == DftNormalization.STANDARD) {
s = 1.0;
} else {
- s = 1.0 / FastMath.sqrt(n);
+ s = 1.0 / Math.sqrt(n);
}
} else {
expected = dft(x, 1);
if (normalization == DftNormalization.STANDARD) {
s = 1.0 / n;
} else {
- s = 1.0 / FastMath.sqrt(n);
+ s = 1.0 / Math.sqrt(n);
}
}
- final Complex[] actual = fft.transform(f, min, max, n, type);
+ final Complex[] actual = fft.apply(f, min, max, n);
for (int i = 0; i < n; i++) {
final String msg = String.format("%d, %d", n, i);
final double re = s * expected[i].getReal();
Assert.assertEquals(msg, re, actual[i].getReal(),
- tol * FastMath.abs(re));
+ tol * Math.abs(re));
final double im = s * expected[i].getImaginary();
- Assert.assertEquals(msg, im, actual[i].getImaginary(), tol *
- FastMath.abs(re));
+ Assert.assertEquals(msg, im, actual[i].getImaginary(),
+ tol * Math.abs(re));
}
}
- /*
- * Tests of standard transform (when data is valid).
- */
+ // Tests of standard transform (when data is valid).
@Test
public void testTransformComplex() {
final DftNormalization[] norm;
norm = 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]);
+ for (boolean type : new boolean[] { true, false }) {
+ doTestTransformComplex(2, 1e-15, norm[i], type);
+ doTestTransformComplex(4, 1e-14, norm[i], type);
+ doTestTransformComplex(8, 1e-13, norm[i], type);
+ doTestTransformComplex(16, 1e-13, norm[i], type);
+ doTestTransformComplex(32, 1e-13, norm[i], type);
+ doTestTransformComplex(64, 1e-12, norm[i], type);
+ doTestTransformComplex(128, 1e-11, norm[i], type);
}
}
}
@@ -355,58 +331,54 @@ public final class FastFourierTransformerTest {
public void testStandardTransformReal() {
final DftNormalization[] norm;
norm = 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]);
+ for (boolean type : new boolean[] { true, false }) {
+ doTestTransformReal(2, 1e-15, norm[i], type);
+ doTestTransformReal(4, 1e-14, norm[i], type);
+ doTestTransformReal(8, 1e-13, norm[i], type);
+ doTestTransformReal(16, 1e-13, norm[i], type);
+ doTestTransformReal(32, 1e-12, norm[i], type);
+ doTestTransformReal(64, 1e-12, norm[i], type);
+ doTestTransformReal(128, 1e-11, norm[i], type);
}
}
}
@Test
public void testStandardTransformFunction() {
- final UnivariateFunction f = new Sinc();
- final double min = -FastMath.PI;
- final double max = FastMath.PI;
+ final UnivariateFunction sinc = new Sinc();
+ final DoubleUnaryOperator f = (x) -> sinc.value(x);
+
+ final double min = -Math.PI;
+ final double max = Math.PI;
final DftNormalization[] norm;
norm = 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]);
+ for (boolean type : new boolean[] { true, false }) {
+ doTestTransformFunction(f, min, max, 2, 1e-15, norm[i], type);
+ doTestTransformFunction(f, min, max, 4, 1e-14, norm[i], type);
+ doTestTransformFunction(f, min, max, 8, 1e-14, norm[i], type);
+ doTestTransformFunction(f, min, max, 16, 1e-13, norm[i], type);
+ doTestTransformFunction(f, min, max, 32, 1e-13, norm[i], type);
+ doTestTransformFunction(f, min, max, 64, 1e-12, norm[i], type);
+ doTestTransformFunction(f, min, max, 128, 1e-11, norm[i], type);
}
}
}
- /*
- * Additional tests for 1D data.
- */
+ // Additional tests for 1D data.
/**
* Test of transformer for the ad hoc data taken from Mathematica.
*/
@Test
public void testAdHocData() {
- FastFourierTransformer transformer;
- transformer = new FastFourierTransformer(DftNormalization.STANDARD);
- Complex result[]; double tolerance = 1E-12;
+ FastFourierTransform transformer;
+ Complex result[]; double tolerance = 1e-12;
- double x[] = {1.3, 2.4, 1.7, 4.1, 2.9, 1.7, 5.1, 2.7};
- Complex y[] = {
+ final double x[] = {1.3, 2.4, 1.7, 4.1, 2.9, 1.7, 5.1, 2.7};
+ final Complex y[] = {
Complex.ofCartesian(21.9, 0.0),
Complex.ofCartesian(-2.09497474683058, 1.91507575950825),
Complex.ofCartesian(-2.6, 2.7),
@@ -416,30 +388,33 @@ public final class FastFourierTransformerTest {
Complex.ofCartesian(-2.6, -2.7),
Complex.ofCartesian(-2.09497474683058, -1.91507575950825)};
- result = transformer.transform(x, TransformType.FORWARD);
+ transformer = new FastFourierTransform(DftNormalization.STANDARD);
+ result = transformer.apply(x);
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.transform(y, TransformType.INVERSE);
+ transformer = new FastFourierTransform(DftNormalization.STANDARD, true);
+ result = transformer.apply(y);
for (int i = 0; i < result.length; i++) {
Assert.assertEquals(x[i], result[i].getReal(), tolerance);
Assert.assertEquals(0.0, result[i].getImaginary(), tolerance);
}
double x2[] = {10.4, 21.6, 40.8, 13.6, 23.2, 32.8, 13.6, 19.2};
- TransformUtils.scaleArray(x2, 1.0 / FastMath.sqrt(x2.length));
+ TransformUtils.scaleInPlace(x2, 1.0 / Math.sqrt(x2.length));
Complex y2[] = y;
- transformer = new FastFourierTransformer(DftNormalization.UNITARY);
- result = transformer.transform(y2, TransformType.FORWARD);
+ transformer = new FastFourierTransform(DftNormalization.UNITARY);
+ result = transformer.apply(y2);
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.transform(x2, TransformType.INVERSE);
+ transformer = new FastFourierTransform(DftNormalization.UNITARY, true);
+ result = transformer.apply(x2);
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);
@@ -451,14 +426,13 @@ public final class FastFourierTransformerTest {
*/
@Test
public void testSinFunction() {
- UnivariateFunction f = new Sin();
- FastFourierTransformer transformer;
- transformer = new FastFourierTransformer(DftNormalization.STANDARD);
+ FastFourierTransform transformer;
Complex result[]; int N = 1 << 8;
- double min, max, tolerance = 1E-12;
+ double min, max, tolerance = 1e-12;
- min = 0.0; max = 2.0 * FastMath.PI;
- result = transformer.transform(f, min, max, N, TransformType.FORWARD);
+ min = 0.0; max = 2.0 * Math.PI;
+ transformer = new FastFourierTransform(DftNormalization.STANDARD);
+ result = transformer.apply(SIN, min, max, N);
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);
@@ -468,8 +442,9 @@ public final class FastFourierTransformerTest {
Assert.assertEquals(0.0, result[i].getImaginary(), tolerance);
}
- min = -FastMath.PI; max = FastMath.PI;
- result = transformer.transform(f, min, max, N, TransformType.INVERSE);
+ min = -Math.PI; max = Math.PI;
+ transformer = new FastFourierTransform(DftNormalization.STANDARD, true);
+ result = transformer.apply(SIN, min, max, N);
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);
diff --git a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/transform/FastHadamardTransformerTest.java b/commons-math-transform/src/test/java/org/apache/commons/math4/transform/FastHadamardTransformerTest.java
similarity index 70%
rename from commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/transform/FastHadamardTransformerTest.java
rename to commons-math-transform/src/test/java/org/apache/commons/math4/transform/FastHadamardTransformerTest.java
index fd783ee..3499317 100644
--- a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/transform/FastHadamardTransformerTest.java
+++ b/commons-math-transform/src/test/java/org/apache/commons/math4/transform/FastHadamardTransformerTest.java
@@ -14,27 +14,25 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.commons.math4.legacy.transform;
+package org.apache.commons.math4.transform;
-import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException;
-import org.apache.commons.numbers.core.Precision;
import org.junit.Assert;
import org.junit.Test;
+import org.apache.commons.numbers.core.Precision;
+
/**
- * JUnit Test for HadamardTransformerTest
- * @see org.apache.commons.math4.legacy.transform.FastHadamardTransformer
+ * Test for {@link FestHadamardTransform}.
*/
public final class FastHadamardTransformerTest {
-
/**
* Test of transformer for the a 8-point FHT (means n=8)
*/
@Test
public void test8Points() {
checkAllTransforms(new int[] { 1, 4, -2, 3, 0, 1, 4, -1 },
- new int[] { 10, -4, 2, -4, 2, -12, 6, 8 });
+ new int[] { 10, -4, 2, -4, 2, -12, 6, 8 });
}
/**
@@ -51,8 +49,8 @@ public final class FastHadamardTransformerTest {
*/
@Test
public void testNoIntInverse() {
- FastHadamardTransformer transformer = new FastHadamardTransformer();
- double[] x = transformer.transform(new double[] { 0, 1, 0, 1}, TransformType.INVERSE);
+ final FastHadamardTransform transformer = new FastHadamardTransform(true);
+ final double[] x = transformer.apply(new double[] { 0, 1, 0, 1});
Assert.assertEquals( 0.5, x[0], 0);
Assert.assertEquals(-0.5, x[1], 0);
Assert.assertEquals( 0.0, x[2], 0);
@@ -65,41 +63,41 @@ public final class FastHadamardTransformerTest {
@Test
public void test3Points() {
try {
- new FastHadamardTransformer().transform(new double[3], TransformType.FORWARD);
+ new FastHadamardTransform().apply(new double[3]);
Assert.fail("an exception should have been thrown");
- } catch (MathIllegalArgumentException iae) {
+ } catch (IllegalArgumentException iae) {
// expected
}
}
- private void checkAllTransforms(int[]x, int[] y) {
+ private void checkAllTransforms(int[] x, int[] y) {
checkDoubleTransform(x, y);
checkInverseDoubleTransform(x, y);
checkIntTransform(x, y);
}
- private void checkDoubleTransform(int[]x, int[] y) {
+ private void checkDoubleTransform(int[] x, int[] y) {
// Initiate the transformer
- FastHadamardTransformer transformer = new FastHadamardTransformer();
+ final FastHadamardTransform transformer = new FastHadamardTransform();
// check double transform
- double[] dX = new double[x.length];
+ final double[] dX = new double[x.length];
for (int i = 0; i < dX.length; ++i) {
dX[i] = x[i];
}
- double dResult[] = transformer.transform(dX, TransformType.FORWARD);
+ final double dResult[] = transformer.apply(dX);
for (int i = 0; i < dResult.length; i++) {
// compare computed results to precomputed results
Assert.assertTrue(Precision.equals(y[i], dResult[i], 1));
}
}
- private void checkIntTransform(int[]x, int[] y) {
+ private void checkIntTransform(int[] x, int[] y) {
// Initiate the transformer
- FastHadamardTransformer transformer = new FastHadamardTransformer();
+ final FastHadamardTransform transformer = new FastHadamardTransform();
// check integer transform
- int iResult[] = transformer.transform(x);
+ final int iResult[] = transformer.apply(x);
for (int i = 0; i < iResult.length; i++) {
// compare computed results to precomputed results
Assert.assertEquals(y[i], iResult[i]);
@@ -109,14 +107,14 @@ public final class FastHadamardTransformerTest {
private void checkInverseDoubleTransform(int[]x, int[] y) {
// Initiate the transformer
- FastHadamardTransformer transformer = new FastHadamardTransformer();
+ final FastHadamardTransform transformer = new FastHadamardTransform(true);
// check double transform
- double[] dY = new double[y.length];
+ final double[] dY = new double[y.length];
for (int i = 0; i < dY.length; ++i) {
dY[i] = y[i];
}
- double dResult[] = transformer.transform(dY, TransformType.INVERSE);
+ final double dResult[] = transformer.apply(dY);
for (int i = 0; i < dResult.length; i++) {
// compare computed results to precomputed results
Assert.assertTrue(Precision.equals(x[i], dResult[i], 1));
diff --git a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/transform/FastSineTransformerTest.java b/commons-math-transform/src/test/java/org/apache/commons/math4/transform/FastSineTransformerTest.java
similarity index 58%
rename from commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/transform/FastSineTransformerTest.java
rename to commons-math-transform/src/test/java/org/apache/commons/math4/transform/FastSineTransformerTest.java
index 21df571..aeed09e 100644
--- a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/transform/FastSineTransformerTest.java
+++ b/commons-math-transform/src/test/java/org/apache/commons/math4/transform/FastSineTransformerTest.java
@@ -14,29 +14,27 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.commons.math4.legacy.transform;
+package org.apache.commons.math4.transform;
import java.util.Arrays;
import java.util.Collection;
+import java.util.function.DoubleUnaryOperator;
-import org.apache.commons.math4.legacy.analysis.UnivariateFunction;
-import org.apache.commons.math4.legacy.analysis.function.Sin;
-import org.apache.commons.math4.legacy.analysis.function.Sinc;
-import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException;
-import org.apache.commons.math4.legacy.exception.MathIllegalStateException;
-import org.apache.commons.math4.legacy.util.FastMath;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
+import org.apache.commons.math3.analysis.UnivariateFunction;
+import org.apache.commons.math3.analysis.function.Sin;
+import org.apache.commons.math3.analysis.function.Sinc;
+
/**
- * Test case for fast sine transformer.
+ * Test case for {@link FastSineTransform}.
* <p>
* FST algorithm is exact, the small tolerance number is used only
* to account for round-off errors.
- *
*/
@RunWith(value = Parameterized.class)
public final class FastSineTransformerTest extends RealTransformerAbstractTest {
@@ -58,7 +56,7 @@ public final class FastSineTransformerTest extends RealTransformerAbstractTest {
129
};
this.relativeTolerance = new double[] {
- 1E-15, 1E-15, 1E-14, 1E-14, 1E-13, 1E-12, 1E-11, 1E-11
+ 1e-15, 1e-15, 1e-14, 1e-14, 1e-13, 1e-12, 1e-11, 1e-11
};
}
@@ -66,7 +64,7 @@ public final class FastSineTransformerTest extends RealTransformerAbstractTest {
* Returns an array containing {@code true, false} in order to check both
* standard and orthogonal DSTs.
*
- * @return an array of parameters for this parameterized test
+ * @return an array of parameters for this parameterized test.
*/
@Parameters
public static Collection<Object[]> data() {
@@ -87,13 +85,13 @@ public final class FastSineTransformerTest extends RealTransformerAbstractTest {
@Override
double[] createRealData(final int n) {
final double[] data = super.createRealData(n);
- data[0] = 0.0;
+ data[0] = 0;
return data;
}
@Override
- RealTransformer createRealTransformer() {
- return new FastSineTransformer(normalization);
+ RealTransform createRealTransformer(boolean inverse) {
+ return new FastSineTransform(normalization, inverse);
}
@Override
@@ -122,8 +120,9 @@ public final class FastSineTransformerTest extends RealTransformerAbstractTest {
}
@Override
- UnivariateFunction getValidFunction() {
- return new Sinc();
+ DoubleUnaryOperator getValidFunction() {
+ final UnivariateFunction sinc = new Sinc();
+ return (x) -> sinc.value(x);
}
@Override
@@ -133,16 +132,16 @@ public final class FastSineTransformerTest extends RealTransformerAbstractTest {
@Override
double getValidUpperBound() {
- return FastMath.PI;
+ return Math.PI;
}
@Override
- double[] transform(final double[] x, final TransformType type) {
+ double[] transform(final double[] x, boolean inverse) {
final int n = x.length;
final double[] y = new double[n];
final double[] sin = new double[2 * n];
for (int i = 0; i < sin.length; i++) {
- sin[i] = FastMath.sin(FastMath.PI * i / n);
+ sin[i] = Math.sin(Math.PI * i / n);
}
for (int j = 0; j < n; j++) {
double yj = 0.0;
@@ -152,90 +151,87 @@ public final class FastSineTransformerTest extends RealTransformerAbstractTest {
y[j] = yj;
}
final double s;
- if (type == TransformType.FORWARD) {
+ if (!inverse) {
if (normalization == DstNormalization.STANDARD_DST_I) {
- s = 1.0;
+ s = 1;
} else if (normalization == DstNormalization.ORTHOGONAL_DST_I) {
- s = FastMath.sqrt(2.0 / n);
+ s = Math.sqrt(2d / n);
} else {
- throw new MathIllegalStateException();
+ throw new IllegalStateException();
}
- } else if (type == TransformType.INVERSE) {
+ } else {
if (normalization == DstNormalization.STANDARD_DST_I) {
- s = 2.0 / n;
+ s = 2d / n;
} else if (normalization == DstNormalization.ORTHOGONAL_DST_I) {
- s = FastMath.sqrt(2.0 / n);
+ s = Math.sqrt(2d / n);
} else {
- throw new MathIllegalStateException();
+ throw new IllegalStateException();
}
- } else {
- /*
- * Should never occur. This clause is a safeguard in case other
- * types are used to TransformType (which should not be done).
- */
- throw new MathIllegalStateException();
}
- TransformUtils.scaleArray(y, s);
+
+ TransformUtils.scaleInPlace(y, s);
return y;
}
- /*
- * Additional tests.
- */
+ // Additional tests.
+
@Test
public void testTransformRealFirstElementNotZero() {
- final TransformType[] type = TransformType.values();
final double[] data = new double[] {
- 1.0, 1.0, 1.0, 1.0
+ 1, 1, 1, 1
};
- final RealTransformer transformer = createRealTransformer();
- for (int j = 0; j < type.length; j++) {
+ for (boolean type : new boolean[] { true, false }) {
try {
- transformer.transform(data, type[j]);
- Assert.fail(type[j].toString());
- } catch (MathIllegalArgumentException e) {
+ final RealTransform transformer = createRealTransformer(type);
+ transformer.apply(data);
+ Assert.fail("type=" + type);
+ } catch (IllegalArgumentException e) {
// Expected: do nothing
}
}
}
- /*
- * Additional (legacy) tests.
- */
+ // Additional (legacy) tests.
/**
* Test of transformer for the ad hoc data.
*/
@Test
public void testAdHocData() {
- FastSineTransformer transformer;
- transformer = new FastSineTransformer(DstNormalization.STANDARD_DST_I);
- double result[], tolerance = 1E-12;
+ FastSineTransform transformer;
+ double result[], tolerance = 1e-12;
- double x[] = { 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0 };
- double y[] = { 0.0, 20.1093579685034, -9.65685424949238,
- 5.98642305066196, -4.0, 2.67271455167720,
- -1.65685424949238, 0.795649469518633 };
+ final double x[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7
+ };
+ final double y[] = {
+ 0.0, 20.1093579685034, -9.65685424949238,
+ 5.98642305066196, -4.0, 2.67271455167720,
+ -1.65685424949238, 0.795649469518633
+ };
- result = transformer.transform(x, TransformType.FORWARD);
+ transformer = new FastSineTransform(DstNormalization.STANDARD_DST_I);
+ result = transformer.apply(x);
for (int i = 0; i < result.length; i++) {
Assert.assertEquals(y[i], result[i], tolerance);
}
- result = transformer.transform(y, TransformType.INVERSE);
+ transformer = new FastSineTransform(DstNormalization.STANDARD_DST_I, true);
+ result = transformer.apply(y);
for (int i = 0; i < result.length; i++) {
Assert.assertEquals(x[i], result[i], tolerance);
}
- TransformUtils.scaleArray(x, FastMath.sqrt(x.length / 2.0));
- transformer = new FastSineTransformer(DstNormalization.ORTHOGONAL_DST_I);
+ TransformUtils.scaleInPlace(x, Math.sqrt(x.length / 2d));
+ transformer = new FastSineTransform(DstNormalization.ORTHOGONAL_DST_I);
- result = transformer.transform(y, TransformType.FORWARD);
+ result = transformer.apply(y);
for (int i = 0; i < result.length; i++) {
Assert.assertEquals(x[i], result[i], tolerance);
}
- result = transformer.transform(x, TransformType.INVERSE);
+ transformer = new FastSineTransform(DstNormalization.ORTHOGONAL_DST_I, true);
+ result = transformer.apply(x);
for (int i = 0; i < result.length; i++) {
Assert.assertEquals(y[i], result[i], tolerance);
}
@@ -246,20 +242,22 @@ public final class FastSineTransformerTest extends RealTransformerAbstractTest {
*/
@Test
public void testSinFunction() {
- UnivariateFunction f = new Sin();
- FastSineTransformer transformer;
- transformer = new FastSineTransformer(DstNormalization.STANDARD_DST_I);
- double min, max, result[], tolerance = 1E-12; int N = 1 << 8;
-
- min = 0.0; max = 2.0 * FastMath.PI;
- result = transformer.transform(f, min, max, N, TransformType.FORWARD);
+ final UnivariateFunction sinFunction = new Sin();
+ final DoubleUnaryOperator f = (x) -> sinFunction.value(x);
+ final FastSineTransform transformer = new FastSineTransform(DstNormalization.STANDARD_DST_I);
+ double min, max, result[], tolerance = 1e-12; int N = 1 << 8;
+
+ min = 0.0;
+ max = 2 * Math.PI;
+ result = transformer.apply(f, min, max, N);
Assert.assertEquals(N >> 1, result[2], tolerance);
for (int i = 0; i < N; i += (i == 1 ? 2 : 1)) {
Assert.assertEquals(0.0, result[i], tolerance);
}
- min = -FastMath.PI; max = FastMath.PI;
- result = transformer.transform(f, min, max, N, TransformType.FORWARD);
+ min = -Math.PI;
+ max = Math.PI;
+ result = transformer.apply(f, min, max, N);
Assert.assertEquals(-(N >> 1), result[2], tolerance);
for (int i = 0; i < N; i += (i == 1 ? 2 : 1)) {
Assert.assertEquals(0.0, result[i], tolerance);
@@ -271,29 +269,29 @@ public final class FastSineTransformerTest extends RealTransformerAbstractTest {
*/
@Test
public void testParameters() throws Exception {
- UnivariateFunction f = new Sin();
- FastSineTransformer transformer;
- transformer = new FastSineTransformer(DstNormalization.STANDARD_DST_I);
+ final UnivariateFunction sinFunction = new Sin();
+ final DoubleUnaryOperator f = (x) -> sinFunction.value(x);
+ final FastSineTransform transformer = new FastSineTransform(DstNormalization.STANDARD_DST_I);
try {
// bad interval
- transformer.transform(f, 1, -1, 64, TransformType.FORWARD);
- Assert.fail("Expecting MathIllegalArgumentException - bad interval");
- } catch (MathIllegalArgumentException ex) {
+ transformer.apply(f, 1, -1, 64);
+ Assert.fail("Expecting IllegalArgumentException - bad interval");
+ } catch (IllegalArgumentException ex) {
// expected
}
try {
// bad samples number
- transformer.transform(f, -1, 1, 0, TransformType.FORWARD);
- Assert.fail("Expecting MathIllegalArgumentException - bad samples number");
- } catch (MathIllegalArgumentException ex) {
+ transformer.apply(f, -1, 1, 0);
+ Assert.fail("Expecting IllegalArgumentException - bad samples number");
+ } catch (IllegalArgumentException ex) {
// expected
}
try {
// bad samples number
- transformer.transform(f, -1, 1, 100, TransformType.FORWARD);
- Assert.fail("Expecting MathIllegalArgumentException - bad samples number");
- } catch (MathIllegalArgumentException ex) {
+ transformer.apply(f, -1, 1, 100);
+ Assert.fail("Expecting IllegalArgumentException - bad samples number");
+ } catch (IllegalArgumentException ex) {
// expected
}
}
diff --git a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/transform/RealTransformerAbstractTest.java b/commons-math-transform/src/test/java/org/apache/commons/math4/transform/RealTransformerAbstractTest.java
similarity index 57%
rename from commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/transform/RealTransformerAbstractTest.java
rename to commons-math-transform/src/test/java/org/apache/commons/math4/transform/RealTransformerAbstractTest.java
index a28d29c..a419110 100644
--- a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/transform/RealTransformerAbstractTest.java
+++ b/commons-math-transform/src/test/java/org/apache/commons/math4/transform/RealTransformerAbstractTest.java
@@ -14,40 +14,38 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.commons.math4.legacy.transform;
+package org.apache.commons.math4.transform;
-import java.util.Random;
-
-import org.apache.commons.math4.legacy.analysis.UnivariateFunction;
-import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException;
-import org.apache.commons.math4.legacy.exception.NotStrictlyPositiveException;
-import org.apache.commons.math4.legacy.exception.NumberIsTooLargeException;
-import org.apache.commons.math4.legacy.util.FastMath;
import org.junit.Assert;
import org.junit.Test;
+import java.util.function.DoubleUnaryOperator;
+
+import org.apache.commons.rng.UniformRandomProvider;
+import org.apache.commons.rng.simple.RandomSource;
+
/**
- * Abstract test for classes implementing the {@link RealTransformer} interface.
+ * Abstract test for classes implementing the {@link RealTransform} interface.
* This abstract test handles the automatic generation of random data of various
* sizes. For each generated data array, actual values (returned by the
* transformer to be tested) are compared to expected values, returned by the
- * {@link #transform(double[], TransformType)} (to be implemented by the user:
- * a naive method may be used). Methods are also provided to test that invalid
- * parameters throw the expected exceptions.
+ * {@link #apply(double[])} (to be implemented by the user: a naive method may
+ * be used). Methods are also provided to test that invalid parameters throw the
+ * expected exceptions.
*
* @since 3.0
*/
public abstract class RealTransformerAbstractTest {
-
- /** The common seed of all random number generators used in this test. */
- private final static long SEED = 20110119L;
+ /** RNG. */
+ private static final UniformRandomProvider RNG = RandomSource.create(RandomSource.MWC_256);
/**
- * Returns a new instance of the {@link RealTransformer} to be tested.
+ * Returns a new instance of the {@link RealTransform} to be tested.
*
+ * @param inverse Whether to apply the inverse transform.
* @return a the transformer to be tested
*/
- abstract RealTransformer createRealTransformer();
+ abstract RealTransform createRealTransformer(boolean inverse);
/**
* Returns an invalid data size. Transforms with this data size should
@@ -62,7 +60,7 @@ public abstract class RealTransformerAbstractTest {
/**
* Returns the total number of invalid data sizes to be tested. If data
* array of any
- * size can be handled by the {@link RealTransformer} to be tested, this
+ * size can be handled by the {@link RealTransform} to be tested, this
* method should return {@code 0}.
*
* @return the total number of invalid data sizes
@@ -98,17 +96,17 @@ public abstract class RealTransformerAbstractTest {
/**
* Returns a function for the accuracy check of
- * {@link RealTransformer#transform(UnivariateFunction, double, double, int, TransformType)}.
+ * {@link RealTransform#apply(DoubleUnaryOperator, double, double, int)}.
* This function should be valid. In other words, none of the above methods
* should throw an exception when passed this function.
*
* @return a valid function
*/
- abstract UnivariateFunction getValidFunction();
+ abstract DoubleUnaryOperator getValidFunction();
/**
* Returns a sampling lower bound for the accuracy check of
- * {@link RealTransformer#transform(UnivariateFunction, double, double, int, TransformType)}.
+ * {@link RealTransform#apply(DoubleUnaryOperator, double, double, int)}.
* This lower bound should be valid. In other words, none of the above
* methods should throw an exception when passed this bound.
*
@@ -118,7 +116,7 @@ public abstract class RealTransformerAbstractTest {
/**
* Returns a sampling upper bound for the accuracy check of
- * {@link RealTransformer#transform(UnivariateFunction, double, double, int, TransformType)}.
+ * {@link RealTransform#apply(DoubleUnaryOperator, double, double, int, TransformType)}.
* This upper bound should be valid. In other words, none of the above
* methods should throw an exception when passed this bound.
*
@@ -129,31 +127,28 @@ public abstract class RealTransformerAbstractTest {
/**
* Returns the expected transform of the specified real data array.
*
- * @param x the real data array to be transformed
- * @param type the type of transform (forward, inverse) to be performed
- * @return the expected transform
+ * @param x Data to be transformed.
+ * @param type Whether to perform the inverse) transform.
+ * @return the expected transform.
*/
- abstract double[] transform(double[] x, TransformType type);
+ abstract double[] transform(double[] x, boolean type);
- /*
- * Check of preconditions.
- */
+ // Check of preconditions.
/**
- * {@link RealTransformer#transform(double[], TransformType)} should throw a
- * {@link MathIllegalArgumentException} if data size is invalid.
+ * {@link RealTransform#apply(double[])} should throw a
+ * {@link IllegalArgumentException} if data size is invalid.
*/
@Test
public void testTransformRealInvalidDataSize() {
- final TransformType[] type = TransformType.values();
- final RealTransformer transformer = createRealTransformer();
for (int i = 0; i < getNumberOfInvalidDataSizes(); i++) {
final int n = getInvalidDataSize(i);
- for (int j = 0; j < type.length; j++) {
+ for (boolean type : new boolean[] { true, false }) {
try {
- transformer.transform(createRealData(n), type[j]);
- Assert.fail(type[j] + ", " + n);
- } catch (MathIllegalArgumentException e) {
+ final RealTransform transformer = createRealTransformer(type);
+ transformer.apply(createRealData(n));
+ Assert.fail(type + ", " + n);
+ } catch (IllegalArgumentException e) {
// Expected: do nothing
}
}
@@ -161,24 +156,23 @@ public abstract class RealTransformerAbstractTest {
}
/**
- * {@link RealTransformer#transform(UnivariateFunction, double, double, int, TransformType)}
- * should throw a {@link MathIllegalArgumentException} if number of samples
- * is invalid.
+ * {@link RealTransformer#(DoubleUnaryOperator, double, double, int)}
+ * should throw {@link IllegalArgumentException} if number of samples is
+ * invalid.
*/
@Test
public void testTransformFunctionInvalidDataSize() {
- final TransformType[] type = TransformType.values();
- final RealTransformer transformer = createRealTransformer();
- final UnivariateFunction f = getValidFunction();
+ final DoubleUnaryOperator f = getValidFunction();
final double a = getValidLowerBound();
final double b = getValidUpperBound();
for (int i = 0; i < getNumberOfInvalidDataSizes(); i++) {
final int n = getInvalidDataSize(i);
- for (int j = 0; j < type.length; j++) {
+ for (boolean type : new boolean[] { true, false }) {
try {
- transformer.transform(f, a, b, n, type[j]);
- Assert.fail(type[j] + ", " + n);
- } catch (MathIllegalArgumentException e) {
+ final RealTransform transformer = createRealTransformer(type);
+ transformer.apply(f, a, b, n);
+ Assert.fail(type + ", " + n);
+ } catch (IllegalArgumentException e) {
// Expected: do nothing
}
}
@@ -186,24 +180,23 @@ public abstract class RealTransformerAbstractTest {
}
/**
- * {@link RealTransformer#transform(UnivariateFunction, double, double, int, TransformType)}
- * should throw a {@link NotStrictlyPositiveException} if number of samples
+ * {@link RealTransform#apply(DoubleUnaryOperator, double, double, int)}
+ * should throw {@link IllegalArgumentException} if number of samples
* is not strictly positive.
*/
@Test
public void testTransformFunctionNotStrictlyPositiveNumberOfSamples() {
- final TransformType[] type = TransformType.values();
- final RealTransformer transformer = createRealTransformer();
- final UnivariateFunction f = getValidFunction();
+ final DoubleUnaryOperator f = getValidFunction();
final double a = getValidLowerBound();
final double b = getValidUpperBound();
for (int i = 0; i < getNumberOfValidDataSizes(); i++) {
final int n = getValidDataSize(i);
- for (int j = 0; j < type.length; j++) {
+ for (boolean type : new boolean[] { true, false }) {
try {
- transformer.transform(f, a, b, -n, type[j]);
- Assert.fail(type[j] + ", " + (-n));
- } catch (NotStrictlyPositiveException e) {
+ final RealTransform transformer = createRealTransformer(type);
+ transformer.apply(f, a, b, -n);
+ Assert.fail(type + ", " + (-n));
+ } catch (IllegalArgumentException e) {
// Expected: do nothing
}
}
@@ -211,133 +204,124 @@ public abstract class RealTransformerAbstractTest {
}
/**
- * {@link RealTransformer#transform(UnivariateFunction, double, double, int, TransformType)}
- * should throw a {@link NumberIsTooLargeException} if sampling bounds are
+ * {@link RealTransform#apply(DoubleUnaryOperator, double, double, int)}
+ * should throw {@link IllegalArgumentException} if sampling bounds are
* not correctly ordered.
*/
@Test
public void testTransformFunctionInvalidBounds() {
- final TransformType[] type = TransformType.values();
- final RealTransformer transformer = createRealTransformer();
- final UnivariateFunction f = getValidFunction();
+ final DoubleUnaryOperator f = getValidFunction();
final double a = getValidLowerBound();
final double b = getValidUpperBound();
for (int i = 0; i < getNumberOfValidDataSizes(); i++) {
final int n = getValidDataSize(i);
- for (int j = 0; j < type.length; j++) {
+ for (boolean type : new boolean[] { true, false }) {
try {
- transformer.transform(f, b, a, n, type[j]);
- Assert.fail(type[j] + ", " + b + ", " + a);
- } catch (NumberIsTooLargeException e) {
+ final RealTransform transformer = createRealTransformer(type);
+ transformer.apply(f, b, a, n);
+ Assert.fail(type + ", " + b + ", " + a);
+ } catch (IllegalArgumentException e) {
// Expected: do nothing
}
}
}
}
- /*
- * Accuracy tests of transform of valid data.
- */
+ // Accuracy tests of transform of valid data.
/**
- * Accuracy check of {@link RealTransformer#transform(double[], TransformType)}.
+ * Accuracy check of {@link RealTransform#apply(double[])}.
* For each valid data size returned by
* {@link #getValidDataSize(int) getValidDataSize(i)},
* a random data array is generated with
* {@link #createRealData(int) createRealData(i)}. The actual
* transform is computed and compared to the expected transform, return by
- * {@link #transform(double[], TransformType)}. Actual and expected values
+ * {@link #transform(double[], boolean)}. Actual and expected values
* should be equal to within the relative error returned by
* {@link #getRelativeTolerance(int) getRelativeTolerance(i)}.
*/
@Test
public void testTransformReal() {
- final TransformType[] type = TransformType.values();
for (int i = 0; i < getNumberOfValidDataSizes(); i++) {
final int n = getValidDataSize(i);
final double tol = getRelativeTolerance(i);
- for (int j = 0; j < type.length; j++) {
- doTestTransformReal(n, tol, type[j]);
+ for (boolean type : new boolean[] { true, false }) {
+ doTestTransformReal(n, tol, type);
}
}
}
/**
* Accuracy check of
- * {@link RealTransformer#transform(UnivariateFunction, double, double, int, TransformType)}.
+ * {@link RealTransform#apply(DoubleUnaryOperator, double, double, int, TransformType)}.
* For each valid data size returned by
* {@link #getValidDataSize(int) getValidDataSize(i)},
* the {@link UnivariateFunction} returned by {@link #getValidFunction()} is
* sampled. The actual transform is computed and compared to the expected
- * transform, return by {@link #transform(double[], TransformType)}. Actual
+ * transform, return by {@link #transform(double[], boolean)}. Actual
* and expected values should be equal to within the relative error returned
* by {@link #getRelativeTolerance(int) getRelativeTolerance(i)}.
*/
@Test
public void testTransformFunction() {
- final TransformType[] type = TransformType.values();
for (int i = 0; i < getNumberOfValidDataSizes(); i++) {
final int n = getValidDataSize(i);
final double tol = getRelativeTolerance(i);
- for (int j = 0; j < type.length; j++) {
- doTestTransformFunction(n, tol, type[j]);
+ for (boolean type : new boolean[] { true, false }) {
+ doTestTransformFunction(n, tol, type);
}
}
}
- /*
- * Utility methods.
- */
+ // Utility methods.
/**
- * Returns a random array of doubles. Random generator always uses the same
- * seed.
+ * Returns a random array of doubles.
*
* @param n the size of the array to be returned
* @return a random array of specified size
*/
double[] createRealData(final int n) {
- final Random random = new Random(SEED);
final double[] data = new double[n];
for (int i = 0; i < n; i++) {
- data[i] = 2.0 * random.nextDouble() - 1.0;
+ data[i] = 2 * RNG.nextDouble() - 1;
}
return data;
}
- /*
- * The tests per se.
- */
+ // Actual tests.
- private void doTestTransformReal(final int n, final double tol,
- final TransformType type) {
- final RealTransformer transformer = createRealTransformer();
+ private void doTestTransformReal(final int n,
+ final double tol,
+ final boolean type) {
+ final RealTransform transformer = createRealTransformer(type);
final double[] x = createRealData(n);
final double[] expected = transform(x, type);
- final double[] actual = transformer.transform(x, type);
+ final double[] actual = transformer.apply(x);
for (int i = 0; i < n; i++) {
final String msg = String.format("%d, %d", n, i);
- final double delta = tol * FastMath.abs(expected[i]);
+ final double delta = tol * Math.abs(expected[i]);
Assert.assertEquals(msg, expected[i], actual[i], delta);
}
}
- private void doTestTransformFunction(final int n, final double tol,
- final TransformType type) {
- final RealTransformer transformer = createRealTransformer();
- final UnivariateFunction f = getValidFunction();
+ private void doTestTransformFunction(final int n,
+ final double tol,
+ final boolean type) {
+ final RealTransform transformer = createRealTransformer(type);
+ final DoubleUnaryOperator f = getValidFunction();
final double a = getValidLowerBound();
final double b = getValidUpperBound();
final double[] x = createRealData(n);
for (int i = 0; i < n; i++) {
final double t = a + i * (b - a) / n;
- x[i] = f.value(t);
+ x[i] = f.applyAsDouble(t);
}
final double[] expected = transform(x, type);
- final double[] actual = transformer.transform(f, a, b, n, type);
+ final double[] actual = transformer.apply(f, a, b, n);
for (int i = 0; i < n; i++) {
final String msg = String.format("%d, %d", n, i);
- final double delta = tol * FastMath.abs(expected[i]);
+ final double delta = tol * Math.abs(expected[i]);
Assert.assertEquals(msg, expected[i], actual[i], delta);
}
}
diff --git a/commons-math-transform/src/test/java/org/apache/commons/math4/transform/TransformUtilsTest.java b/commons-math-transform/src/test/java/org/apache/commons/math4/transform/TransformUtilsTest.java
new file mode 100644
index 0000000..817ae69
--- /dev/null
+++ b/commons-math-transform/src/test/java/org/apache/commons/math4/transform/TransformUtilsTest.java
@@ -0,0 +1,59 @@
+/*
+ * 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.math4.transform;
+
+import java.util.function.DoubleUnaryOperator;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.apache.commons.math3.analysis.function.Sin;
+
+/**
+ * Tests for {@link TransformUtils}.
+ */
+public class TransformUtilsTest {
+ private static final Sin SIN_FUNCTION = new Sin();
+ private static final DoubleUnaryOperator SIN = (x) -> SIN_FUNCTION.value(x);
+
+ @Test(expected = TransformException.class)
+ public void testSampleWrongBounds(){
+ TransformUtils.sample(SIN, Math.PI, 0.0, 10);
+ }
+
+ @Test(expected = TransformException.class)
+ public void testSampleNegativeNumberOfPoints(){
+ TransformUtils.sample(SIN, 0.0, Math.PI, -1);
+ }
+
+ @Test(expected = TransformException.class)
+ public void testSampleNullNumberOfPoints(){
+ TransformUtils.sample(SIN, 0.0, Math.PI, 0);
+ }
+
+ @Test
+ public void testSample() {
+ final int n = 11;
+ final double min = 0.0;
+ final double max = Math.PI;
+ final double[] actual = TransformUtils.sample(SIN, min, max, n);
+ for (int i = 0; i < n; i++) {
+ final double x = min + (max - min) / n * i;
+ Assert.assertEquals("x = " + x, Math.sin(x), actual[i], 1e-15);
+ }
+ }
+}
diff --git a/pom.xml b/pom.xml
index e8c4149..134c52b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -107,6 +107,7 @@
<modules>
<!-- Modules that do not depend on "legacy" codes. -->
<module>commons-math-neuralnet</module>
+ <module>commons-math-transform</module>
<!-- Non-modularized functionalities. -->
<module>commons-math-legacy</module>
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index a9f80b2..2019541 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -54,6 +54,9 @@ If the output is not quite correct, check for invisible trailing spaces!
</release>
<release version="4.0" date="XXXX-XX-XX" description="">
+ <action dev="erans" type="update" issue="MATH-1582">
+ Transforms codes moved into a dedicated maven module.
+ </action>
<action dev="erans" type="update" issue="MATH-1578">
ANN codes moved into a dedicated maven module.
</action>