diff options
Diffstat (limited to 'src/main/java/org/apache/commons/math3/transform/FastFourierTransformer.java')
-rw-r--r-- | src/main/java/org/apache/commons/math3/transform/FastFourierTransformer.java | 749 |
1 files changed, 749 insertions, 0 deletions
diff --git a/src/main/java/org/apache/commons/math3/transform/FastFourierTransformer.java b/src/main/java/org/apache/commons/math3/transform/FastFourierTransformer.java new file mode 100644 index 0000000..116b21d --- /dev/null +++ b/src/main/java/org/apache/commons/math3/transform/FastFourierTransformer.java @@ -0,0 +1,749 @@ +/* + * 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.math3.transform; + +import org.apache.commons.math3.analysis.FunctionUtils; +import org.apache.commons.math3.analysis.UnivariateFunction; +import org.apache.commons.math3.complex.Complex; +import org.apache.commons.math3.exception.DimensionMismatchException; +import org.apache.commons.math3.exception.MathIllegalArgumentException; +import org.apache.commons.math3.exception.MathIllegalStateException; +import org.apache.commons.math3.exception.util.LocalizedFormats; +import org.apache.commons.math3.util.ArithmeticUtils; +import org.apache.commons.math3.util.FastMath; +import org.apache.commons.math3.util.MathArrays; + +import java.io.Serializable; +import java.lang.reflect.Array; + +/** + * 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>{@code dataRI[1][i]} is the imaginary part of the {@code i}-th data point. + * </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[][] {MathArrays.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.math3.exception.NumberIsTooLargeException if the lower bound is + * greater than, or equal to the upper bound + * @throws org.apache.commons.math3.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); + } + + /** + * Performs a multi-dimensional Fourier transform on a given array. Use {@link + * #transform(Complex[], TransformType)} in a row-column implementation in any number of + * dimensions with O(N×log(N)) complexity with N = n<sub>1</sub> × n<sub>2</sub> + * ×n<sub>3</sub> × ... × n<sub>d</sub>, where n<sub>k</sub> is the number of + * elements in dimension k, and d is the total number of dimensions. + * + * @param mdca Multi-Dimensional Complex Array, i.e. {@code Complex[][][][]} + * @param type the type of transform (forward, inverse) to be performed + * @return transform of {@code mdca} as a Multi-Dimensional Complex Array, i.e. {@code + * Complex[][][][]} + * @throws IllegalArgumentException if any dimension is not a power of two + * @deprecated see MATH-736 + */ + @Deprecated + public Object mdfft(Object mdca, TransformType type) { + MultiDimensionalComplexMatrix mdcm = + (MultiDimensionalComplexMatrix) new MultiDimensionalComplexMatrix(mdca).clone(); + int[] dimensionSize = mdcm.getDimensionSizes(); + // cycle through each dimension + for (int i = 0; i < dimensionSize.length; i++) { + mdfft(mdcm, type, i, new int[0]); + } + return mdcm.getArray(); + } + + /** + * Performs one dimension of a multi-dimensional Fourier transform. + * + * @param mdcm input matrix + * @param type the type of transform (forward, inverse) to be performed + * @param d index of the dimension to process + * @param subVector recursion subvector + * @throws IllegalArgumentException if any dimension is not a power of two + * @deprecated see MATH-736 + */ + @Deprecated + private void mdfft( + MultiDimensionalComplexMatrix mdcm, TransformType type, int d, int[] subVector) { + + int[] dimensionSize = mdcm.getDimensionSizes(); + // if done + if (subVector.length == dimensionSize.length) { + Complex[] temp = new Complex[dimensionSize[d]]; + for (int i = 0; i < dimensionSize[d]; i++) { + // fft along dimension d + subVector[d] = i; + temp[i] = mdcm.get(subVector); + } + + temp = transform(temp, type); + + for (int i = 0; i < dimensionSize[d]; i++) { + subVector[d] = i; + mdcm.set(temp[i], subVector); + } + } else { + int[] vector = new int[subVector.length + 1]; + System.arraycopy(subVector, 0, vector, 0, subVector.length); + if (subVector.length == d) { + // value is not important once the recursion is done. + // then an fft will be applied along the dimension d. + vector[d] = 0; + mdfft(mdcm, type, d, vector); + } else { + for (int i = 0; i < dimensionSize[subVector.length]; i++) { + vector[subVector.length] = i; + // further split along the next dimension + mdfft(mdcm, type, d, vector); + } + } + } + } + + /** + * Complex matrix implementation. Not designed for synchronized access may eventually be + * replaced by jsr-83 of the java community process http://jcp.org/en/jsr/detail?id=83 may + * require additional exception throws for other basic requirements. + * + * @deprecated see MATH-736 + */ + @Deprecated + private static class MultiDimensionalComplexMatrix implements Cloneable { + + /** Size in all dimensions. */ + protected int[] dimensionSize; + + /** Storage array. */ + protected Object multiDimensionalComplexArray; + + /** + * Simple constructor. + * + * @param multiDimensionalComplexArray array containing the matrix elements + */ + MultiDimensionalComplexMatrix(Object multiDimensionalComplexArray) { + + this.multiDimensionalComplexArray = multiDimensionalComplexArray; + + // count dimensions + int numOfDimensions = 0; + for (Object lastDimension = multiDimensionalComplexArray; + lastDimension instanceof Object[]; ) { + final Object[] array = (Object[]) lastDimension; + numOfDimensions++; + lastDimension = array[0]; + } + + // allocate array with exact count + dimensionSize = new int[numOfDimensions]; + + // fill array + numOfDimensions = 0; + for (Object lastDimension = multiDimensionalComplexArray; + lastDimension instanceof Object[]; ) { + final Object[] array = (Object[]) lastDimension; + dimensionSize[numOfDimensions++] = array.length; + lastDimension = array[0]; + } + } + + /** + * Get a matrix element. + * + * @param vector indices of the element + * @return matrix element + * @exception DimensionMismatchException if dimensions do not match + */ + public Complex get(int... vector) throws DimensionMismatchException { + + if (vector == null) { + if (dimensionSize.length > 0) { + throw new DimensionMismatchException(0, dimensionSize.length); + } + return null; + } + if (vector.length != dimensionSize.length) { + throw new DimensionMismatchException(vector.length, dimensionSize.length); + } + + Object lastDimension = multiDimensionalComplexArray; + + for (int i = 0; i < dimensionSize.length; i++) { + lastDimension = ((Object[]) lastDimension)[vector[i]]; + } + return (Complex) lastDimension; + } + + /** + * Set a matrix element. + * + * @param magnitude magnitude of the element + * @param vector indices of the element + * @return the previous value + * @exception DimensionMismatchException if dimensions do not match + */ + public Complex set(Complex magnitude, int... vector) throws DimensionMismatchException { + + if (vector == null) { + if (dimensionSize.length > 0) { + throw new DimensionMismatchException(0, dimensionSize.length); + } + return null; + } + if (vector.length != dimensionSize.length) { + throw new DimensionMismatchException(vector.length, dimensionSize.length); + } + + Object[] lastDimension = (Object[]) multiDimensionalComplexArray; + for (int i = 0; i < dimensionSize.length - 1; i++) { + lastDimension = (Object[]) lastDimension[vector[i]]; + } + + Complex lastValue = (Complex) lastDimension[vector[dimensionSize.length - 1]]; + lastDimension[vector[dimensionSize.length - 1]] = magnitude; + + return lastValue; + } + + /** + * Get the size in all dimensions. + * + * @return size in all dimensions + */ + public int[] getDimensionSizes() { + return dimensionSize.clone(); + } + + /** + * Get the underlying storage array. + * + * @return underlying storage array + */ + public Object getArray() { + return multiDimensionalComplexArray; + } + + /** {@inheritDoc} */ + @Override + public Object clone() { + MultiDimensionalComplexMatrix mdcm = + new MultiDimensionalComplexMatrix( + Array.newInstance(Complex.class, dimensionSize)); + clone(mdcm); + return mdcm; + } + + /** + * Copy contents of current array into mdcm. + * + * @param mdcm array where to copy data + */ + private void clone(MultiDimensionalComplexMatrix mdcm) { + + int[] vector = new int[dimensionSize.length]; + int size = 1; + for (int i = 0; i < dimensionSize.length; i++) { + size *= dimensionSize[i]; + } + int[][] vectorList = new int[size][dimensionSize.length]; + for (int[] nextVector : vectorList) { + System.arraycopy(vector, 0, nextVector, 0, dimensionSize.length); + for (int i = 0; i < dimensionSize.length; i++) { + vector[i]++; + if (vector[i] < dimensionSize[i]) { + break; + } else { + vector[i] = 0; + } + } + } + + for (int[] nextVector : vectorList) { + mdcm.set(get(nextVector), nextVector); + } + } + } +} |