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