You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by ah...@apache.org on 2022/06/07 14:19:17 UTC

[commons-math] 02/03: Fix FFT Test to use the expected imaginary result for relative error

This is an automated email from the ASF dual-hosted git repository.

aherbert pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-math.git

commit 9293da2a06dc65ab5261486688159242552a9ea8
Author: aherbert <ah...@apache.org>
AuthorDate: Tue Jun 7 14:24:41 2022 +0100

    Fix FFT Test to use the expected imaginary result for relative error
    
    Update to JUnit 5 Assertions.
    
    Add absolute tolerance check in addition to relative tolerance.
    
    Use Precision for equality checks.
    
    Add relative/abs error in the assertion failure message.
---
 .../transform/FastFourierTransformerTest.java      | 212 ++++++++++-----------
 .../checkstyle/checkstyle-suppressions.xml         |   1 +
 2 files changed, 100 insertions(+), 113 deletions(-)

diff --git a/commons-math-transform/src/test/java/org/apache/commons/math4/transform/FastFourierTransformerTest.java b/commons-math-transform/src/test/java/org/apache/commons/math4/transform/FastFourierTransformerTest.java
index d4d31bc11..1f746aa12 100644
--- a/commons-math-transform/src/test/java/org/apache/commons/math4/transform/FastFourierTransformerTest.java
+++ b/commons-math-transform/src/test/java/org/apache/commons/math4/transform/FastFourierTransformerTest.java
@@ -17,14 +17,13 @@
 package org.apache.commons.math4.transform;
 
 import java.util.function.DoubleUnaryOperator;
-
-import org.junit.Assert;
+import java.util.function.Supplier;
 import org.junit.Test;
-
+import org.junit.jupiter.api.Assertions;
 import org.apache.commons.rng.UniformRandomProvider;
 import org.apache.commons.rng.simple.RandomSource;
 import org.apache.commons.numbers.complex.Complex;
-
+import org.apache.commons.numbers.core.Precision;
 import org.apache.commons.math3.analysis.UnivariateFunction;
 import org.apache.commons.math3.analysis.function.Sin;
 import org.apache.commons.math3.analysis.function.Sinc;
