From 8caf8fa7fd38103699c0ce42b6a667e6af169c36 Mon Sep 17 00:00:00 2001
From: Peter Powers <pmpowers@usgs.gov>
Date: Wed, 22 Sep 2021 17:24:43 -0600
Subject: [PATCH] additional sequences class tests

---
 .../usgs/earthquake/nshmp/data/Sequences.java | 36 +++-----
 .../earthquake/nshmp/data/SequencesTests.java | 84 +++++++++++++++++++
 2 files changed, 95 insertions(+), 25 deletions(-)

diff --git a/src/main/java/gov/usgs/earthquake/nshmp/data/Sequences.java b/src/main/java/gov/usgs/earthquake/nshmp/data/Sequences.java
index 023cd033..a5acd173 100644
--- a/src/main/java/gov/usgs/earthquake/nshmp/data/Sequences.java
+++ b/src/main/java/gov/usgs/earthquake/nshmp/data/Sequences.java
@@ -20,6 +20,10 @@ public class Sequences {
 
   private Sequences() {}
 
+  /**
+   * Check that the supplied arrays are not empty, are the same size, and that
+   * the supplied xs increase monotonically.
+   */
   static void validateArrays(double[] xs, double[] ys) {
     checkArgument(xs.length > 0, "x-values may not be empty");
     checkArgument(xs.length == ys.length, "x- and y-values are different sizes");
@@ -30,9 +34,10 @@ public class Sequences {
 
   /**
    * Trim points from the start or end of a sequence for which y-values are
-   * zero. If no such leading or trailing points exist, sequence conatins only a
+   * zero. If no such leading or trailing points exist, sequence contains only a
    * single point, or all y-values are zero, method returns the supplied
-   * sequence.
+   * sequence. If supplied sequence is mutable, returned sequence is mutable;
+   * otherwise returned sequence is immutable.
    */
   static XySequence trim(ArrayXySequence xy) {
     if (xy.size() == 1 || xy.isClear()) {
@@ -93,7 +98,7 @@ public class Sequences {
     return ((int) Maths.round(((max - min) / delta), 6)) + 1;
   }
 
-  /*
+  /**
    * Ensure validity of sequence discretization parameters. Confirms that for a
    * specified range [min..max] and Δ that (1) min, max, and Δ are finite, (2)
    * max > min, and (3) Δ > 0. Returns the supplied Δ for use inline.
@@ -107,8 +112,9 @@ public class Sequences {
     return Δ;
   }
 
-  // TODO docs; consider moving to cumulate method in data/sequence package;
-  // not necessarily MFD specific
+  /**
+   * Create a new XySequence with reverse cumulative values.
+   */
   public static XySequence toCumulative(XySequence incremental) {
     MutableXySequence cumulative = MutableXySequence.copyOf(incremental);
     double sum = 0.0;
@@ -216,32 +222,12 @@ public class Sequences {
           : sequence;
     }
 
-    /*
-     * TODO clean
-     *
-     * Method rounds (max-min)/Δ to 1e-6 before casting to an integer to
-     * determine the number of elements in the sequence. If (max-min)/Δ is
-     * reasonably close to an integer but max is off by some double-precision
-     * error (e.g. 6.7999999999), then max of 6.8 will be the upper end of the
-     * sequence.
-     */
-    // private static double[] buildSequence(double min, double max, double Δ) {
-    // checkSequenceParameters(min, max, Δ);
-    // int size = ((int) Maths.round(((max - min) / Δ), 6)) + 1;
-    // checkArgument(Range.openClosed(0, 100000).contains(size), "sequence
-    // size");
-    // return IntStream.range(0, size)
-    // .mapToDouble(i -> min + Δ * i)
-    // .toArray();
-    // }
-
     private static double[] buildSequence(double min, double Δ, int size) {
       checkArgument(Range.openClosed(0, 100000).contains(size), "sequence size");
       return IntStream.range(0, size)
           .mapToDouble(i -> min + Δ * i)
           .toArray();
     }
-
   }
 
 }
diff --git a/src/test/java/gov/usgs/earthquake/nshmp/data/SequencesTests.java b/src/test/java/gov/usgs/earthquake/nshmp/data/SequencesTests.java
index 185e9137..42c67e57 100644
--- a/src/test/java/gov/usgs/earthquake/nshmp/data/SequencesTests.java
+++ b/src/test/java/gov/usgs/earthquake/nshmp/data/SequencesTests.java
@@ -1,10 +1,13 @@
 package gov.usgs.earthquake.nshmp.data;
 
 import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertSame;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 
 import java.util.Arrays;
+import java.util.Optional;
 
 import org.junit.jupiter.api.Test;
 
@@ -12,6 +15,76 @@ import com.google.common.primitives.Doubles;
 
 class SequencesTests {
 
+  @Test
+  final void validateArraysTests() {
+    // empty xs array
+    assertThrows(IllegalArgumentException.class, () -> {
+      Sequences.validateArrays(new double[0], new double[0]);
+    });
+    // xs and ys different sizes
+    assertThrows(IllegalArgumentException.class, () -> {
+      Sequences.validateArrays(new double[2], new double[3]);
+    });
+    // xs not monotonic
+    assertThrows(IllegalArgumentException.class, () -> {
+      Sequences.validateArrays(new double[] { 1, 0 }, new double[2]);
+    });
+    // xs not monotonic
+    assertDoesNotThrow(() -> {
+      Sequences.validateArrays(new double[] { 0, 1 }, new double[2]);
+    });
+    // single values makes it through monotonic test
+    assertDoesNotThrow(() -> {
+      Sequences.validateArrays(new double[1], new double[1]);
+    });
+  }
+
+  @Test
+  final void trimTests() {
+    double[] xs1 = new double[1];
+    double[] ys1 = new double[1];
+
+    double[] xs3 = new double[] { 1, 2, 3 };
+    double[] ys3zero = new double[3];
+    double[] ys3ones = new double[] { 1, 1, 1 };
+
+    // size and clear check
+    ArrayXySequence xy1 = (ArrayXySequence) XySequence.create(xs1, ys1);
+    assertSame(xy1, Sequences.trim(xy1));
+    ArrayXySequence xy3a = (ArrayXySequence) XySequence.create(xs3, ys3zero);
+    assertSame(xy3a, Sequences.trim(xy3a));
+
+    // start and end y values > 0
+    ArrayXySequence xy3b = (ArrayXySequence) XySequence.create(xs3, ys3ones);
+    assertSame(xy3b, Sequences.trim(xy3b));
+
+    double[] xs4toTrim = new double[] { 1, 2, 3, 4 };
+    double[] ys4toTrim = new double[] { 1, 1, 1, 0 };
+    double[] xs4expect = new double[] { 1, 2, 3 };
+    double[] ys4expect = new double[] { 1, 1, 1 };
+
+    // extra test that gets upper end y = 0
+    ArrayXySequence xy4toTrim = (ArrayXySequence) XySequence.create(xs4toTrim, ys4toTrim);
+    ArrayXySequence xy4expect = (ArrayXySequence) XySequence.create(xs4expect, ys4expect);
+    assertEquals(xy4expect, Sequences.trim(xy4toTrim));
+
+    double[] xs5toTrim = new double[] { 1, 2, 3, 4, 5 };
+    double[] ys5toTrim = new double[] { 0, 1, 1, 1, 0 };
+    double[] xs5expect = new double[] { 2, 3, 4 };
+    double[] ys5expect = new double[] { 1, 1, 1 };
+
+    // immutable trimmed
+    ArrayXySequence xy5toTrim = (ArrayXySequence) XySequence.create(xs5toTrim, ys5toTrim);
+    ArrayXySequence xy5expect = (ArrayXySequence) XySequence.create(xs5expect, ys5expect);
+    assertEquals(xy5expect, Sequences.trim(xy5toTrim));
+
+    // mutable trimmed
+    MutableArrayXySequence xy5toTrimMutable = (MutableArrayXySequence) MutableXySequence.create(
+        xs5toTrim,
+        Optional.of(ys5toTrim));
+    assertEquals(xy5expect, Sequences.trim(xy5toTrimMutable));
+  }
+
   @Test
   final void nonZeroIndexTests() {
     double[] values = new double[] { 0.0, 0.0, 1.0, 1.0, 0.0, 0.0 };
@@ -25,6 +98,17 @@ class SequencesTests {
     assertEquals(-1, Sequences.lastNonZeroIndex(zeros), 0.0);
   }
 
+  @Test
+  final void toCumulativeTests() {
+    double[] xs = new double[] { 1, 2, 3, 4, 5 };
+    double[] ys = new double[] { 1, 1, 1, 1, 1 };
+    double[] ysExpect = new double[] { 5, 4, 3, 2, 1 };
+
+    XySequence xyActual = Sequences.toCumulative(XySequence.create(xs, ys));
+    XySequence xyExpect = XySequence.create(xs, ysExpect);
+    assertEquals(xyExpect, xyActual);
+  }
+
   @Test
   final void arrayBuilderTests() {
 
-- 
GitLab