/* ***** BEGIN LICENSE BLOCK *****
* JTransforms
* Copyright (c) 2007 onward, Piotr Wendykier
* 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.
*
* 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.
*
* ***** END LICENSE BLOCK ***** */
package org.jtransforms.fft;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Random;
import org.jtransforms.utils.CommonUtils;
import pl.edu.icm.jlargearrays.ConcurrencyUtils;
import org.jtransforms.utils.IOUtils;
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 pl.edu.icm.jlargearrays.DoubleLargeArray;
import pl.edu.icm.jlargearrays.LargeArray;
import static org.apache.commons.math3.util.FastMath.*;
/**
*
* This is a test of the class {@link DoubleFFT_2D}. In this test, a very crude
* 2d FFT method is implemented (see {@link #complexForward(double[][])}),
* assuming that {@link DoubleFFT_1D} has been fully tested and validated. This
* crude (unoptimized) method is then used to establish <em>expected</em> values
* of <em>direct</em> Fourier transforms.
* </p>
*
* For <em>inverse</em> Fourier transforms, the test assumes that the
* corresponding <em>direct</em> Fourier transform has been tested and
* validated.
* </p>
*
* In all cases, the test consists in creating a random array of data, and
* verifying that expected and actual values of its Fourier transform coincide
* (L2 norm is zero, within a specified accuracy).
* </p>
*
* @author Sébastien Brisard
* @author Piotr Wendykier
*/
@RunWith(value = Parameterized.class)
public class DoubleFFT_2DTest
{
/**
* Base message of all exceptions.
*/
public static final String DEFAULT_MESSAGE = "%d-threaded FFT of size %dx%d: ";
/**
* The constant value of the seed of the random generator.
*/
public static final int SEED = 20110602;
private static final double EPS = pow(10, -12);
@Parameters
public static Collection<Object[]> getParameters()
{
final int[] size = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16, 32,
64, 100, 120, 128, 256, 310, 511, 512, 1024};
final ArrayList<Object[]> parameters = new ArrayList<Object[]>();
for (int i = 0; i < size.length; i++) {
for (int j = 0; j < size.length; j++) {
parameters.add(new Object[]{size[i], size[j], 1, SEED});
parameters.add(new Object[]{size[i], size[j], 8, SEED});
}
}
return parameters;
}
/**
* Fourier transform of the columns.
*/
private final DoubleFFT_1D cfft;
/**
* The object to be tested.
*/
private final DoubleFFT_2D fft;
/**
* Number of columns of the data arrays to be Fourier transformed.
*/
private final int numCols;
/**
* Number of rows of the data arrays to be Fourier transformed.
*/
private final int numRows;
/**
* Fourier transform of the rows.
*/
private final DoubleFFT_1D rfft;
/**
* For the generation of the data arrays.
*/
private final Random random;
/**
* The number of threads used.
*/
private final int numThreads;
/**
* Creates a new instance of this test.
*
* @param numRows
*
number of rows
* @param numColumns
*
number of columns
* @param numThreads
*
the number of threads to be used
* @param seed
*
the seed of the random generator
*/
public DoubleFFT_2DTest(final int numRows, final int numColumns,
final int numThreads, final long seed)
{
this.numRows = numRows;
this.numCols = numColumns;
LargeArray.setMaxSizeOf32bitArray(1);
this.rfft = new DoubleFFT_1D(numColumns);
this.cfft = new DoubleFFT_1D(numRows);
this.fft = new DoubleFFT_2D(numRows, numColumns);
this.random = new Random(seed);
ConcurrencyUtils.setNumberOfThreads(numThreads);
CommonUtils.setThreadsBeginN_2D(4);
this.numThreads = ConcurrencyUtils.getNumberOfThreads();
}
/**
* A crude implementation of 2d complex FFT.
*
* @param a
*
the data to be transformed
*/
public void complexForward(final double[][] a)
{
for (int r = 0; r < numRows; r++) {
rfft.complexForward(a[r]);
}
final double[] buffer = new double[2 * numRows];
for (int c = 0; c < numCols; c++) {
for (int r = 0; r < numRows; r++) {
buffer[2 * r] = a[r][2 * c];
buffer[2 * r + 1] = a[r][2 * c + 1];
}
cfft.complexForward(buffer);
for (int r = 0; r < numRows; r++) {
a[r][2 * c] = buffer[2 * r];
a[r][2 * c + 1] = buffer[2 * r + 1];
}
}
}
/**
* A test of {@link DoubleFFT_2D#complexForward(double[])}.
*/
@Test
public void testComplexForward1dInput()
{
final double[] actual = new double[2 * numRows * numCols];
final double[][] expected0 = new double[numRows][2 * numCols];
final double[] expected = new double[2 * numRows * numCols];
for (int r = 0; r < numRows; r++) {
for (int c = 0; c < 2 * numCols; c++) {
final double rnd = random.nextDouble();
actual[2 * r * numCols + c] = rnd;
expected0[r][c] = rnd;
}
}
fft.complexForward(actual);
complexForward(expected0);
for (int r = 0; r < numRows; r++) {
for (int c = 0; c < 2 * numCols; c++) {
expected[2 * r * numCols + c] = expected0[r][c];
}
}
double rmse = IOUtils.computeRMSE(actual, expected);
Assert.assertEquals(String.format(DEFAULT_MESSAGE, numThreads, numRows, numCols) + ", rmse = " + rmse, 0.0, rmse, EPS);
}
/**
* A test of {@link DoubleFFT_2D#complexForward(DoubleLargeArray)}.
*/
@Test
public void testComplexForwardLarge()
{
final DoubleLargeArray actual = new DoubleLargeArray(2 * numRows * numCols);
final double[][] expected0 = new double[numRows][2 * numCols];
final DoubleLargeArray expected = new DoubleLargeArray(2 * numRows * numCols);
for (int r = 0; r < numRows; r++) {
for (int c = 0; c < 2 * numCols; c++) {
final double rnd = random.nextDouble();
actual.setDouble(2 * r * numCols + c, rnd);
expected0[r][c] = rnd;
}
}
fft.complexForward(actual);
complexForward(expected0);
for (int r = 0; r < numRows; r++) {
for (int c = 0; c < 2 * numCols; c++) {
expected.setDouble(2 * r * numCols + c, expected0[r][c]);
}
}
double rmse = IOUtils.computeRMSE(actual, expected);
Assert.assertEquals(String.format(DEFAULT_MESSAGE, numThreads, numRows, numCols) + ", rmse = " + rmse, 0.0, rmse, EPS);
}
/**
* A test of {@link DoubleFFT_2D#complexForward(double[][])}.
*/
@Test
public void testComplexForward2dInput()
{
final double[][] actual = new double[numRows][2 * numCols];
final double[][] expected = new double[numRows][2 * numCols];
for (int r = 0; r < numRows; r++) {
for (int c = 0; c < 2 * numCols; c++) {
final double rnd = random.nextDouble();
actual[r][c] = rnd;
expected[r][c] = rnd;
}
}
fft.complexForward(actual);
complexForward(expected);
double rmse = IOUtils.computeRMSE(actual, expected);
Assert.assertEquals(String.format(DEFAULT_MESSAGE, numThreads, numRows, numCols) + ", rmse = " + rmse, 0.0, rmse, EPS);
}
/**
* A test of {@link DoubleFFT_2D#complexInverse(double[], boolean)}, with
* the second parameter set to <code>true</code>.
*/
@Test
public void testComplexInverseScaled1dInput()
{
final double[] expected = new double[2 * numRows * numCols];
final double[] actual = new double[2 * numRows * numCols];
for (int i = 0; i < actual.length; i++) {
final double rnd = random.nextDouble();
actual[i] = rnd;
expected[i] = rnd;
}
fft.complexForward(actual);
fft.complexInverse(actual, true);
double rmse = IOUtils.computeRMSE(actual, expected);
Assert.assertEquals(String.format(DEFAULT_MESSAGE, numThreads, numRows, numCols) + ", rmse = " + rmse, 0.0, rmse, EPS);
}
/**
* A test of {@link DoubleFFT_2D#complexInverse(DoubleLargeArray, boolean)}, with
* the second parameter set to <code>true</code>.
*/
@Test
public void testComplexInverseScaledLarge()
{
final DoubleLargeArray expected = new DoubleLargeArray(2 * numRows * numCols);
final DoubleLargeArray actual = new DoubleLargeArray(2 * numRows * numCols);
for (int i = 0; i < actual.length(); i++) {
final double rnd = random.nextDouble();
actual.setDouble(i, rnd);
expected.setDouble(i, rnd);
}
fft.complexForward(actual);
fft.complexInverse(actual, true);
double rmse = IOUtils.computeRMSE(actual, expected);
Assert.assertEquals(String.format(DEFAULT_MESSAGE, numThreads, numRows, numCols) + ", rmse = " + rmse, 0.0, rmse, EPS);
}
/**
* A test of {@link DoubleFFT_2D#complexInverse(double[][], boolean)}, with
* the second parameter set to <code>true</code>.
*/
@Test
public void testComplexInverseScaled2dInput()
{
final double[][] expected = new double[numRows][2 * numCols];
final double[][] actual = new double[numRows][2 * numCols];
for (int r = 0; r < numRows; r++) {
for (int c = 0; c < 2 * numCols; c++) {
final double rnd = random.nextDouble();
actual[r][c] = rnd;
expected[r][c] = rnd;
}
}
fft.complexForward(actual);
fft.complexInverse(actual, true);
double rmse = IOUtils.computeRMSE(actual, expected);
Assert.assertEquals(String.format(DEFAULT_MESSAGE, numThreads, numRows, numCols) + ", rmse = " + rmse, 0.0, rmse, EPS);
}
/**
* A test of {@link DoubleFFT_2D#complexInverse(double[], boolean)}, with
* the second parameter set to <code>false</code>.
*/
@Test
public void testComplexInverseUnScaled1dInput()
{
final double[] expected = new double[2 * numRows * numCols];
final double[] actual = new double[2 * numRows * numCols];
for (int i = 0; i < actual.length; i++) {
final double rnd = random.nextDouble();
actual[i] = rnd;
expected[i] = rnd;
}
fft.complexForward(actual);
fft.complexInverse(actual, false);
final double s = numRows * numCols;
for (int i = 0; i < actual.length; i++) {
actual[i] = actual[i] / s;
}
double rmse = IOUtils.computeRMSE(actual, expected);
Assert.assertEquals(String.format(DEFAULT_MESSAGE, numThreads, numRows, numCols) + ", rmse = " + rmse, 0.0, rmse, EPS);
}
/**
* A test of {@link DoubleFFT_2D#complexInverse(DoubleLargeArray, boolean)}, with
* the second parameter set to <code>false</code>.
*/
@Test
public void testComplexInverseUnScaledLarge()
{
final DoubleLargeArray expected = new DoubleLargeArray(2 * numRows * numCols);
final DoubleLargeArray actual = new DoubleLargeArray(2 * numRows * numCols);
for (int i = 0; i < actual.length(); i++) {
final double rnd = random.nextDouble();
actual.setDouble(i, rnd);
expected.setDouble(i, rnd);
}
fft.complexForward(actual);
fft.complexInverse(actual, false);
final double s = numRows * numCols;
for (int i = 0; i < actual.length(); i++) {
actual.setDouble(i, actual.getDouble(i) / s);
}
double rmse = IOUtils.computeRMSE(actual, expected);
Assert.assertEquals(String.format(DEFAULT_MESSAGE, numThreads, numRows, numCols) + ", rmse = " + rmse, 0.0, rmse, EPS);
}
/**
* A test of {@link DoubleFFT_2D#complexInverse(double[][], boolean)}, with
* the second parameter set to <code>false</code>.
*/
@Test
public void testComplexInverseUnScaled2dInput()
{
final double[][] expected = new double[numRows][2 * numCols];
final double[][] actual = new double[numRows][2 * numCols];
for (int r = 0; r < numRows; r++) {
for (int c = 0; c < 2 * numCols; c++) {
final double rnd = random.nextDouble();
expected[r][c] = rnd;
actual[r][c] = rnd;
}
}
fft.complexForward(actual);
fft.complexInverse(actual, false);
final double s = numRows * numCols;
for (int r = 0; r < numRows; r++) {
for (int c = 0; c < 2 * numCols; c++) {
actual[r][c] = actual[r][c] / s;
}
}
double rmse = IOUtils.computeRMSE(actual, expected);
Assert.assertEquals(String.format(DEFAULT_MESSAGE, numThreads, numRows, numCols) + ", rmse = " + rmse, 0.0, rmse, EPS);
}
private static void fillSymmetric(final double[] a, int rows, int columns)
{
final int twon2 = 2 * columns;
int idx1, idx2, idx3, idx4;
int n1d2 = rows / 2;
for (int r = (rows - 1); r >= 1; r--) {
idx1 = r * columns;
idx2 = 2 * idx1;
for (int c = 0; c < columns; c += 2) {
a[idx2 + c] = a[idx1 + c];
a[idx1 + c] = 0;
a[idx2 + c + 1] = a[idx1 + c + 1];
a[idx1 + c + 1] = 0;
}
}
for (int r = 1; r < n1d2; r++) {
idx2 = r * twon2;
idx3 = (rows - r) * twon2;
a[idx2 + columns] = a[idx3 + 1];
a[idx2 + columns + 1] = -a[idx3];
}
for (int r = 1; r < n1d2; r++) {
idx2 = r * twon2;
idx3 = (rows - r + 1) * twon2;
for (int c = columns + 2; c < twon2; c += 2) {
a[idx2 + c] = a[idx3 - c];
a[idx2 + c + 1] = -a[idx3 - c + 1];
}
}
for (int r = 0; r <= rows / 2; r++) {
idx1 = r * twon2;
idx4 = ((rows - r) % rows) * twon2;
for (int c = 0; c < twon2; c += 2) {
idx2 = idx1 + c;
idx3 = idx4 + (twon2 - c) % twon2;
a[idx3] = a[idx2];
a[idx3 + 1] = -a[idx2 + 1];
}
}
a[columns] = -a[1];
a[1] = 0;
idx1 = n1d2 * twon2;
a[idx1 + columns] = -a[idx1 + 1];
a[idx1 + 1] = 0;
a[idx1 + columns + 1] = 0;
}
/**
* A test of {@link DoubleFFT_2D#realForward(double[])}.
*/
@Test
public void testRealForward1dInput()
{
if (!CommonUtils.isPowerOf2(numRows)) {
return;
}
if (!CommonUtils.isPowerOf2(numCols)) {
return;
}
final double[] actual = new double[2 * numRows * numCols];
final double[] expected = new double[numRows * 2 * numCols];
for (int r = 0; r < numRows; r++) {
for (int c = 0; c < numCols; c++) {
final double rnd = random.nextDouble();
actual[r * numCols + c] = rnd;
expected[r * 2 * numCols + 2 * c] = rnd;
}
}
fft.realForward(actual);
fft.complexForward(expected);
fillSymmetric(actual, numRows, numCols);
double rmse = IOUtils.computeRMSE(actual, expected);
Assert.assertEquals(String.format(DEFAULT_MESSAGE, numThreads, numRows, numCols) + ", rmse = " + rmse, 0.0, rmse, EPS);
}
private static void fillSymmetric(final DoubleLargeArray a, int rowsl, int columnsl)
{
final long twon2 = 2 * columnsl;
long idx1, idx2, idx3, idx4;
long n1d2 = rowsl / 2;
for (long r = (rowsl - 1); r >= 1; r--) {
idx1 = r * columnsl;
idx2 = 2 * idx1;
for (long c = 0; c < columnsl; c += 2) {
a.setDouble(idx2 + c, a.getDouble(idx1 + c));
a.setDouble(idx1 + c, 0);
a.setDouble(idx2 + c + 1, a.getDouble(idx1 + c + 1));
a.setDouble(idx1 + c + 1, 0);
}
}
for (long r = 1; r < n1d2; r++) {
idx2 = r * twon2;
idx3 = (rowsl - r) * twon2;
a.setDouble(idx2 + columnsl, a.getDouble(idx3 + 1));
a.setDouble(idx2 + columnsl + 1, -a.getDouble(idx3));
}
for (long r = 1; r < n1d2; r++) {
idx2 = r * twon2;
idx3 = (rowsl - r + 1) * twon2;
for (long c = columnsl + 2; c < twon2; c += 2) {
a.setDouble(idx2 + c, a.getDouble(idx3 - c));
a.setDouble(idx2 + c + 1, -a.getDouble(idx3 - c + 1));
}
}
for (long r = 0; r <= rowsl / 2; r++) {
idx1 = r * twon2;
idx4 = ((rowsl - r) % rowsl) * twon2;
for (long c = 0; c < twon2; c += 2) {
idx2 = idx1 + c;
idx3 = idx4 + (twon2 - c) % twon2;
a.setDouble(idx3, a.getDouble(idx2));
a.setDouble(idx3 + 1, -a.getDouble(idx2 + 1));
}
}
a.setDouble(columnsl, -a.getDouble(1));
a.setDouble(1, 0);
idx1 = n1d2 * twon2;
a.setDouble(idx1 + columnsl, -a.getDouble(idx1 + 1));
a.setDouble(idx1 + 1, 0);
a.setDouble(idx1 + columnsl + 1, 0);
}
/**
* A test of {@link DoubleFFT_2D#realForward(DoubleLargeArray)}.
*/
@Test
public void testRealForwardLarge()
{
if (!CommonUtils.isPowerOf2(numRows)) {
return;
}
if (!CommonUtils.isPowerOf2(numCols)) {
return;
}
final DoubleLargeArray actual = new DoubleLargeArray(2 * numRows * numCols);
final DoubleLargeArray expected = new DoubleLargeArray(numRows * 2 * numCols);
for (int r = 0; r < numRows; r++) {
for (int c = 0; c < numCols; c++) {
final double rnd = random.nextDouble();
actual.setDouble(r * numCols + c, rnd);
expected.setDouble(r * 2 * numCols + 2 * c, rnd);
}
}
fft.realForward(actual);
fft.complexForward(expected);
fillSymmetric(actual, numRows, numCols);
double rmse = IOUtils.computeRMSE(actual, expected);
Assert.assertEquals(String.format(DEFAULT_MESSAGE, numThreads, numRows, numCols) + ", rmse = " + rmse, 0.0, rmse, EPS);
}
private void fillSymmetric(final double[][] a, int rows, int columns)
{
final int newn2 = 2 * columns;
int n1d2 = rows / 2;
for (int r = 1; r < n1d2; r++) {
int idx1 = rows - r;
a[r][columns] = a[idx1][1];
a[r][columns + 1] = -a[idx1][0];
}
for (int r = 1; r < n1d2; r++) {
int idx1 = rows - r;
for (int c = columns + 2; c < newn2; c += 2) {
int idx2 = newn2 - c;
a[r][c] = a[idx1][idx2];
a[r][c + 1] = -a[idx1][idx2 + 1];
}
}
for (int r = 0; r <= rows / 2; r++) {
int idx1 = (rows - r) % rows;
for (int c = 0; c < newn2; c += 2) {
int idx2 = (newn2 - c) % newn2;
a[idx1][idx2] = a[r][c];
a[idx1][idx2 + 1] = -a[r][c + 1];
}
}
a[0][columns] = -a[0][1];
a[0][1] = 0;
a[n1d2][columns] = -a[n1d2][1];
a[n1d2][1] = 0;
a[n1d2][columns + 1] = 0;
}
/**
* A test of {@link DoubleFFT_2D#realForward(double[][])}.
*/
@Test
public void testRealForward2dInput()
{
if (!CommonUtils.isPowerOf2(numRows)) {
return;
}
if (!CommonUtils.isPowerOf2(numCols)) {
return;
}
final double[][] actual = new double[numRows][2 * numCols];
final double[][] expected = new double[numRows][2 * numCols];
for (int r = 0; r < numRows; r++) {
for (int c = 0; c < numCols; c++) {
final double rnd = random.nextDouble();
actual[r][c] = rnd;
expected[r][2 * c] = rnd;
expected[r][2 * c + 1] = 0.0;
}
}
fft.realForward(actual);
complexForward(expected);
fillSymmetric(actual, numRows, numCols);
double rmse = IOUtils.computeRMSE(actual, expected);
Assert.assertEquals(String.format(DEFAULT_MESSAGE, numThreads, numRows, numCols) + ", rmse = " + rmse, 0.0, rmse, EPS);
}
/**
* A test of {@link DoubleFFT_2D#realForwardFull(double[])}.
*/
@Test
public void testRealForwardFull1dInput()
{
final double[] actual = new double[2 * numRows * numCols];
final double[][] expected0 = new double[numRows][2 * numCols];
final double[] expected = new double[numRows * 2 * numCols];
for (int r = 0; r < numRows; r++) {
for (int c = 0; c < numCols; c++) {
final double rnd = random.nextDouble();
actual[r * numCols + c] = rnd;
expected0[r][2 * c] = rnd;
}
}
fft.realForwardFull(actual);
complexForward(expected0);
for (int r = 0; r < numRows; r++) {
for (int c = 0; c < 2 * numCols; c++) {
expected[2 * r * numCols + c] = expected0[r][c];
}
}
double rmse = IOUtils.computeRMSE(actual, expected);
Assert.assertEquals(String.format(DEFAULT_MESSAGE, numThreads, numRows, numCols) + ", rmse = " + rmse, 0.0, rmse, EPS);
}
/**
* A test of {@link DoubleFFT_2D#realForwardFull(DoubleLargeArray)}.
*/
@Test
public void testRealForwardFullLarge()
{
final DoubleLargeArray actual = new DoubleLargeArray(2 * numRows * numCols);
final double[][] expected0 = new double[numRows][2 * numCols];
final DoubleLargeArray expected = new DoubleLargeArray(numRows * 2 * numCols);
for (int r = 0; r < numRows; r++) {
for (int c = 0; c < numCols; c++) {
final double rnd = random.nextDouble();
actual.setDouble(r * numCols + c, rnd);
expected0[r][2 * c] = rnd;
}
}
fft.realForwardFull(actual);
complexForward(expected0);
for (int r = 0; r < numRows; r++) {
for (int c = 0; c < 2 * numCols; c++) {
expected.setDouble(2 * r * numCols + c, expected0[r][c]);
}
}
double rmse = IOUtils.computeRMSE(actual, expected);
Assert.assertEquals(String.format(DEFAULT_MESSAGE, numThreads, numRows, numCols) + ", rmse = " + rmse, 0.0, rmse, EPS);
}
/**
* A test of {@link DoubleFFT_2D#realForwardFull(double[][])}.
*/
@Test
public void testRealForwardFull2dInput()
{
final double[][] actual = new double[numRows][2 * numCols];
final double[][] expected = new double[numRows][2 * numCols];
for (int r = 0; r < numRows; r++) {
for (int c = 0; c < numCols; c++) {
final double rnd = random.nextDouble();
actual[r][c] = rnd;
expected[r][2 * c] = rnd;
}
}
fft.realForwardFull(actual);
complexForward(expected);
double rmse = IOUtils.computeRMSE(actual, expected);
Assert.assertEquals(String.format(DEFAULT_MESSAGE, numThreads, numRows, numCols) + ", rmse = " + rmse, 0.0, rmse, EPS);
}
/**
* A test of {@link DoubleFFT_2D#realInverseFull(double[], boolean)}, with
* the second parameter set to <code>true</code>.
*/
@Test
public void testRealInverseFullScaled1dInput()
{
final double[] actual = new double[2 * numRows * numCols];
final double[] expected = new double[2 * numRows * numCols];
for (int r = 0; r < numRows; r++) {
for (int c = 0; c < numCols; c++) {
final double rnd = random.nextDouble();
final int index = r * numCols + c;
actual[index] = rnd;
expected[2 * index] = rnd;
}
}
fft.realInverseFull(actual, true);
fft.complexInverse(expected, true);
double rmse = IOUtils.computeRMSE(actual, expected);
Assert.assertEquals(String.format(DEFAULT_MESSAGE, numThreads, numRows, numCols) + ", rmse = " + rmse, 0.0, rmse, EPS);
}
/**
* A test of {@link DoubleFFT_2D#realInverseFull(DoubleLargeArray, boolean)}, with
* the second parameter set to <code>true</code>.
*/
@Test
public void testRealInverseFullScaledLarge()
{
final DoubleLargeArray actual = new DoubleLargeArray(2 * numRows * numCols);
final DoubleLargeArray expected = new DoubleLargeArray(2 * numRows * numCols);
for (int r = 0; r < numRows; r++) {
for (int c = 0; c < numCols; c++) {
final double rnd = random.nextDouble();
final int index = r * numCols + c;
actual.setDouble(index, rnd);
expected.setDouble(2 * index, rnd);
}
}
fft.complexInverse(expected, true);
fft.realInverseFull(actual, true);
double rmse = IOUtils.computeRMSE(actual, expected);
Assert.assertEquals(String.format(DEFAULT_MESSAGE, numThreads, numRows, numCols) + ", rmse = " + rmse, 0.0, rmse, EPS);
}
/**
* A test of {@link DoubleFFT_2D#realInverseFull(double[][], boolean)}, with
* the second parameter set to <code>true</code>.
*/
@Test
public void testRealInverseFullScaled2dInput()
{
final double[][] actual = new double[numRows][2 * numCols];
final double[][] expected = new double[numRows][2 * numCols];
for (int r = 0; r < numRows; r++) {
for (int c = 0; c < numCols; c++) {
final double rnd = random.nextDouble();
actual[r][c] = rnd;
expected[r][2 * c] = rnd;
}
}
fft.realInverseFull(actual, true);
fft.complexInverse(expected, true);
double rmse = IOUtils.computeRMSE(actual, expected);
Assert.assertEquals(String.format(DEFAULT_MESSAGE, numThreads, numRows, numCols) + ", rmse = " + rmse, 0.0, rmse, EPS);
}
/**
* A test of {@link DoubleFFT_2D#realInverseFull(double[], boolean)}, with
* the second parameter set to <code>false</code>.
*/
@Test
public void testRealInverseFullUnscaled1dInput()
{
final double[] actual = new double[2 * numRows * numCols];
final double[] expected = new double[2 * numRows * numCols];
for (int r = 0; r < numRows; r++) {
for (int c = 0; c < numCols; c++) {
final double rnd = random.nextDouble();
final int index = r * numCols + c;
actual[index] = rnd;
expected[2 * index] = rnd;
}
}
fft.complexInverse(expected, false);
fft.realInverseFull(actual, false);
double rmse = IOUtils.computeRMSE(actual, expected);
Assert.assertEquals(String.format(DEFAULT_MESSAGE, numThreads, numRows, numCols) + ", rmse = " + rmse, 0.0, rmse, EPS);
}
/**
* A test of {@link DoubleFFT_2D#realInverseFull(DoubleLargeArray, boolean)}, with
* the second parameter set to <code>false</code>.
*/
@Test
public void testRealInverseFullUnscaledLarge()
{
final DoubleLargeArray actual = new DoubleLargeArray(2 * numRows * numCols);
final DoubleLargeArray expected = new DoubleLargeArray(2 * numRows * numCols);
for (int r = 0; r < numRows; r++) {
for (int c = 0; c < numCols; c++) {
final double rnd = random.nextDouble();
final int index = r * numCols + c;
actual.set(index, rnd);
expected.setDouble(2 * index, rnd);
}
}
fft.complexInverse(expected, false);
fft.realInverseFull(actual, false);
double rmse = IOUtils.computeRMSE(actual, expected);
Assert.assertEquals(String.format(DEFAULT_MESSAGE, numThreads, numRows, numCols) + ", rmse = " + rmse, 0.0, rmse, EPS);
}
/**
* A test of {@link DoubleFFT_2D#realInverseFull(double[][], boolean)}, with
* the second parameter set to <code>false</code>.
*/
@Test
public void testRealInverseFullUnscaled2dInput()
{
final double[][] actual = new double[numRows][2 * numCols];
final double[][] expected = new double[numRows][2 * numCols];
for (int r = 0; r < numRows; r++) {
for (int c = 0; c < numCols; c++) {
final double rnd = random.nextDouble();
actual[r][c] = rnd;
expected[r][2 * c] = rnd;
}
}
fft.realInverseFull(actual, false);
fft.complexInverse(expected, false);
double rmse = IOUtils.computeRMSE(actual, expected);
Assert.assertEquals(String.format(DEFAULT_MESSAGE, numThreads, numRows, numCols) + ", rmse = " + rmse, 0.0, rmse, EPS);
}
/**
* A test of {@link DoubleFFT_2D#realInverse(double[], boolean)}, with the
* second parameter set to <code>true</code>.
*/
@Test
public void testRealInverseScaled1dInput()
{
if (!CommonUtils.isPowerOf2(numRows)) {
return;
}
if (!CommonUtils.isPowerOf2(numCols)) {
return;
}
final double[] actual = new double[numRows * numCols];
final double[] expected = new double[actual.length];
for (int i = 0; i < actual.length; i++) {
final double rnd = random.nextDouble();
actual[i] = rnd;
expected[i] = rnd;
}
fft.realForward(actual);
fft.realInverse(actual, true);
double rmse = IOUtils.computeRMSE(actual, expected);
Assert.assertEquals(String.format(DEFAULT_MESSAGE, numThreads, numRows, numCols) + ", rmse = " + rmse, 0.0, rmse, EPS);
}
/**
* A test of {@link DoubleFFT_2D#realInverse(DoubleLargeArray, boolean)}, with the
* second parameter set to <code>true</code>.
*/
@Test
public void testRealInverseScaledLarge()
{
if (!CommonUtils.isPowerOf2(numRows)) {
return;
}
if (!CommonUtils.isPowerOf2(numCols)) {
return;
}
final DoubleLargeArray actual = new DoubleLargeArray(numRows * numCols);
final DoubleLargeArray expected = new DoubleLargeArray(actual.length());
for (int i = 0; i < actual.length(); i++) {
final double rnd = random.nextDouble();
actual.setDouble(i, rnd);
expected.setDouble(i, rnd);
}
fft.realForward(actual);
fft.realInverse(actual, true);
double rmse = IOUtils.computeRMSE(actual, expected);
Assert.assertEquals(String.format(DEFAULT_MESSAGE, numThreads, numRows, numCols) + ", rmse = " + rmse, 0.0, rmse, EPS);
}
/**
* A test of {@link DoubleFFT_2D#realInverse(double[][], boolean)}, with the
* second parameter set to <code>true</code>.
*/
@Test
public void testRealInverseScaled2dInput()
{
if (!CommonUtils.isPowerOf2(numRows)) {
return;
}
if (!CommonUtils.isPowerOf2(numCols)) {
return;
}
final double[][] actual = new double[numRows][numCols];
final double[][] expected = new double[numRows][numCols];
for (int r = 0; r < numRows; r++) {
for (int c = 0; c < numCols; c++) {
final double rnd = random.nextDouble();
actual[r][c] = rnd;
expected[r][c] = rnd;
}
}
fft.realForward(actual);
fft.realInverse(actual, true);
double rmse = IOUtils.computeRMSE(actual, expected);
Assert.assertEquals(String.format(DEFAULT_MESSAGE, numThreads, numRows, numCols) + ", rmse = " + rmse, 0.0, rmse, EPS);
}
}