@@ -42,23 +41,20 @@ public final class FastFourierTransformerTest {
     /** RNG. */
     private static final UniformRandomProvider RNG = RandomSource.MWC_256.create();
 
+    /** Minimum relative error epsilon. Can be used a small absolute delta epsilon. */
+    private static final double EPSILON = Math.ulp(1.0);
+
     // Precondition checks.
 
     @Test
     public void testTransformComplexSizeNotAPowerOfTwo() {
         final int n = 127;
         final Complex[] x = createComplexData(n);
-        final FastFourierTransform.Norm[] norm = FastFourierTransform.Norm.values();
-        for (int i = 0; i < norm.length; i++) {
+        for (FastFourierTransform.Norm norm : FastFourierTransform.Norm.values()) {
             for (boolean type : new boolean[] {true, false}) {
-                final FastFourierTransform fft = new FastFourierTransform(norm[i], type);
-                try {
-                    fft.apply(x);
-                    Assert.fail(norm[i] + ", " + type +
-                        ": IllegalArgumentException was expected");
-                } catch (IllegalArgumentException e) {
-                    // Expected behaviour
-                }
+                final FastFourierTransform fft = new FastFourierTransform(norm, type);
+                Assertions.assertThrows(IllegalArgumentException.class, () -> fft.apply(x),
+                    () -> norm + ", " + type);
             }
         }
     }
@@ -67,17 +63,11 @@ public final class FastFourierTransformerTest {
     public void testTransformRealSizeNotAPowerOfTwo() {
         final int n = 127;
         final double[] x = createRealData(n);
-        final FastFourierTransform.Norm[] norm = FastFourierTransform.Norm.values();
-        for (int i = 0; i < norm.length; i++) {
+        for (FastFourierTransform.Norm norm : FastFourierTransform.Norm.values()) {
             for (boolean type : new boolean[] {true, false}) {
-                final FastFourierTransform fft = new FastFourierTransform(norm[i], type);
-                try {
-                    fft.apply(x);
-                    Assert.fail(norm[i] + ", " + type +
-                        ": IllegalArgumentException was expected");
-                } catch (IllegalArgumentException e) {
-                    // Expected behaviour
-                }
+                final FastFourierTransform fft = new FastFourierTransform(norm, type);
+                Assertions.assertThrows(IllegalArgumentException.class, () -> fft.apply(x),
+                    () -> norm + ", " + type);
             }
         }
     }
@@ -85,17 +75,11 @@ public final class FastFourierTransformerTest {
     @Test
     public void testTransformFunctionSizeNotAPowerOfTwo() {
         final int n = 127;
-        final FastFourierTransform.Norm[] norm = FastFourierTransform.Norm.values();
-        for (int i = 0; i < norm.length; i++) {
+        for (FastFourierTransform.Norm norm : FastFourierTransform.Norm.values()) {
             for (boolean type : new boolean[] {true, false}) {
-                final FastFourierTransform fft = new FastFourierTransform(norm[i], type);
-                try {
-                    fft.apply(SIN, 0.0, Math.PI, n);
-                    Assert.fail(norm[i] + ", " + type +
-                        ": IllegalArgumentException was expected");
-                } catch (IllegalArgumentException e) {
-                    // Expected behaviour
-                }
+                final FastFourierTransform fft = new FastFourierTransform(norm, type);
+                Assertions.assertThrows(IllegalArgumentException.class, () -> fft.apply(SIN, 0.0, Math.PI, n),
+                    () -> norm + ", " + type);
             }
         }
     }
@@ -103,18 +87,11 @@ public final class FastFourierTransformerTest {
     @Test
     public void testTransformFunctionNotStrictlyPositiveNumberOfSamples() {
         final int n = -128;
-        final FastFourierTransform.Norm[] norm = FastFourierTransform.Norm.values();
-        for (int i = 0; i < norm.length; i++) {
+        for (FastFourierTransform.Norm norm : FastFourierTransform.Norm.values()) {
             for (boolean type : new boolean[] {true, false}) {
-                final FastFourierTransform fft = new FastFourierTransform(norm[i], type);
-                try {
-                    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
-                }
+                final FastFourierTransform fft = new FastFourierTransform(norm, type);
+                Assertions.assertThrows(IllegalArgumentException.class, () -> fft.apply(SIN, 0.0, Math.PI, n),
+                    () -> norm + ", " + type);
             }
         }
     }
@@ -122,17 +99,11 @@ public final class FastFourierTransformerTest {
     @Test
     public void testTransformFunctionInvalidBounds() {
         final int n = 128;
-        final FastFourierTransform.Norm[] norm = FastFourierTransform.Norm.values();
-        for (int i = 0; i < norm.length; i++) {
+        for (FastFourierTransform.Norm norm : FastFourierTransform.Norm.values()) {
             for (boolean type : new boolean[] {true, false}) {
-                final FastFourierTransform fft = new FastFourierTransform(norm[i], type);
-                try {
-                    fft.apply(SIN, Math.PI, 0.0, n);
-                    Assert.fail(norm[i] + ", " + type +
-                        ": IllegalArgumentException was expected");
-                } catch (IllegalArgumentException e) {
-                    // Expected behaviour
-                }
+                final FastFourierTransform fft = new FastFourierTransform(norm, type);
+                Assertions.assertThrows(IllegalArgumentException.class, () -> fft.apply(SIN, Math.PI, 0.0, n),
+                    () -> norm + ", " + type);
             }
         }
     }
@@ -187,6 +158,7 @@ public final class FastFourierTransformerTest {
 
     private static void doTestTransformComplex(final int n,
                                                final double tol,
+                                               final double absTol,
                                                final FastFourierTransform.Norm normalization,
                                                boolean inverse) {
         final FastFourierTransform fft = new FastFourierTransform(normalization, inverse);
@@ -210,19 +182,19 @@ public final class FastFourierTransformerTest {
         }
         final Complex[] actual = fft.apply(x);
         for (int i = 0; i < n; i++) {
-            final String msg;
-            msg = String.format("%s, %s, %d, %d", normalization, inverse, n, i);
+            final int index = i;
             final double re = s * expected[i].getReal();
-            Assert.assertEquals(msg, re, actual[i].getReal(),
-                                tol * Math.abs(re));
+            assertEqualsRelativeOrAbsolute(re, actual[i].getReal(), tol, absTol,
+                () -> String.format("%s, %s, %d, %d", normalization, inverse, n, index));
             final double im = s * expected[i].getImaginary();
-            Assert.assertEquals(msg, im, actual[i].getImaginary(),
-                                tol * Math.abs(re));
+            assertEqualsRelativeOrAbsolute(im, actual[i].getImaginary(), tol, absTol,
+                () -> String.format("%s, %s, %d, %d", normalization, inverse, n, index));
         }
     }
 
     private static void doTestTransformReal(final int n,
                                             final double tol,
+                                            final double absTol,
                                             final FastFourierTransform.Norm normalization,
                                             final boolean inverse) {
         final FastFourierTransform fft = new FastFourierTransform(normalization, inverse);
@@ -250,14 +222,13 @@ public final class FastFourierTransformerTest {
         }
         final Complex[] actual = fft.apply(x);
         for (int i = 0; i < n; i++) {
-            final String msg;
-            msg = String.format("%s, %s, %d, %d", normalization, inverse, n, i);
+            final int index = i;
             final double re = s * expected[i].getReal();
-            Assert.assertEquals(msg, re, actual[i].getReal(),
-                                tol * Math.abs(re));
+            assertEqualsRelativeOrAbsolute(re, actual[i].getReal(), tol, absTol,
+                () -> String.format("%s, %s, %d, %d", normalization, inverse, n, index));
             final double im = s * expected[i].getImaginary();
-            Assert.assertEquals(msg, im, actual[i].getImaginary(),
-                                tol * Math.abs(re));
+            assertEqualsRelativeOrAbsolute(im, actual[i].getImaginary(), tol, absTol,
+                () -> String.format("%s, %s, %d, %d", normalization, inverse, n, index));
         }
     }
 
@@ -266,6 +237,7 @@ public final class FastFourierTransformerTest {
                                                 final double max,
                                                 int n,
                                                 final double tol,
+                                                final double absTol,
                                                 final FastFourierTransform.Norm normalization,
                                                 final boolean inverse) {
         final FastFourierTransform fft = new FastFourierTransform(normalization, inverse);
@@ -293,13 +265,27 @@ public final class FastFourierTransformerTest {
         }
         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 int index = i;
             final double re = s * expected[i].getReal();
-            Assert.assertEquals(msg, re, actual[i].getReal(),
-                                tol * Math.abs(re));
+            assertEqualsRelativeOrAbsolute(re, actual[i].getReal(), tol, absTol,
+                () -> String.format("%s, %s, %d, %d", normalization, inverse, n, index));
             final double im = s * expected[i].getImaginary();
-            Assert.assertEquals(msg, im, actual[i].getImaginary(),
-                                tol * Math.abs(re));
+            assertEqualsRelativeOrAbsolute(im, actual[i].getImaginary(), tol, absTol,
+                () -> String.format("%s, %s, %d, %d", normalization, inverse, n, index));
+        }
+    }
+
+    private static void assertEqualsRelativeOrAbsolute(double expected, double actual,
+            double relativeTolerance, double absoluteTolerance, Supplier<String> msg) {
+        if (!(Precision.equals(expected, actual, absoluteTolerance) ||
+              Precision.equalsWithRelativeTolerance(expected, actual, relativeTolerance))) {
+            // Custom supplier to provide relative and absolute error
+            final double absoluteMax = Math.max(Math.abs(expected), Math.abs(actual));
+            final double abs = Math.abs(expected - actual);
+            final double rel = abs / absoluteMax;
+            final Supplier<String> message = () -> String.format("%s: rel=%s, abs=%s", msg.get(), rel, abs);
+            // Re-use assertEquals to obtain the formatting
+            Assertions.assertEquals(expected, actual, message);
         }
     }
 
@@ -310,13 +296,13 @@ public final class FastFourierTransformerTest {
         final FastFourierTransform.Norm[] norm = FastFourierTransform.Norm.values();
         for (int i = 0; i < norm.length; i++) {
             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-12, norm[i], type);
-                doTestTransformComplex(64, 1e-11, norm[i], type);
-                doTestTransformComplex(128, 1e-11, norm[i], type);
+                doTestTransformComplex(2, 1e-15, EPSILON, norm[i], type);
+                doTestTransformComplex(4, 1e-14, EPSILON, norm[i], type);
+                doTestTransformComplex(8, 1e-13, EPSILON, norm[i], type);
+                doTestTransformComplex(16, 1e-13, EPSILON, norm[i], type);
+                doTestTransformComplex(32, 1e-12, EPSILON, norm[i], type);
+                doTestTransformComplex(64, 1e-11, EPSILON, norm[i], type);
+                doTestTransformComplex(128, 1e-11, EPSILON, norm[i], type);
             }
         }
     }
@@ -326,13 +312,13 @@ public final class FastFourierTransformerTest {
         final FastFourierTransform.Norm[] norm = FastFourierTransform.Norm.values();
         for (int i = 0; i < norm.length; i++) {
             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);
+                doTestTransformReal(2, 1e-15, EPSILON, norm[i], type);
+                doTestTransformReal(4, 1e-14, EPSILON, norm[i], type);
+                doTestTransformReal(8, 1e-13, 2 * EPSILON, norm[i], type);
+                doTestTransformReal(16, 1e-13, 2 * EPSILON, norm[i], type);
+                doTestTransformReal(32, 1e-12, 4 * EPSILON, norm[i], type);
+                doTestTransformReal(64, 1e-12, 4 * EPSILON, norm[i], type);
+                doTestTransformReal(128, 1e-11, 8 * EPSILON, norm[i], type);
             }
         }
     }
@@ -348,13 +334,13 @@ public final class FastFourierTransformerTest {
 
         for (int i = 0; i < norm.length; i++) {
             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);
+                doTestTransformFunction(f, min, max, 2, 1e-15, 4 * EPSILON, norm[i], type);
+                doTestTransformFunction(f, min, max, 4, 1e-14, 4 * EPSILON, norm[i], type);
+                doTestTransformFunction(f, min, max, 8, 1e-14, 4 * EPSILON, norm[i], type);
+                doTestTransformFunction(f, min, max, 16, 1e-13, 4 * EPSILON, norm[i], type);
+                doTestTransformFunction(f, min, max, 32, 1e-13, 8 * EPSILON, norm[i], type);
+                doTestTransformFunction(f, min, max, 64, 1e-12, 16 * EPSILON, norm[i], type);
+                doTestTransformFunction(f, min, max, 128, 1e-11, 64 * EPSILON, norm[i], type);
             }
         }
     }
@@ -384,15 +370,15 @@ public final class FastFourierTransformerTest {
         transformer = new FastFourierTransform(FastFourierTransform.Norm.STD);
         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);
+            Assertions.assertEquals(y[i].getReal(), result[i].getReal(), tolerance);
+            Assertions.assertEquals(y[i].getImaginary(), result[i].getImaginary(), tolerance);
         }
 
         transformer = new FastFourierTransform(FastFourierTransform.Norm.STD, 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);
+            Assertions.assertEquals(x[i], result[i].getReal(), tolerance);
+            Assertions.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};
@@ -402,15 +388,15 @@ public final class FastFourierTransformerTest {
         transformer = new FastFourierTransform(FastFourierTransform.Norm.UNIT);
         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);
+            Assertions.assertEquals(x2[i], result[i].getReal(), tolerance);
+            Assertions.assertEquals(0.0, result[i].getImaginary(), tolerance);
         }
 
         transformer = new FastFourierTransform(FastFourierTransform.Norm.UNIT, 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);
+            Assertions.assertEquals(y2[i].getReal(), result[i].getReal(), tolerance);
+            Assertions.assertEquals(y2[i].getImaginary(), result[i].getImaginary(), tolerance);
         }
     }
 
