From d30bd730c36c1f787d716c5b982860aaadb72a9c Mon Sep 17 00:00:00 2001 From: Peter Powers <pmpowers@usgs.gov> Date: Thu, 23 Sep 2021 08:44:24 -0600 Subject: [PATCH] interpolator cleanup, tests, and docs --- .../earthquake/nshmp/calc/Disaggregation.java | 2 +- .../earthquake/nshmp/data/Interpolator.java | 90 +++--- .../nshmp/data/InterpolatorTest.java | 185 ------------- .../nshmp/data/InterpolatorTests.java | 256 ++++++++++++++++-- 4 files changed, 285 insertions(+), 248 deletions(-) delete mode 100644 src/test/java/gov/usgs/earthquake/nshmp/data/InterpolatorTest.java diff --git a/src/main/java/gov/usgs/earthquake/nshmp/calc/Disaggregation.java b/src/main/java/gov/usgs/earthquake/nshmp/calc/Disaggregation.java index 7fba75e1..72999c4a 100644 --- a/src/main/java/gov/usgs/earthquake/nshmp/calc/Disaggregation.java +++ b/src/main/java/gov/usgs/earthquake/nshmp/calc/Disaggregation.java @@ -226,7 +226,7 @@ public final class Disaggregation { /* Hazard curves are already in log-x space. */ static final Interpolator IML_INTERPOLATER = Interpolator.builder() .logy() - .decreasingX() + .decreasingY() .build(); /* Hazard curves are already in log-x space. */ diff --git a/src/main/java/gov/usgs/earthquake/nshmp/data/Interpolator.java b/src/main/java/gov/usgs/earthquake/nshmp/data/Interpolator.java index c4fd0b06..c6063740 100644 --- a/src/main/java/gov/usgs/earthquake/nshmp/data/Interpolator.java +++ b/src/main/java/gov/usgs/earthquake/nshmp/data/Interpolator.java @@ -9,19 +9,21 @@ import java.util.List; /** * Utility class to perform linear and log interpolations. The methods of this - * class are designed to be fast and, as such, perform very little argument - * checking for monotonicity and the like. + * class are designed to be fast and perform very little argument checking for + * monotonicity and the like. Results are undefined for x- and y-value arguments + * where {@code size < 2}. * * <p>Making some assumptions, interpolation is fairly straightforward. Most of * the methods implemented here are designed to support interpolation (or - * derivation) of y-values keyed to monotonically increasing x-values. x-value - * interpolation is somewhat thornier. Assumptions and behaviors: + * derivation) of y-values keyed to monotonically increasing x-values. X-value + * interpolation requires knowing if y-values are increasing or decreasing. + * Assumptions and behaviors: * * <ul><li>No error checking for null, empty, single-valued arrays; or arrays of * different lengths is performed. Buyer beware.</li> * * <li>X-value arrays are always assumed to be strictly monotonically ascending - * (no repeated values)</li> + * with no repeated values.</li> * * <li>Internally, binary search is used for y-value interpolation; linear * search is used for x-value interpolation.</li> @@ -29,7 +31,7 @@ import java.util.List; * <li>Y-value interpolation will always extrapolate off the ends a sequence; * this may change, or be configurable, in the future.</li> * - * <li>X-value interpolation is predicated on x-values representing some form of + * <li>X-value interpolation is predicated on y-values representing some form of * cumulative distribution function, either increasing or decreasing * (complementary), and must be specified as such. X-values are assumed to be * increasing by default.</li> @@ -46,20 +48,10 @@ import java.util.List; * all interpolation operations in this class. These two methods are point-order * agnostic. * - * TODO example; explain array swapping techniques for x-interpolation - * * @author U.S. Geological Survey */ public abstract class Interpolator { - /* - * Developer notes: - * - * ------------------------------------------------------------------------- - * Perhaps add extrapolation constraint (on/off) for y value interpolation - * ------------------------------------------------------------------------- - */ - private Interpolator() {} /** @@ -107,11 +99,11 @@ public abstract class Interpolator { * Return an interpolated x-value corresponding to the supplied y-value in the * supplied xy-sequence. * - * @param xys an xy-sequence + * @param xy an xy-sequence * @param y value at which to find x * @return an interpolated x-value */ - public abstract double findX(XySequence xys, double y); + public abstract double findX(XySequence xy, double y); /** * Return an interpolated or extrapolated y-value corresponding to the @@ -157,11 +149,11 @@ public abstract class Interpolator { * Return an interpolated or extrapolated y-value corresponding to the * supplied x-value in the supplied xy-sequence. * - * @param xys an xy-sequence + * @param xy an xy-sequence * @param x value at which to find y * @return an interpolated y-value */ - public abstract double findY(XySequence xys, double x); + public abstract double findY(XySequence xy, double x); /** * Return interpolated or extrapolated y-values using the supplied x- and @@ -189,26 +181,31 @@ public abstract class Interpolator { * Return interpolated or extrapolated y-values using the supplied x- and * y-value arrays. * - * @param xys an xy-sequence + * @param xy an xy-sequence * @param x values at which to find y-values * @return interpolated y-values */ - public abstract double[] findY(XySequence xys, double[] x); + public abstract double[] findY(XySequence xy, double[] x); + /** Create a new builder instance. */ public static Builder builder() { return new Builder(); } + /** + * An interpolator builder. + */ public static final class Builder { private Builder() {} boolean logx = false; boolean logy = false; - boolean xIncreasing = true; + boolean yIncreasing = true; /** - * Indicate that interpolation should be performed in y-value log space. + * Indicate that interpolation should be performed in {@code log(x)} value + * space. */ public Builder logx() { this.logx = true; @@ -216,7 +213,8 @@ public abstract class Interpolator { } /** - * Indicate that interpolation should be performed in y-value log space. + * Indicate that interpolation should be performed in {@code log(y)} value + * space. */ public Builder logy() { this.logy = true; @@ -224,12 +222,13 @@ public abstract class Interpolator { } /** - * Indicate if the x-values to be interpolated are decreasing. In the - * absence of calling this method, x-value are assumed to monotonically - * increasing. This setting has no effect on y-value interpolation. + * Indicate if the y-values to be interpolated decrease monotonically. In + * the absence of calling this method, both x- and y-values are assumed to + * monotonically increase. This setting has no effect on y-value + * interpolation. */ - public Builder decreasingX() { - this.xIncreasing = false; + public Builder decreasingY() { + this.yIncreasing = false; return this; } @@ -237,18 +236,17 @@ public abstract class Interpolator { * Return a newly created {@code Interpolator}. */ public Interpolator build() { - return new RegularInterpolator(logx, logy, xIncreasing); + return new RegularInterpolator(logx, logy, yIncreasing); } - } private static final class RegularInterpolator extends Interpolator { private final InterpolateFn yFunction; private final InterpolateFn xFunction; - private final boolean xIncreasing; + private final boolean yIncreasing; - private RegularInterpolator(boolean logx, boolean logy, boolean xIncreasing) { + private RegularInterpolator(boolean logx, boolean logy, boolean yIncreasing) { if (logx && logy) { xFunction = new XFn_LogX_LogY(); yFunction = new YFn_LogX_LogY(); @@ -262,12 +260,12 @@ public abstract class Interpolator { xFunction = new XFn(); yFunction = new YFn(); } - this.xIncreasing = xIncreasing; + this.yIncreasing = yIncreasing; } @Override public double findX(double[] xs, double[] ys, double y) { - int i = linearIndex(ys, y, xIncreasing); + int i = linearIndex(ys, y, yIncreasing); if (i == -1) { return 0; } @@ -276,7 +274,7 @@ public abstract class Interpolator { @Override public double findX(List<Double> xs, List<Double> ys, double y) { - int i = linearIndex(ys, y, xIncreasing); + int i = linearIndex(ys, y, yIncreasing); if (i == -1) { return 0; } @@ -284,10 +282,10 @@ public abstract class Interpolator { } @Override - public double findX(XySequence xys, double y) { + public double findX(XySequence xy, double y) { // safe covariant cast - ArrayXySequence ixys = (ArrayXySequence) xys; - return findX(ixys.xs, ixys.ys, y); + ArrayXySequence ixy = (ArrayXySequence) xy; + return findX(ixy.xs, ixy.ys, y); } @Override @@ -303,10 +301,10 @@ public abstract class Interpolator { } @Override - public double findY(XySequence xys, double x) { + public double findY(XySequence xy, double x) { // safe covariant cast - ArrayXySequence ixys = (ArrayXySequence) xys; - return findY(ixys.xs, ixys.ys, x); + ArrayXySequence ixy = (ArrayXySequence) xy; + return findY(ixy.xs, ixy.ys, x); } @Override @@ -328,10 +326,10 @@ public abstract class Interpolator { } @Override - public double[] findY(XySequence xys, double[] x) { + public double[] findY(XySequence xy, double[] x) { // safe covariant cast - ArrayXySequence ixys = (ArrayXySequence) xys; - return findY(ixys.xs, ixys.ys, x); + ArrayXySequence ixy = (ArrayXySequence) xy; + return findY(ixy.xs, ixy.ys, x); } } diff --git a/src/test/java/gov/usgs/earthquake/nshmp/data/InterpolatorTest.java b/src/test/java/gov/usgs/earthquake/nshmp/data/InterpolatorTest.java deleted file mode 100644 index d673b21c..00000000 --- a/src/test/java/gov/usgs/earthquake/nshmp/data/InterpolatorTest.java +++ /dev/null @@ -1,185 +0,0 @@ -package gov.usgs.earthquake.nshmp.data; - -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertEquals; - -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.DoubleStream; - -import org.junit.jupiter.api.Test; - -class InterpolatorTest { - - static final double[] X = { 0.01, 0.1, 0.3, 0.5, 0.7, 0.9, 1.0 }; - static final double[] Y = { 1, 0.9, 0.7, 0.5, 0.3, 0.1, 1e-2 }; - - static final List<Double> X_LIST; - static final List<Double> Y_LIST; - - static final XySequence XY_SEQUENCE; - - static final double[] X_TARGET = { 0.01, 0.11, 0.4, 0.5, 0.8, 0.99, 1 }; - static final int[] LOWER_BIN_INDEX = { 0, 1, 2, 3, 4, 5, 5 }; - - // Expected results calculated in Excel - static final double[] Y_TARGET_LINX_LINY = { 1.00, 0.89, 0.60, 0.50, 0.20, 0.019, 0.01 }; - static final double[] Y_TARGET_LOGX_LINY = { - 1.00, 0.882648987129, 0.587365841075, 0.50, 0.193733604125, 0.018585096809, 0.01 }; - static final double[] Y_TARGET_LINX_LOGY = { - 1.00, 0.888761607855, 0.591607978310, 0.50, 0.173205080757, 0.012589254118, 0.01 }; - static final double[] Y_TARGET_LOGX_LOGY = { - 1.00, 0.880589847272, 0.579165919197, 0.50, 0.167344511862, 0.012456325964, 0.01 }; - - static final Interpolator LINEAR_LINEAR_INTERPOLATOR = Interpolator.builder() - .build(); - static final Interpolator LINEAR_LINEAR_DOWN_INTERPOLATOR = Interpolator.builder() - .decreasingX() - .build(); - static final Interpolator LINEAR_LOG_INTERPOLATOR = Interpolator.builder() - .logy() - .build(); - static final Interpolator LOG_LINEAR_INTERPOLATOR = Interpolator.builder() - .logx() - .build(); - static final Interpolator LOG_LOG_INTERPOLATOR = Interpolator.builder() - .logx() - .logy() - .build(); - - static final double TOL = 1e-10; - - static { - assert (X.length == Y.length); - assert (X_TARGET.length == LOWER_BIN_INDEX.length); - assert (X_TARGET.length == Y_TARGET_LINX_LINY.length); - assert (X_TARGET.length == Y_TARGET_LOGX_LINY.length); - assert (X_TARGET.length == Y_TARGET_LINX_LOGY.length); - assert (X_TARGET.length == Y_TARGET_LOGX_LOGY.length); - - X_LIST = DoubleStream.of(X).boxed().collect(Collectors.toCollection(ArrayList::new)); - Y_LIST = DoubleStream.of(Y).boxed().collect(Collectors.toCollection(ArrayList::new)); - XY_SEQUENCE = XySequence.create(X, Y); - } - - @Test - final void testFindX_DoubleDoubleDoubleDoubleDouble() { - for (int i = 0; i < X_TARGET.length; i++) { - int j = LOWER_BIN_INDEX[i]; - int k = j + 1; - double actualX = Interpolator.findX(X[j], Y[j], X[k], Y[k], Y_TARGET_LINX_LINY[i]); - assertEquals(X_TARGET[i], actualX, TOL); - } - } - - @Test - final void testFindY_DoubleDoubleDoubleDoubleDouble() { - for (int i = 0; i < X_TARGET.length; i++) { - int j = LOWER_BIN_INDEX[i]; - int k = j + 1; - double actualY = Interpolator.findY(X[j], Y[j], X[k], Y[k], X_TARGET[i]); - assertEquals(Y_TARGET_LINX_LINY[i], actualY, TOL); - } - } - - @Test - final void testFindX_DoubleArrayDoubleArrayDouble() { - for (int i = 0; i < X_TARGET.length; i++) { - // need to use an interpolator with decreasingX() since we're using the - // same data and swapping X & Y - double actualX = LINEAR_LINEAR_DOWN_INTERPOLATOR.findX(X, Y, Y_TARGET_LINX_LINY[i]); - assertEquals(X_TARGET[i], actualX, TOL); - } - } - - @Test - final void testFindX_ListOfDoubleListOfDoubleDouble() { - for (int i = 0; i < X_TARGET.length; i++) { - // need to use an interpolator with decreasingX() since we're using the - // same data and swapping X & Y - double actualX = LINEAR_LINEAR_DOWN_INTERPOLATOR.findX(X_LIST, Y_LIST, Y_TARGET_LINX_LINY[i]); - assertEquals(X_TARGET[i], actualX, TOL); - } - } - - @Test - final void testFindX_XySequenceDouble() { - for (int i = 0; i < X_TARGET.length; i++) { - // need to use an interpolator with decreasingX() since we're using the - // same data and swapping X & Y - double actualX = LINEAR_LINEAR_DOWN_INTERPOLATOR.findX(XY_SEQUENCE, Y_TARGET_LINX_LINY[i]); - assertEquals(X_TARGET[i], actualX, TOL); - } - } - - @Test - final void testFindY_DoubleArrayDoubleArrayDouble() { - for (int i = 0; i < X_TARGET.length; i++) { - double actualY = LINEAR_LINEAR_INTERPOLATOR.findY(X, Y, X_TARGET[i]); - assertEquals(Y_TARGET_LINX_LINY[i], actualY, TOL); - } - } - - @Test - final void testFindY_ListOfDoubleListOfDoubleDouble() { - for (int i = 0; i < X_TARGET.length; i++) { - double actualY = LINEAR_LINEAR_INTERPOLATOR.findY(X_LIST, Y_LIST, X_TARGET[i]); - assertEquals(Y_TARGET_LINX_LINY[i], actualY, TOL); - } - } - - @Test - final void testFindY_XySequenceDouble() { - for (int i = 0; i < X_TARGET.length; i++) { - double actualY = LINEAR_LINEAR_INTERPOLATOR.findY(XY_SEQUENCE, X_TARGET[i]); - assertEquals(Y_TARGET_LINX_LINY[i], actualY, TOL); - } - } - - @Test - final void testFindY_DoubleArrayDoubleArrayDoubleArray() { - double[] actual = LINEAR_LINEAR_INTERPOLATOR.findY(X, Y, X_TARGET); - assertArrayEquals(Y_TARGET_LINX_LINY, actual, TOL); - - actual = LOG_LINEAR_INTERPOLATOR.findY(X, Y, X_TARGET); - assertArrayEquals(Y_TARGET_LOGX_LINY, actual, TOL); - - actual = LINEAR_LOG_INTERPOLATOR.findY(X, Y, X_TARGET); - assertArrayEquals(Y_TARGET_LINX_LOGY, actual, TOL); - - actual = LOG_LOG_INTERPOLATOR.findY(X, Y, X_TARGET); - assertArrayEquals(Y_TARGET_LOGX_LOGY, actual, TOL); - } - - @Test - final void testFindY_ListOfDoubleListOfDoubleDoubleArray() { - double[] actual = LINEAR_LINEAR_INTERPOLATOR.findY(X_LIST, Y_LIST, X_TARGET); - assertArrayEquals(Y_TARGET_LINX_LINY, actual, TOL); - - actual = LOG_LINEAR_INTERPOLATOR.findY(X_LIST, Y_LIST, X_TARGET); - assertArrayEquals(Y_TARGET_LOGX_LINY, actual, TOL); - - actual = LINEAR_LOG_INTERPOLATOR.findY(X_LIST, Y_LIST, X_TARGET); - assertArrayEquals(Y_TARGET_LINX_LOGY, actual, TOL); - - actual = LOG_LOG_INTERPOLATOR.findY(X_LIST, Y_LIST, X_TARGET); - assertArrayEquals(Y_TARGET_LOGX_LOGY, actual, TOL); - } - - @Test - final void testFindY_XySequenceDoubleArray() { - double[] actual = LINEAR_LINEAR_INTERPOLATOR.findY(XY_SEQUENCE, X_TARGET); - assertArrayEquals(Y_TARGET_LINX_LINY, actual, TOL); - - actual = LOG_LINEAR_INTERPOLATOR.findY(XY_SEQUENCE, X_TARGET); - assertArrayEquals(Y_TARGET_LOGX_LINY, actual, TOL); - - actual = LINEAR_LOG_INTERPOLATOR.findY(XY_SEQUENCE, X_TARGET); - assertArrayEquals(Y_TARGET_LINX_LOGY, actual, TOL); - - actual = LOG_LOG_INTERPOLATOR.findY(XY_SEQUENCE, X_TARGET); - assertArrayEquals(Y_TARGET_LOGX_LOGY, actual, TOL); - } - -} diff --git a/src/test/java/gov/usgs/earthquake/nshmp/data/InterpolatorTests.java b/src/test/java/gov/usgs/earthquake/nshmp/data/InterpolatorTests.java index 33c2fe0b..2df2af71 100644 --- a/src/test/java/gov/usgs/earthquake/nshmp/data/InterpolatorTests.java +++ b/src/test/java/gov/usgs/earthquake/nshmp/data/InterpolatorTests.java @@ -1,22 +1,246 @@ package gov.usgs.earthquake.nshmp.data; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.DoubleStream; + +import org.junit.jupiter.api.Test; + +import com.google.common.primitives.Doubles; + class InterpolatorTests { - /* - * Developer notes: - * - * How are single valued XySequences handled; should empty XySequences be - * allowed, probably not; singletons should be however; so how would this - * behave in interpolator if extrapolation is allowed for y-interpolation; - * answer: singletons shouldn't be allowed as arguments; it's just simpler - * - * add checkArgument(xys.size() > 1), test with XySeq.size = 1; add to docs - */ - - // @Test - // public void test() { - // - // fail("Not yet implemented"); - // } + static final double[] X = { 0.01, 0.1, 0.3, 0.5, 0.7, 0.9, 1.0 }; + static final double[] Y = { 1, 0.9, 0.7, 0.5, 0.3, 0.1, 1e-2 }; + + static final List<Double> X_LIST; + static final List<Double> Y_LIST; + + static final XySequence XY_SEQUENCE; + + static final double[] X_TARGET = { 0.01, 0.11, 0.4, 0.5, 0.8, 0.99, 1 }; + static final int[] LOWER_BIN_INDEX = { 0, 1, 2, 3, 4, 5, 5 }; + + // Expected results calculated in Excel + static final double[] Y_TARGET_LINX_LINY = { 1.00, 0.89, 0.60, 0.50, 0.20, 0.019, 0.01 }; + static final double[] Y_TARGET_LOGX_LINY = { + 1.00, 0.882648987129, 0.587365841075, 0.50, 0.193733604125, 0.018585096809, 0.01 }; + static final double[] Y_TARGET_LINX_LOGY = { + 1.00, 0.888761607855, 0.591607978310, 0.50, 0.173205080757, 0.012589254118, 0.01 }; + static final double[] Y_TARGET_LOGX_LOGY = { + 1.00, 0.880589847272, 0.579165919197, 0.50, 0.167344511862, 0.012456325964, 0.01 }; + + static final Interpolator LINEAR_LINEAR_INTERPOLATOR = Interpolator.builder() + .build(); + static final Interpolator LINEAR_LINEAR_DOWN_INTERPOLATOR = Interpolator.builder() + .decreasingY() + .build(); + static final Interpolator LINEAR_LOG_INTERPOLATOR = Interpolator.builder() + .logy() + .build(); + static final Interpolator LOG_LINEAR_INTERPOLATOR = Interpolator.builder() + .logx() + .build(); + static final Interpolator LOG_LOG_INTERPOLATOR = Interpolator.builder() + .logx() + .logy() + .build(); + + static final double TOL = 1e-10; + + static { + assert (X.length == Y.length); + assert (X_TARGET.length == LOWER_BIN_INDEX.length); + assert (X_TARGET.length == Y_TARGET_LINX_LINY.length); + assert (X_TARGET.length == Y_TARGET_LOGX_LINY.length); + assert (X_TARGET.length == Y_TARGET_LINX_LOGY.length); + assert (X_TARGET.length == Y_TARGET_LOGX_LOGY.length); + + X_LIST = DoubleStream.of(X).boxed().collect(Collectors.toCollection(ArrayList::new)); + Y_LIST = DoubleStream.of(Y).boxed().collect(Collectors.toCollection(ArrayList::new)); + XY_SEQUENCE = XySequence.create(X, Y); + } + + @Test + final void testFindX_DoubleDoubleDoubleDoubleDouble() { + for (int i = 0; i < X_TARGET.length; i++) { + int j = LOWER_BIN_INDEX[i]; + int k = j + 1; + double actualX = Interpolator.findX(X[j], Y[j], X[k], Y[k], Y_TARGET_LINX_LINY[i]); + assertEquals(X_TARGET[i], actualX, TOL); + } + } + + @Test + final void testFindY_DoubleDoubleDoubleDoubleDouble() { + for (int i = 0; i < X_TARGET.length; i++) { + int j = LOWER_BIN_INDEX[i]; + int k = j + 1; + double actualY = Interpolator.findY(X[j], Y[j], X[k], Y[k], X_TARGET[i]); + assertEquals(Y_TARGET_LINX_LINY[i], actualY, TOL); + } + } + + @Test + final void testFindX_DoubleArrayDoubleArrayDouble() { + for (int i = 0; i < X_TARGET.length; i++) { + // need to use an interpolator with decreasingY() since we're using the + // same data and swapping X & Y + double actualX = LINEAR_LINEAR_DOWN_INTERPOLATOR.findX(X, Y, Y_TARGET_LINX_LINY[i]); + assertEquals(X_TARGET[i], actualX, TOL); + } + } + + @Test + final void testFindX_ListOfDoubleListOfDoubleDouble() { + for (int i = 0; i < X_TARGET.length; i++) { + // need to use an interpolator with decreasingY() since we're using the + // same data and swapping X & Y + double actualX = LINEAR_LINEAR_DOWN_INTERPOLATOR.findX(X_LIST, Y_LIST, Y_TARGET_LINX_LINY[i]); + assertEquals(X_TARGET[i], actualX, TOL); + } + } + + @Test + final void testFindX_XySequenceDouble() { + for (int i = 0; i < X_TARGET.length; i++) { + // need to use an interpolator with decreasingY() since we're using the + // same data and swapping X & Y + double actualX = LINEAR_LINEAR_DOWN_INTERPOLATOR.findX(XY_SEQUENCE, Y_TARGET_LINX_LINY[i]); + assertEquals(X_TARGET[i], actualX, TOL); + } + } + + @Test + final void testFindY_DoubleArrayDoubleArrayDouble() { + for (int i = 0; i < X_TARGET.length; i++) { + double actualY = LINEAR_LINEAR_INTERPOLATOR.findY(X, Y, X_TARGET[i]); + assertEquals(Y_TARGET_LINX_LINY[i], actualY, TOL); + } + } + + @Test + final void testFindY_ListOfDoubleListOfDoubleDouble() { + for (int i = 0; i < X_TARGET.length; i++) { + double actualY = LINEAR_LINEAR_INTERPOLATOR.findY(X_LIST, Y_LIST, X_TARGET[i]); + assertEquals(Y_TARGET_LINX_LINY[i], actualY, TOL); + } + } + + @Test + final void testFindY_XySequenceDouble() { + for (int i = 0; i < X_TARGET.length; i++) { + double actualY = LINEAR_LINEAR_INTERPOLATOR.findY(XY_SEQUENCE, X_TARGET[i]); + assertEquals(Y_TARGET_LINX_LINY[i], actualY, TOL); + } + } + + @Test + final void testFindXin_DoubleArrayDoubleArrayDoubleArray() { + + double[] xs = { 1, 2, 3 }; + double[] ys = { 0.2, 0.5, 0.8 }; + + /* Missing coverage for findX functions (XFn) */ + + double expected = 1.259921049894; + double actual = LOG_LINEAR_INTERPOLATOR.findX(xs, ys, 0.3); + assertEquals(expected, actual, TOL); + + expected = 1.442507049349; + actual = LINEAR_LOG_INTERPOLATOR.findX(xs, ys, 0.3); + assertEquals(expected, actual, TOL); + + expected = 1.358963821816; + actual = LOG_LOG_INTERPOLATOR.findX(xs, ys, 0.3); + assertEquals(expected, actual, TOL); + } + + @Test + final void testFindY_DoubleArrayDoubleArrayDoubleArray() { + double[] actual = LINEAR_LINEAR_INTERPOLATOR.findY(X, Y, X_TARGET); + assertArrayEquals(Y_TARGET_LINX_LINY, actual, TOL); + + actual = LOG_LINEAR_INTERPOLATOR.findY(X, Y, X_TARGET); + assertArrayEquals(Y_TARGET_LOGX_LINY, actual, TOL); + + actual = LINEAR_LOG_INTERPOLATOR.findY(X, Y, X_TARGET); + assertArrayEquals(Y_TARGET_LINX_LOGY, actual, TOL); + + actual = LOG_LOG_INTERPOLATOR.findY(X, Y, X_TARGET); + assertArrayEquals(Y_TARGET_LOGX_LOGY, actual, TOL); + } + + @Test + final void testFindY_ListOfDoubleListOfDoubleDoubleArray() { + double[] actual = LINEAR_LINEAR_INTERPOLATOR.findY(X_LIST, Y_LIST, X_TARGET); + assertArrayEquals(Y_TARGET_LINX_LINY, actual, TOL); + + actual = LOG_LINEAR_INTERPOLATOR.findY(X_LIST, Y_LIST, X_TARGET); + assertArrayEquals(Y_TARGET_LOGX_LINY, actual, TOL); + + actual = LINEAR_LOG_INTERPOLATOR.findY(X_LIST, Y_LIST, X_TARGET); + assertArrayEquals(Y_TARGET_LINX_LOGY, actual, TOL); + + actual = LOG_LOG_INTERPOLATOR.findY(X_LIST, Y_LIST, X_TARGET); + assertArrayEquals(Y_TARGET_LOGX_LOGY, actual, TOL); + } + + @Test + final void testFindY_XySequenceDoubleArray() { + double[] actual = LINEAR_LINEAR_INTERPOLATOR.findY(XY_SEQUENCE, X_TARGET); + assertArrayEquals(Y_TARGET_LINX_LINY, actual, TOL); + + actual = LOG_LINEAR_INTERPOLATOR.findY(XY_SEQUENCE, X_TARGET); + assertArrayEquals(Y_TARGET_LOGX_LINY, actual, TOL); + + actual = LINEAR_LOG_INTERPOLATOR.findY(XY_SEQUENCE, X_TARGET); + assertArrayEquals(Y_TARGET_LINX_LOGY, actual, TOL); + + actual = LOG_LOG_INTERPOLATOR.findY(XY_SEQUENCE, X_TARGET); + assertArrayEquals(Y_TARGET_LOGX_LOGY, actual, TOL); + } + + /* Errors and Edge Cases */ + @Test + final void testErrorsAndEdgeCases() { + + double[] xs = { 2, 3, 4 }; + double[] ys = { 0.2, 0.5, 0.8 }; + Interpolator interp = Interpolator.builder().build(); + + /* linear index */ + + double yBelow = 0.1; + double yAbove = 0.9; + + // out of range below + double actual = interp.findX(xs, ys, yBelow); + assertEquals(0.0, actual, 0.0); + actual = interp.findX( + Doubles.asList(xs), + Doubles.asList(ys), yBelow); + assertEquals(0.0, actual, 0.0); + + // out of range above + actual = interp.findX(xs, ys, yAbove); + assertEquals(0.0, actual, 0.0); + actual = interp.findX( + Doubles.asList(xs), + Doubles.asList(ys), yAbove); + assertEquals(0.0, actual, 0.0); + + /* binary index */ + + // out of range below + double xBelow = 1.0; + actual = interp.findY(xs, ys, xBelow); + assertEquals(-0.1, actual, TOL); + + } } -- GitLab