From cd9287434c969c721a6c3aba0d71085335eacbcc Mon Sep 17 00:00:00 2001 From: Jason Altekruse <jaltekruse@contractor.usgs.gov> Date: Fri, 20 Mar 2020 13:14:32 -0600 Subject: [PATCH] add Sequences.combine() and tests. ghsc/nshmp/nshmp-lib#51 --- .../usgs/earthquake/nshmp/data/Sequences.java | 44 +++++- .../earthquake/nshmp/data/SequencesTests.java | 139 ++++++++++++------ 2 files changed, 137 insertions(+), 46 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 33a78723..7b08a39c 100644 --- a/src/main/java/gov/usgs/earthquake/nshmp/data/Sequences.java +++ b/src/main/java/gov/usgs/earthquake/nshmp/data/Sequences.java @@ -6,7 +6,9 @@ import static gov.usgs.earthquake.nshmp.data.DoubleData.areMonotonic; import java.util.Arrays; import java.util.Collection; +import java.util.TreeMap; import java.util.function.Predicate; +import java.util.stream.Collectors; /** * Static methods we don't want in public interfaces. @@ -65,8 +67,7 @@ class Sequences { if (xySequences.size() == 1) { return true; } - // Safe covariant cast - ArrayXySequence firstXy = (ArrayXySequence) xySequences.iterator().next(); + ArrayXySequence firstXy = getFirstSequence(xySequences); Predicate<XySequence> firstXsPredicate = other -> { return Arrays.equals( firstXy.xs, @@ -77,4 +78,43 @@ class Sequences { .allMatch(firstXsPredicate); } + /** + * Combine {@code Collection} of {@code XySequence} such that the resulting + * x-values are the union of all specified sequences, and the y-values are + * summed accordingly. + * + * @param xySequences + * @return xys + */ + static XySequence combine(Collection<XySequence> xySequences) { + checkState(!xySequences.isEmpty()); + if (xySequences.size() == 1) { + return getFirstSequence(xySequences); + } + if (areSimilar(xySequences)) { + MutableXySequence result = MutableXySequence.emptyCopyOf(getFirstSequence(xySequences)); + for (XySequence xys : xySequences) { + result.add(xys); + } + return result; + } + + var combinedMap = xySequences.stream() + .flatMap(XySequence::stream) + .collect(Collectors.toMap( + (XyPoint xy) -> (double) xy.x(), + (XyPoint xy) -> (double) xy.y(), + (a, b) -> a + b, + TreeMap::new)); + return XySequence.create( + combinedMap.keySet(), + combinedMap.values()); + } + + private static ArrayXySequence getFirstSequence(Collection<XySequence> xySequences) { + checkState(!xySequences.isEmpty()); + // Safe covariant cast + return (ArrayXySequence) xySequences.iterator().next(); + } + } 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 53be21da..302918a7 100644 --- a/src/test/java/gov/usgs/earthquake/nshmp/data/SequencesTests.java +++ b/src/test/java/gov/usgs/earthquake/nshmp/data/SequencesTests.java @@ -1,9 +1,11 @@ package gov.usgs.earthquake.nshmp.data; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.util.Arrays; import java.util.List; import org.junit.jupiter.api.Test; @@ -12,59 +14,108 @@ import com.google.common.collect.ImmutableList; class SequencesTests { - private static double[] xs1 = new double[] { 0, 1, 2, 3 }; - private static double[] xs2 = new double[] { 1, 2, 3, 4 }; - private static double[] xs3 = new double[] { 6, 7, 8 }; - - private static double[] ys1 = new double[] { 10, 9, 8, 7 }; - private static double[] ys2 = new double[] { 5, 4, 3, 2 }; - private static double[] ys3 = new double[] { 10, 9, 8 }; - - private static XySequence xyBase = XySequence.create(xs1, ys1); - private static XySequence xySameXs = XySequence.create(xs1, ys2); - private static XySequence xyDifferentXs = XySequence.create(xs2, ys2); - private static XySequence xyShorter = XySequence.create(xs3, ys3); - - private static List<XySequence> emptyCollection = new ImmutableList.Builder<XySequence>().build(); - private static List<XySequence> singleSequences = - new ImmutableList.Builder<XySequence>() - .add(xyBase) - .build(); - private static List<XySequence> identicalSequences = - new ImmutableList.Builder<XySequence>() - .add(xyBase) - .add(xyBase) - .build(); - private static List<XySequence> sameXs = - new ImmutableList.Builder<XySequence>() - .add(xyBase) - .add(xySameXs) - .build(); - private static List<XySequence> differentXs = - new ImmutableList.Builder<XySequence>() - .add(xyBase) - .add(xySameXs) - .add(xyDifferentXs) - .build(); - private static List<XySequence> withShorterXs = - new ImmutableList.Builder<XySequence>() - .add(xyBase) - .add(xySameXs) - .add(xyDifferentXs) - .add(xyShorter) - .build(); + private static final double[] xs1 = new double[] { 0, 1, 2, 3 }; + private static final double[] xs2 = new double[] { 1, 2, 3, 4 }; + private static final double[] xs3 = new double[] { 5, 6, 7 }; - @Test - final void areSimilarTests() { + private static final double[] ys1 = new double[] { 10, 9, 8, 7 }; + private static final double[] ys2 = new double[] { 5, 4, 3, 2 }; + private static final double[] ys3 = new double[] { 10, 9, 8 }; + + private static final XySequence xyBase = XySequence.create(xs1, ys1); + private static final XySequence xySameXs = XySequence.create(xs1, ys2); + private static final XySequence xyDifferentXs = XySequence.create(xs2, ys2); + private static final XySequence xyShorter = XySequence.create(xs3, ys3); + + private static final List<XySequence> emptyCollection; + private static final List<XySequence> singleSequence; + private static final XySequence expectedSingleSequenceResults; + private static final List<XySequence> identicalSequences; + private static final XySequence expectedIdenticalSequences; + private static final List<XySequence> sameXs; + private static final XySequence expectedSameXs; + private static final List<XySequence> differentXs; + private static final XySequence expectedDifferentXs; + private static final List<XySequence> withShorterXs; + private static final XySequence expectedWithShorterXs; + + static { + emptyCollection = new ImmutableList.Builder<XySequence>().build(); + + singleSequence = new ImmutableList.Builder<XySequence>() + .add(xyBase) + .build(); + expectedSingleSequenceResults = xyBase; + + identicalSequences = new ImmutableList.Builder<XySequence>() + .add(xyBase) + .add(xyBase) + .build(); + double[] result = new double[xs1.length]; + Arrays.setAll(result, i -> ys1[i] + ys1[i]); + expectedIdenticalSequences = XySequence.create(xs1, result); + sameXs = new ImmutableList.Builder<XySequence>() + .add(xyBase) + .add(xySameXs) + .build(); + Arrays.setAll(result, i -> ys1[i] + ys2[i]); + expectedSameXs = XySequence.create(xs1, result); + + differentXs = new ImmutableList.Builder<XySequence>() + .add(xyBase) + .add(xyDifferentXs) + .build(); + // manually construct for now + expectedDifferentXs = XySequence.create( + new double[] { 0, 1, 2, 3, 4 }, + new double[] { 10, 14, 12, 10, 2 }); + + withShorterXs = new ImmutableList.Builder<XySequence>() + .add(xyBase) + .add(xyDifferentXs) + .add(xyShorter) + .build(); + // manually construct for now + expectedWithShorterXs = XySequence.create( + new double[] { 0, 1, 2, 3, 4, 5, 6, 7 }, + new double[] { 10, 14, 12, 10, 2, 10, 9, 8 }); + } + + @Test + final void areSimilarTests_emptyThrowsISE() { assertThrows(IllegalStateException.class, () -> { Sequences.areSimilar(emptyCollection); }); - assertTrue(Sequences.areSimilar(singleSequences)); + } + + @Test + final void areSimilarTests() { + assertTrue(Sequences.areSimilar(singleSequence)); assertTrue(Sequences.areSimilar(identicalSequences)); assertTrue(Sequences.areSimilar(sameXs)); assertFalse(Sequences.areSimilar(differentXs)); assertFalse(Sequences.areSimilar(withShorterXs)); } + @Test + final void combineTests_emptyThrowsISE() { + assertThrows(IllegalStateException.class, () -> { + Sequences.combine(emptyCollection); + }); + } + + @Test + final void combineTests_similarSequences() { + assertEquals(expectedSingleSequenceResults, Sequences.combine(singleSequence)); + assertEquals(expectedIdenticalSequences, Sequences.combine(identicalSequences)); + assertEquals(expectedSameXs, Sequences.combine(sameXs)); + } + + @Test + final void combineTests_dissimilarSequences() { + assertEquals(expectedDifferentXs, Sequences.combine(differentXs)); + assertEquals(expectedWithShorterXs, Sequences.combine(withShorterXs)); + } + } -- GitLab