@@ -428,26 +414,26 @@ public final class FastFourierTransformerTest {
         double max = 2 * Math.PI;
         transformer = new FastFourierTransform(FastFourierTransform.Norm.STD);
         result = transformer.apply(SIN, min, max, size);
-        Assert.assertEquals(0.0, result[1].getReal(), tolerance);
-        Assert.assertEquals(-(size >> 1), result[1].getImaginary(), tolerance);
-        Assert.assertEquals(0.0, result[size - 1].getReal(), tolerance);
-        Assert.assertEquals(size >> 1, result[size - 1].getImaginary(), tolerance);
+        Assertions.assertEquals(0.0, result[1].getReal(), tolerance);
+        Assertions.assertEquals(-(size >> 1), result[1].getImaginary(), tolerance);
+        Assertions.assertEquals(0.0, result[size - 1].getReal(), tolerance);
+        Assertions.assertEquals(size >> 1, result[size - 1].getImaginary(), tolerance);
         for (int i = 0; i < size - 1; i += i == 0 ? 2 : 1) {
-            Assert.assertEquals(0.0, result[i].getReal(), tolerance);
-            Assert.assertEquals(0.0, result[i].getImaginary(), tolerance);
+            Assertions.assertEquals(0.0, result[i].getReal(), tolerance);
+            Assertions.assertEquals(0.0, result[i].getImaginary(), tolerance);
         }
 
         min = -Math.PI;
         max = Math.PI;
         transformer = new FastFourierTransform(FastFourierTransform.Norm.STD, true);
         result = transformer.apply(SIN, min, max, size);
-        Assert.assertEquals(0.0, result[1].getReal(), tolerance);
-        Assert.assertEquals(-0.5, result[1].getImaginary(), tolerance);
-        Assert.assertEquals(0.0, result[size - 1].getReal(), tolerance);
-        Assert.assertEquals(0.5, result[size - 1].getImaginary(), tolerance);
+        Assertions.assertEquals(0.0, result[1].getReal(), tolerance);
+        Assertions.assertEquals(-0.5, result[1].getImaginary(), tolerance);
+        Assertions.assertEquals(0.0, result[size - 1].getReal(), tolerance);
+        Assertions.assertEquals(0.5, result[size - 1].getImaginary(), tolerance);
         for (int i = 0; i < size - 1; i += i == 0 ? 2 : 1) {
-            Assert.assertEquals(0.0, result[i].getReal(), tolerance);
-            Assert.assertEquals(0.0, result[i].getImaginary(), tolerance);
+            Assertions.assertEquals(0.0, result[i].getReal(), tolerance);
+            Assertions.assertEquals(0.0, result[i].getImaginary(), tolerance);
         }
     }
 }
diff --git a/src/main/resources/checkstyle/checkstyle-suppressions.xml b/src/main/resources/checkstyle/checkstyle-suppressions.xml
index 1e5855989..6590336f9 100644
--- a/src/main/resources/checkstyle/checkstyle-suppressions.xml
+++ b/src/main/resources/checkstyle/checkstyle-suppressions.xml
@@ -47,4 +47,5 @@
   <suppress checks="MethodLength" files=".*/Dfp.*Test.java" />
   <suppress checks="MethodLength" files=".*[/\\]AccurateMathTest\.java" />
   <suppress checks="LocalFinalVariableName" files=".*[/\\]AccurateMathTest\.java" />
+  <suppress checks="ParameterNumber" files=".*[/\\]FastFourierTransformerTest\.java" />
 </suppressions>