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