• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2013 The Guava Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.common.math;
18 
19 import static com.google.common.base.Preconditions.checkArgument;
20 import static com.google.common.truth.Truth.assertThat;
21 import static java.lang.Double.NEGATIVE_INFINITY;
22 import static java.lang.Double.NaN;
23 import static java.lang.Double.POSITIVE_INFINITY;
24 import static org.junit.Assert.fail;
25 
26 import com.google.common.base.Predicates;
27 import com.google.common.collect.ImmutableList;
28 import com.google.common.collect.Iterables;
29 import com.google.common.collect.Lists;
30 import com.google.common.primitives.Doubles;
31 import com.google.common.primitives.Ints;
32 import java.math.BigInteger;
33 import java.util.List;
34 
35 /**
36  * Inputs, expected outputs, and helper methods for tests of {@link StatsAccumulator}, {@link
37  * Stats}, {@link PairedStatsAccumulator}, and {@link PairedStats}.
38  *
39  * @author Pete Gillin
40  */
41 class StatsTesting {
42 
43   static final double ALLOWED_ERROR = 1e-10;
44 
45   // Inputs and their statistics:
46 
47   static final double ONE_VALUE = 12.34;
48 
49   static final double OTHER_ONE_VALUE = -56.78;
50 
51   static final ImmutableList<Double> TWO_VALUES = ImmutableList.of(12.34, -56.78);
52   static final double TWO_VALUES_MEAN = (12.34 - 56.78) / 2;
53   static final double TWO_VALUES_SUM_OF_SQUARES_OF_DELTAS =
54       (12.34 - TWO_VALUES_MEAN) * (12.34 - TWO_VALUES_MEAN)
55           + (-56.78 - TWO_VALUES_MEAN) * (-56.78 - TWO_VALUES_MEAN);
56   static final double TWO_VALUES_MAX = 12.34;
57   static final double TWO_VALUES_MIN = -56.78;
58 
59   static final ImmutableList<Double> OTHER_TWO_VALUES = ImmutableList.of(123.456, -789.012);
60   static final double OTHER_TWO_VALUES_MEAN = (123.456 - 789.012) / 2;
61   static final double TWO_VALUES_SUM_OF_PRODUCTS_OF_DELTAS =
62       (12.34 - TWO_VALUES_MEAN) * (123.456 - OTHER_TWO_VALUES_MEAN)
63           + (-56.78 - TWO_VALUES_MEAN) * (-789.012 - OTHER_TWO_VALUES_MEAN);
64 
65   /**
66    * Helper class for testing with non-finite values. {@link #ALL_MANY_VALUES} gives a number
67    * instances with many combinations of finite and non-finite values. All have {@link
68    * #MANY_VALUES_COUNT} values. If all the values are finite then the mean is {@link
69    * #MANY_VALUES_MEAN} and the sum-of-squares-of-deltas is {@link
70    * #MANY_VALUES_SUM_OF_SQUARES_OF_DELTAS}. The smallest and largest finite values are always
71    * {@link #MANY_VALUES_MIN} and {@link #MANY_VALUES_MAX}, although setting non-finite values will
72    * change the true min and max.
73    */
74   static class ManyValues {
75 
76     private final ImmutableList<Double> values;
77 
ManyValues(double[] values)78     ManyValues(double[] values) {
79       this.values = ImmutableList.copyOf(Doubles.asList(values));
80     }
81 
asIterable()82     ImmutableList<Double> asIterable() {
83       return values;
84     }
85 
asArray()86     double[] asArray() {
87       return Doubles.toArray(values);
88     }
89 
hasAnyPositiveInfinity()90     boolean hasAnyPositiveInfinity() {
91       return Iterables.any(values, Predicates.equalTo(POSITIVE_INFINITY));
92     }
93 
hasAnyNegativeInfinity()94     boolean hasAnyNegativeInfinity() {
95       return Iterables.any(values, Predicates.equalTo(NEGATIVE_INFINITY));
96     }
97 
hasAnyNaN()98     boolean hasAnyNaN() {
99       return Iterables.any(values, Predicates.equalTo(NaN));
100     }
101 
hasAnyNonFinite()102     boolean hasAnyNonFinite() {
103       return hasAnyPositiveInfinity() || hasAnyNegativeInfinity() || hasAnyNaN();
104     }
105 
106     @Override
toString()107     public String toString() {
108       return values.toString();
109     }
110 
createAll()111     private static ImmutableList<ManyValues> createAll() {
112       ImmutableList.Builder<ManyValues> builder = ImmutableList.builder();
113       double[] values = new double[5];
114       for (double first : ImmutableList.of(1.1, POSITIVE_INFINITY, NEGATIVE_INFINITY, NaN)) {
115         values[0] = first;
116         values[1] = -44.44;
117         for (double third : ImmutableList.of(33.33, POSITIVE_INFINITY, NEGATIVE_INFINITY, NaN)) {
118           values[2] = third;
119           values[3] = 555.555;
120           for (double fifth : ImmutableList.of(-2.2, POSITIVE_INFINITY, NEGATIVE_INFINITY, NaN)) {
121             values[4] = fifth;
122             builder.add(new ManyValues(values));
123           }
124         }
125       }
126       return builder.build();
127     }
128   }
129 
130   static final ImmutableList<ManyValues> ALL_MANY_VALUES = ManyValues.createAll();
131 
132   static final ImmutableList<Double> MANY_VALUES =
133       ImmutableList.of(1.1, -44.44, 33.33, 555.555, -2.2);
134   static final int MANY_VALUES_COUNT = 5;
135   static final double MANY_VALUES_MEAN = (1.1 - 44.44 + 33.33 + 555.555 - 2.2) / 5;
136   static final double MANY_VALUES_SUM_OF_SQUARES_OF_DELTAS =
137       (1.1 - MANY_VALUES_MEAN) * (1.1 - MANY_VALUES_MEAN)
138           + (-44.44 - MANY_VALUES_MEAN) * (-44.44 - MANY_VALUES_MEAN)
139           + (33.33 - MANY_VALUES_MEAN) * (33.33 - MANY_VALUES_MEAN)
140           + (555.555 - MANY_VALUES_MEAN) * (555.555 - MANY_VALUES_MEAN)
141           + (-2.2 - MANY_VALUES_MEAN) * (-2.2 - MANY_VALUES_MEAN);
142   static final double MANY_VALUES_MAX = 555.555;
143   static final double MANY_VALUES_MIN = -44.44;
144 
145   // Doubles which will overflow if summed:
146   static final double[] LARGE_VALUES = {Double.MAX_VALUE, Double.MAX_VALUE / 2.0};
147   static final double LARGE_VALUES_MEAN = 0.75 * Double.MAX_VALUE;
148 
149   static final ImmutableList<Double> OTHER_MANY_VALUES =
150       ImmutableList.of(1.11, -2.22, 33.3333, -44.4444, 555.555555);
151   static final int OTHER_MANY_VALUES_COUNT = 5;
152   static final double OTHER_MANY_VALUES_MEAN = (1.11 - 2.22 + 33.3333 - 44.4444 + 555.555555) / 5;
153 
154   static final double MANY_VALUES_SUM_OF_PRODUCTS_OF_DELTAS =
155       (1.1 - MANY_VALUES_MEAN) * (1.11 - OTHER_MANY_VALUES_MEAN)
156           + (-44.44 - MANY_VALUES_MEAN) * (-2.22 - OTHER_MANY_VALUES_MEAN)
157           + (33.33 - MANY_VALUES_MEAN) * (33.3333 - OTHER_MANY_VALUES_MEAN)
158           + (555.555 - MANY_VALUES_MEAN) * (-44.4444 - OTHER_MANY_VALUES_MEAN)
159           + (-2.2 - MANY_VALUES_MEAN) * (555.555555 - OTHER_MANY_VALUES_MEAN);
160 
161   static final ImmutableList<Integer> INTEGER_MANY_VALUES =
162       ImmutableList.of(11, -22, 3333, -4444, 555555);
163   static final int INTEGER_MANY_VALUES_COUNT = 5;
164   static final double INTEGER_MANY_VALUES_MEAN = (11.0 - 22.0 + 3333.0 - 4444.0 + 555555.0) / 5;
165   static final double INTEGER_MANY_VALUES_SUM_OF_SQUARES_OF_DELTAS =
166       (11.0 - INTEGER_MANY_VALUES_MEAN) * (11.0 - INTEGER_MANY_VALUES_MEAN)
167           + (-22.0 - INTEGER_MANY_VALUES_MEAN) * (-22.0 - INTEGER_MANY_VALUES_MEAN)
168           + (3333.0 - INTEGER_MANY_VALUES_MEAN) * (3333.0 - INTEGER_MANY_VALUES_MEAN)
169           + (-4444.0 - INTEGER_MANY_VALUES_MEAN) * (-4444.0 - INTEGER_MANY_VALUES_MEAN)
170           + (555555.0 - INTEGER_MANY_VALUES_MEAN) * (555555.0 - INTEGER_MANY_VALUES_MEAN);
171   static final double INTEGER_MANY_VALUES_MAX = 555555.0;
172   static final double INTEGER_MANY_VALUES_MIN = -4444.0;
173 
174   // Integers which will overflow if summed (using integer arithmetic):
175   static final int[] LARGE_INTEGER_VALUES = {Integer.MAX_VALUE, Integer.MAX_VALUE / 2};
176   static final double LARGE_INTEGER_VALUES_MEAN =
177       BigInteger.valueOf(Integer.MAX_VALUE)
178           .multiply(BigInteger.valueOf(3L))
179           .divide(BigInteger.valueOf(4L))
180           .doubleValue();
181   static final double LARGE_INTEGER_VALUES_POPULATION_VARIANCE =
182       BigInteger.valueOf(Integer.MAX_VALUE)
183           .multiply(BigInteger.valueOf(Integer.MAX_VALUE))
184           .divide(BigInteger.valueOf(16L))
185           .doubleValue();
186 
187   static final ImmutableList<Long> LONG_MANY_VALUES =
188       ImmutableList.of(1111L, -2222L, 33333333L, -44444444L, 5555555555L);
189   static final int LONG_MANY_VALUES_COUNT = 5;
190   static final double LONG_MANY_VALUES_MEAN =
191       (1111.0 - 2222.0 + 33333333.0 - 44444444.0 + 5555555555.0) / 5;
192   static final double LONG_MANY_VALUES_SUM_OF_SQUARES_OF_DELTAS =
193       (1111.0 - LONG_MANY_VALUES_MEAN) * (1111.0 - LONG_MANY_VALUES_MEAN)
194           + (-2222.0 - LONG_MANY_VALUES_MEAN) * (-2222.0 - LONG_MANY_VALUES_MEAN)
195           + (33333333.0 - LONG_MANY_VALUES_MEAN) * (33333333.0 - LONG_MANY_VALUES_MEAN)
196           + (-44444444.0 - LONG_MANY_VALUES_MEAN) * (-44444444.0 - LONG_MANY_VALUES_MEAN)
197           + (5555555555.0 - LONG_MANY_VALUES_MEAN) * (5555555555.0 - LONG_MANY_VALUES_MEAN);
198   static final double LONG_MANY_VALUES_MAX = 5555555555.0;
199   static final double LONG_MANY_VALUES_MIN = -44444444.0;
200 
201   // Longs which will overflow if summed (using long arithmetic):
202   static final long[] LARGE_LONG_VALUES = {Long.MAX_VALUE, Long.MAX_VALUE / 2};
203   static final double LARGE_LONG_VALUES_MEAN =
204       BigInteger.valueOf(Long.MAX_VALUE)
205           .multiply(BigInteger.valueOf(3L))
206           .divide(BigInteger.valueOf(4L))
207           .doubleValue();
208   static final double LARGE_LONG_VALUES_POPULATION_VARIANCE =
209       BigInteger.valueOf(Long.MAX_VALUE)
210           .multiply(BigInteger.valueOf(Long.MAX_VALUE))
211           .divide(BigInteger.valueOf(16L))
212           .doubleValue();
213 
214   // Stats instances:
215 
216   static final Stats EMPTY_STATS_VARARGS = Stats.of();
217   static final Stats EMPTY_STATS_ITERABLE = Stats.of(ImmutableList.<Double>of());
218   static final Stats ONE_VALUE_STATS = Stats.of(ONE_VALUE);
219   static final Stats OTHER_ONE_VALUE_STATS = Stats.of(OTHER_ONE_VALUE);
220   static final Stats TWO_VALUES_STATS = Stats.of(TWO_VALUES);
221   static final Stats OTHER_TWO_VALUES_STATS = Stats.of(OTHER_TWO_VALUES);
222   static final Stats MANY_VALUES_STATS_VARARGS = Stats.of(1.1, -44.44, 33.33, 555.555, -2.2);
223   static final Stats MANY_VALUES_STATS_ITERABLE = Stats.of(MANY_VALUES);
224   static final Stats MANY_VALUES_STATS_ITERATOR = Stats.of(MANY_VALUES.iterator());
225   static final Stats MANY_VALUES_STATS_SNAPSHOT = buildManyValuesStatsSnapshot();
226   static final Stats LARGE_VALUES_STATS = Stats.of(LARGE_VALUES);
227   static final Stats OTHER_MANY_VALUES_STATS = Stats.of(OTHER_MANY_VALUES);
228   static final Stats INTEGER_MANY_VALUES_STATS_VARARGS =
229       Stats.of(Ints.toArray(INTEGER_MANY_VALUES));
230   static final Stats INTEGER_MANY_VALUES_STATS_ITERABLE = Stats.of(INTEGER_MANY_VALUES);
231   static final Stats LARGE_INTEGER_VALUES_STATS = Stats.of(LARGE_INTEGER_VALUES);
232   static final Stats LONG_MANY_VALUES_STATS_ITERATOR = Stats.of(LONG_MANY_VALUES.iterator());
233   static final Stats LONG_MANY_VALUES_STATS_SNAPSHOT = buildLongManyValuesStatsSnapshot();
234   static final Stats LARGE_LONG_VALUES_STATS = Stats.of(LARGE_LONG_VALUES);
235 
buildManyValuesStatsSnapshot()236   private static Stats buildManyValuesStatsSnapshot() {
237     StatsAccumulator accumulator = new StatsAccumulator();
238     accumulator.addAll(MANY_VALUES);
239     Stats stats = accumulator.snapshot();
240     accumulator.add(999.999); // should do nothing to the snapshot
241     return stats;
242   }
243 
buildLongManyValuesStatsSnapshot()244   private static Stats buildLongManyValuesStatsSnapshot() {
245     StatsAccumulator accumulator = new StatsAccumulator();
246     accumulator.addAll(LONG_MANY_VALUES);
247     return accumulator.snapshot();
248   }
249 
250   static final ImmutableList<Stats> ALL_STATS =
251       ImmutableList.of(
252           EMPTY_STATS_VARARGS,
253           EMPTY_STATS_ITERABLE,
254           ONE_VALUE_STATS,
255           OTHER_ONE_VALUE_STATS,
256           TWO_VALUES_STATS,
257           OTHER_TWO_VALUES_STATS,
258           MANY_VALUES_STATS_VARARGS,
259           MANY_VALUES_STATS_ITERABLE,
260           MANY_VALUES_STATS_ITERATOR,
261           MANY_VALUES_STATS_SNAPSHOT,
262           LARGE_VALUES_STATS,
263           OTHER_MANY_VALUES_STATS,
264           INTEGER_MANY_VALUES_STATS_VARARGS,
265           INTEGER_MANY_VALUES_STATS_ITERABLE,
266           LARGE_INTEGER_VALUES_STATS,
267           LONG_MANY_VALUES_STATS_ITERATOR,
268           LONG_MANY_VALUES_STATS_SNAPSHOT,
269           LARGE_LONG_VALUES_STATS);
270 
271   // PairedStats instances:
272 
273   static final PairedStats EMPTY_PAIRED_STATS =
274       createPairedStatsOf(ImmutableList.<Double>of(), ImmutableList.<Double>of());
275   static final PairedStats ONE_VALUE_PAIRED_STATS =
276       createPairedStatsOf(ImmutableList.of(ONE_VALUE), ImmutableList.of(OTHER_ONE_VALUE));
277   static final PairedStats TWO_VALUES_PAIRED_STATS =
278       createPairedStatsOf(TWO_VALUES, OTHER_TWO_VALUES);
279   static final PairedStats MANY_VALUES_PAIRED_STATS = buildManyValuesPairedStats();
280   static final PairedStats DUPLICATE_MANY_VALUES_PAIRED_STATS =
281       createPairedStatsOf(MANY_VALUES, OTHER_MANY_VALUES);
282   static final PairedStats HORIZONTAL_VALUES_PAIRED_STATS = buildHorizontalValuesPairedStats();
283   static final PairedStats VERTICAL_VALUES_PAIRED_STATS = buildVerticalValuesPairedStats();
284   static final PairedStats CONSTANT_VALUES_PAIRED_STATS = buildConstantValuesPairedStats();
285 
buildManyValuesPairedStats()286   private static PairedStats buildManyValuesPairedStats() {
287     PairedStatsAccumulator accumulator =
288         createFilledPairedStatsAccumulator(MANY_VALUES, OTHER_MANY_VALUES);
289     PairedStats stats = accumulator.snapshot();
290     accumulator.add(99.99, 9999.9999); // should do nothing to the snapshot
291     return stats;
292   }
293 
buildHorizontalValuesPairedStats()294   private static PairedStats buildHorizontalValuesPairedStats() {
295     PairedStatsAccumulator accumulator = new PairedStatsAccumulator();
296     for (double x : MANY_VALUES) {
297       accumulator.add(x, OTHER_ONE_VALUE);
298     }
299     return accumulator.snapshot();
300   }
301 
buildVerticalValuesPairedStats()302   private static PairedStats buildVerticalValuesPairedStats() {
303     PairedStatsAccumulator accumulator = new PairedStatsAccumulator();
304     for (double y : OTHER_MANY_VALUES) {
305       accumulator.add(ONE_VALUE, y);
306     }
307     return accumulator.snapshot();
308   }
309 
buildConstantValuesPairedStats()310   private static PairedStats buildConstantValuesPairedStats() {
311     PairedStatsAccumulator accumulator = new PairedStatsAccumulator();
312     for (int i = 0; i < MANY_VALUES_COUNT; ++i) {
313       accumulator.add(ONE_VALUE, OTHER_ONE_VALUE);
314     }
315     return accumulator.snapshot();
316   }
317 
318   static final ImmutableList<PairedStats> ALL_PAIRED_STATS =
319       ImmutableList.of(
320           EMPTY_PAIRED_STATS,
321           ONE_VALUE_PAIRED_STATS,
322           TWO_VALUES_PAIRED_STATS,
323           MANY_VALUES_PAIRED_STATS,
324           DUPLICATE_MANY_VALUES_PAIRED_STATS,
325           HORIZONTAL_VALUES_PAIRED_STATS,
326           VERTICAL_VALUES_PAIRED_STATS,
327           CONSTANT_VALUES_PAIRED_STATS);
328 
329   // Helper methods:
330 
assertStatsApproxEqual(Stats expectedStats, Stats actualStats)331   static void assertStatsApproxEqual(Stats expectedStats, Stats actualStats) {
332     assertThat(actualStats.count()).isEqualTo(expectedStats.count());
333     if (expectedStats.count() == 0) {
334       try {
335         actualStats.mean();
336         fail("Expected IllegalStateException");
337       } catch (IllegalStateException expected) {
338       }
339       try {
340         actualStats.populationVariance();
341         fail("Expected IllegalStateException");
342       } catch (IllegalStateException expected) {
343       }
344       try {
345         actualStats.min();
346         fail("Expected IllegalStateException");
347       } catch (IllegalStateException expected) {
348       }
349       try {
350         actualStats.max();
351         fail("Expected IllegalStateException");
352       } catch (IllegalStateException expected) {
353       }
354     } else if (expectedStats.count() == 1) {
355       assertThat(actualStats.mean()).isWithin(ALLOWED_ERROR).of(expectedStats.mean());
356       assertThat(actualStats.populationVariance()).isWithin(0.0).of(0.0);
357       assertThat(actualStats.min()).isWithin(ALLOWED_ERROR).of(expectedStats.min());
358       assertThat(actualStats.max()).isWithin(ALLOWED_ERROR).of(expectedStats.max());
359     } else {
360       assertThat(actualStats.mean()).isWithin(ALLOWED_ERROR).of(expectedStats.mean());
361       assertThat(actualStats.populationVariance())
362           .isWithin(ALLOWED_ERROR)
363           .of(expectedStats.populationVariance());
364       assertThat(actualStats.min()).isWithin(ALLOWED_ERROR).of(expectedStats.min());
365       assertThat(actualStats.max()).isWithin(ALLOWED_ERROR).of(expectedStats.max());
366     }
367   }
368 
369   /**
370    * Asserts that {@code transformation} is diagonal (i.e. neither horizontal or vertical) and
371    * passes through both {@code (x1, y1)} and {@code (x1 + xDelta, y1 + yDelta)}. Includes
372    * assertions about all the public instance methods of {@link LinearTransformation} (on both
373    * {@code transformation} and its inverse). Since the transformation is expected to be diagonal,
374    * neither {@code xDelta} nor {@code yDelta} may be zero.
375    */
assertDiagonalLinearTransformation( LinearTransformation transformation, double x1, double y1, double xDelta, double yDelta)376   static void assertDiagonalLinearTransformation(
377       LinearTransformation transformation, double x1, double y1, double xDelta, double yDelta) {
378     checkArgument(xDelta != 0.0);
379     checkArgument(yDelta != 0.0);
380     assertThat(transformation.isHorizontal()).isFalse();
381     assertThat(transformation.isVertical()).isFalse();
382     assertThat(transformation.inverse().isHorizontal()).isFalse();
383     assertThat(transformation.inverse().isVertical()).isFalse();
384     assertThat(transformation.transform(x1)).isWithin(ALLOWED_ERROR).of(y1);
385     assertThat(transformation.transform(x1 + xDelta)).isWithin(ALLOWED_ERROR).of(y1 + yDelta);
386     assertThat(transformation.inverse().transform(y1)).isWithin(ALLOWED_ERROR).of(x1);
387     assertThat(transformation.inverse().transform(y1 + yDelta))
388         .isWithin(ALLOWED_ERROR)
389         .of(x1 + xDelta);
390     assertThat(transformation.slope()).isWithin(ALLOWED_ERROR).of(yDelta / xDelta);
391     assertThat(transformation.inverse().slope()).isWithin(ALLOWED_ERROR).of(xDelta / yDelta);
392     assertThat(transformation.inverse()).isSameInstanceAs(transformation.inverse());
393     assertThat(transformation.inverse().inverse()).isSameInstanceAs(transformation);
394   }
395 
396   /**
397    * Asserts that {@code transformation} is horizontal with the given value of {@code y}. Includes
398    * assertions about all the public instance methods of {@link LinearTransformation}, including an
399    * assertion that {@link LinearTransformation#transform} and {@link LinearTransformation#slope} on
400    * its inverse throws as expected.
401    */
assertHorizontalLinearTransformation(LinearTransformation transformation, double y)402   static void assertHorizontalLinearTransformation(LinearTransformation transformation, double y) {
403     assertThat(transformation.isHorizontal()).isTrue();
404     assertThat(transformation.isVertical()).isFalse();
405     assertThat(transformation.inverse().isHorizontal()).isFalse();
406     assertThat(transformation.inverse().isVertical()).isTrue();
407     assertThat(transformation.transform(-1.0)).isWithin(ALLOWED_ERROR).of(y);
408     assertThat(transformation.transform(1.0)).isWithin(ALLOWED_ERROR).of(y);
409     try {
410       transformation.inverse().transform(0.0);
411       fail("Expected IllegalStateException");
412     } catch (IllegalStateException expected) {
413     }
414     assertThat(transformation.slope()).isWithin(ALLOWED_ERROR).of(0.0);
415     try {
416       transformation.inverse().slope();
417       fail("Expected IllegalStateException");
418     } catch (IllegalStateException expected) {
419     }
420     assertThat(transformation.inverse()).isSameInstanceAs(transformation.inverse());
421     assertThat(transformation.inverse().inverse()).isSameInstanceAs(transformation);
422   }
423 
424   /**
425    * Asserts that {@code transformation} is vertical with the given value of {@code x}. Includes
426    * assertions about all the public instance methods of {@link LinearTransformation}, including
427    * assertions that {@link LinearTransformation#slope} and {@link LinearTransformation#transform}
428    * throw as expected.
429    */
assertVerticalLinearTransformation(LinearTransformation transformation, double x)430   static void assertVerticalLinearTransformation(LinearTransformation transformation, double x) {
431     assertThat(transformation.isHorizontal()).isFalse();
432     assertThat(transformation.isVertical()).isTrue();
433     assertThat(transformation.inverse().isHorizontal()).isTrue();
434     assertThat(transformation.inverse().isVertical()).isFalse();
435     try {
436       transformation.transform(0.0);
437       fail("Expected IllegalStateException");
438     } catch (IllegalStateException expected) {
439     }
440     assertThat(transformation.inverse().transform(-1.0)).isWithin(ALLOWED_ERROR).of(x);
441     assertThat(transformation.inverse().transform(1.0)).isWithin(ALLOWED_ERROR).of(x);
442     try {
443       transformation.slope();
444       fail("Expected IllegalStateException");
445     } catch (IllegalStateException expected) {
446     }
447     assertThat(transformation.inverse().slope()).isWithin(ALLOWED_ERROR).of(0.0);
448     assertThat(transformation.inverse()).isSameInstanceAs(transformation.inverse());
449     assertThat(transformation.inverse().inverse()).isSameInstanceAs(transformation);
450   }
451 
452   /**
453    * Asserts that {@code transformation} behaves as expected for {@link
454    * LinearTransformation#forNaN}.
455    */
assertLinearTransformationNaN(LinearTransformation transformation)456   static void assertLinearTransformationNaN(LinearTransformation transformation) {
457     assertThat(transformation.isHorizontal()).isFalse();
458     assertThat(transformation.isVertical()).isFalse();
459     assertThat(transformation.slope()).isNaN();
460     assertThat(transformation.transform(0.0)).isNaN();
461     assertThat(transformation.inverse()).isSameInstanceAs(transformation);
462   }
463 
464   /**
465    * Creates a {@link PairedStats} from with the given lists of {@code x} and {@code y} values,
466    * which must be of the same size.
467    */
createPairedStatsOf(List<Double> xValues, List<Double> yValues)468   static PairedStats createPairedStatsOf(List<Double> xValues, List<Double> yValues) {
469     return createFilledPairedStatsAccumulator(xValues, yValues).snapshot();
470   }
471 
472   /**
473    * Creates a {@link PairedStatsAccumulator} filled with the given lists of {@code x} and {@code y}
474    * values, which must be of the same size.
475    */
createFilledPairedStatsAccumulator( List<Double> xValues, List<Double> yValues)476   static PairedStatsAccumulator createFilledPairedStatsAccumulator(
477       List<Double> xValues, List<Double> yValues) {
478     checkArgument(xValues.size() == yValues.size());
479     PairedStatsAccumulator accumulator = new PairedStatsAccumulator();
480     for (int index = 0; index < xValues.size(); index++) {
481       accumulator.add(xValues.get(index), yValues.get(index));
482     }
483     return accumulator;
484   }
485 
486   /**
487    * Creates a {@link PairedStatsAccumulator} filled with the given lists of {@code x} and {@code y}
488    * values, which must be of the same size, added in groups of {@code partitionSize} using {@link
489    * PairedStatsAccumulator#addAll(PairedStats)}.
490    */
createPartitionedFilledPairedStatsAccumulator( List<Double> xValues, List<Double> yValues, int partitionSize)491   static PairedStatsAccumulator createPartitionedFilledPairedStatsAccumulator(
492       List<Double> xValues, List<Double> yValues, int partitionSize) {
493     checkArgument(xValues.size() == yValues.size());
494     checkArgument(partitionSize > 0);
495     PairedStatsAccumulator accumulator = new PairedStatsAccumulator();
496     List<List<Double>> xPartitions = Lists.partition(xValues, partitionSize);
497     List<List<Double>> yPartitions = Lists.partition(yValues, partitionSize);
498     for (int index = 0; index < xPartitions.size(); index++) {
499       accumulator.addAll(createPairedStatsOf(xPartitions.get(index), yPartitions.get(index)));
500     }
501     return accumulator;
502   }
503 
StatsTesting()504   private StatsTesting() {}
505 }
506