• 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 import java.util.stream.DoubleStream;
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 
44   static final double ALLOWED_ERROR = 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
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   /**
216    * Returns a stream of a million primitive doubles. The stream is parallel, which should cause
217    * {@code collect} calls to run in multi-threaded mode, so testing the combiner as well as the
218    * supplier and accumulator.
219    */
megaPrimitiveDoubleStream()220   static DoubleStream megaPrimitiveDoubleStream() {
221     return DoubleStream.iterate(0.0, x -> x + 1.0).limit(MEGA_STREAM_COUNT).parallel();
222   }
223 
224   /** Returns a stream containing half the values from {@link #megaPrimitiveDoubleStream}. */
megaPrimitiveDoubleStreamPart1()225   static DoubleStream megaPrimitiveDoubleStreamPart1() {
226     return DoubleStream.iterate(0.0, x -> x + 2.0).limit(MEGA_STREAM_COUNT / 2).parallel();
227   }
228 
229   /**
230    * Returns a stream containing the values from {@link #megaPrimitiveDoubleStream} not in {@link
231    * #megaPrimitiveDoubleStreamPart1()}.
232    */
megaPrimitiveDoubleStreamPart2()233   static DoubleStream megaPrimitiveDoubleStreamPart2() {
234     return DoubleStream.iterate(999_999.0, x -> x - 2.0).limit(MEGA_STREAM_COUNT / 2).parallel();
235   }
236 
237   static final long MEGA_STREAM_COUNT = 1_000_000;
238   static final double MEGA_STREAM_MEAN = 999_999.0 / 2;
239   static final double MEGA_STREAM_POPULATION_VARIANCE = 999_999.0 * 1_000_001.0 / 12;
240   static final double MEGA_STREAM_MIN = 0.0;
241   static final double MEGA_STREAM_MAX = 999_999.0;
242 
243   // Stats instances:
244 
245   static final Stats EMPTY_STATS_VARARGS = Stats.of();
246   static final Stats EMPTY_STATS_ITERABLE = Stats.of(ImmutableList.<Double>of());
247   static final Stats ONE_VALUE_STATS = Stats.of(ONE_VALUE);
248   static final Stats OTHER_ONE_VALUE_STATS = Stats.of(OTHER_ONE_VALUE);
249   static final Stats TWO_VALUES_STATS = Stats.of(TWO_VALUES);
250   static final Stats OTHER_TWO_VALUES_STATS = Stats.of(OTHER_TWO_VALUES);
251   static final Stats MANY_VALUES_STATS_VARARGS = Stats.of(1.1, -44.44, 33.33, 555.555, -2.2);
252   static final Stats MANY_VALUES_STATS_ITERABLE = Stats.of(MANY_VALUES);
253   static final Stats MANY_VALUES_STATS_ITERATOR = Stats.of(MANY_VALUES.iterator());
254   static final Stats MANY_VALUES_STATS_SNAPSHOT = buildManyValuesStatsSnapshot();
255   static final Stats LARGE_VALUES_STATS = Stats.of(LARGE_VALUES);
256   static final Stats OTHER_MANY_VALUES_STATS = Stats.of(OTHER_MANY_VALUES);
257   static final Stats INTEGER_MANY_VALUES_STATS_VARARGS =
258       Stats.of(Ints.toArray(INTEGER_MANY_VALUES));
259   static final Stats INTEGER_MANY_VALUES_STATS_ITERABLE = Stats.of(INTEGER_MANY_VALUES);
260   static final Stats LARGE_INTEGER_VALUES_STATS = Stats.of(LARGE_INTEGER_VALUES);
261   static final Stats LONG_MANY_VALUES_STATS_ITERATOR = Stats.of(LONG_MANY_VALUES.iterator());
262   static final Stats LONG_MANY_VALUES_STATS_SNAPSHOT = buildLongManyValuesStatsSnapshot();
263   static final Stats LARGE_LONG_VALUES_STATS = Stats.of(LARGE_LONG_VALUES);
264 
buildManyValuesStatsSnapshot()265   private static Stats buildManyValuesStatsSnapshot() {
266     StatsAccumulator accumulator = new StatsAccumulator();
267     accumulator.addAll(MANY_VALUES);
268     Stats stats = accumulator.snapshot();
269     accumulator.add(999.999); // should do nothing to the snapshot
270     return stats;
271   }
272 
buildLongManyValuesStatsSnapshot()273   private static Stats buildLongManyValuesStatsSnapshot() {
274     StatsAccumulator accumulator = new StatsAccumulator();
275     accumulator.addAll(LONG_MANY_VALUES);
276     return accumulator.snapshot();
277   }
278 
279   static final ImmutableList<Stats> ALL_STATS =
280       ImmutableList.of(
281           EMPTY_STATS_VARARGS,
282           EMPTY_STATS_ITERABLE,
283           ONE_VALUE_STATS,
284           OTHER_ONE_VALUE_STATS,
285           TWO_VALUES_STATS,
286           OTHER_TWO_VALUES_STATS,
287           MANY_VALUES_STATS_VARARGS,
288           MANY_VALUES_STATS_ITERABLE,
289           MANY_VALUES_STATS_ITERATOR,
290           MANY_VALUES_STATS_SNAPSHOT,
291           LARGE_VALUES_STATS,
292           OTHER_MANY_VALUES_STATS,
293           INTEGER_MANY_VALUES_STATS_VARARGS,
294           INTEGER_MANY_VALUES_STATS_ITERABLE,
295           LARGE_INTEGER_VALUES_STATS,
296           LONG_MANY_VALUES_STATS_ITERATOR,
297           LONG_MANY_VALUES_STATS_SNAPSHOT,
298           LARGE_LONG_VALUES_STATS);
299 
300   // PairedStats instances:
301 
302   static final PairedStats EMPTY_PAIRED_STATS =
303       createPairedStatsOf(ImmutableList.<Double>of(), ImmutableList.<Double>of());
304   static final PairedStats ONE_VALUE_PAIRED_STATS =
305       createPairedStatsOf(ImmutableList.of(ONE_VALUE), ImmutableList.of(OTHER_ONE_VALUE));
306   static final PairedStats TWO_VALUES_PAIRED_STATS =
307       createPairedStatsOf(TWO_VALUES, OTHER_TWO_VALUES);
308   static final PairedStats MANY_VALUES_PAIRED_STATS = buildManyValuesPairedStats();
309   static final PairedStats DUPLICATE_MANY_VALUES_PAIRED_STATS =
310       createPairedStatsOf(MANY_VALUES, OTHER_MANY_VALUES);
311   static final PairedStats HORIZONTAL_VALUES_PAIRED_STATS = buildHorizontalValuesPairedStats();
312   static final PairedStats VERTICAL_VALUES_PAIRED_STATS = buildVerticalValuesPairedStats();
313   static final PairedStats CONSTANT_VALUES_PAIRED_STATS = buildConstantValuesPairedStats();
314 
buildManyValuesPairedStats()315   private static PairedStats buildManyValuesPairedStats() {
316     PairedStatsAccumulator accumulator =
317         createFilledPairedStatsAccumulator(MANY_VALUES, OTHER_MANY_VALUES);
318     PairedStats stats = accumulator.snapshot();
319     accumulator.add(99.99, 9999.9999); // should do nothing to the snapshot
320     return stats;
321   }
322 
buildHorizontalValuesPairedStats()323   private static PairedStats buildHorizontalValuesPairedStats() {
324     PairedStatsAccumulator accumulator = new PairedStatsAccumulator();
325     for (double x : MANY_VALUES) {
326       accumulator.add(x, OTHER_ONE_VALUE);
327     }
328     return accumulator.snapshot();
329   }
330 
buildVerticalValuesPairedStats()331   private static PairedStats buildVerticalValuesPairedStats() {
332     PairedStatsAccumulator accumulator = new PairedStatsAccumulator();
333     for (double y : OTHER_MANY_VALUES) {
334       accumulator.add(ONE_VALUE, y);
335     }
336     return accumulator.snapshot();
337   }
338 
buildConstantValuesPairedStats()339   private static PairedStats buildConstantValuesPairedStats() {
340     PairedStatsAccumulator accumulator = new PairedStatsAccumulator();
341     for (int i = 0; i < MANY_VALUES_COUNT; ++i) {
342       accumulator.add(ONE_VALUE, OTHER_ONE_VALUE);
343     }
344     return accumulator.snapshot();
345   }
346 
347   static final ImmutableList<PairedStats> ALL_PAIRED_STATS =
348       ImmutableList.of(
349           EMPTY_PAIRED_STATS,
350           ONE_VALUE_PAIRED_STATS,
351           TWO_VALUES_PAIRED_STATS,
352           MANY_VALUES_PAIRED_STATS,
353           DUPLICATE_MANY_VALUES_PAIRED_STATS,
354           HORIZONTAL_VALUES_PAIRED_STATS,
355           VERTICAL_VALUES_PAIRED_STATS,
356           CONSTANT_VALUES_PAIRED_STATS);
357 
358   // Helper methods:
359 
assertStatsApproxEqual(Stats expectedStats, Stats actualStats)360   static void assertStatsApproxEqual(Stats expectedStats, Stats actualStats) {
361     assertThat(actualStats.count()).isEqualTo(expectedStats.count());
362     if (expectedStats.count() == 0) {
363       try {
364         actualStats.mean();
365         fail("Expected IllegalStateException");
366       } catch (IllegalStateException expected) {
367       }
368       try {
369         actualStats.populationVariance();
370         fail("Expected IllegalStateException");
371       } catch (IllegalStateException expected) {
372       }
373       try {
374         actualStats.min();
375         fail("Expected IllegalStateException");
376       } catch (IllegalStateException expected) {
377       }
378       try {
379         actualStats.max();
380         fail("Expected IllegalStateException");
381       } catch (IllegalStateException expected) {
382       }
383     } else if (expectedStats.count() == 1) {
384       assertThat(actualStats.mean()).isWithin(ALLOWED_ERROR).of(expectedStats.mean());
385       assertThat(actualStats.populationVariance()).isWithin(0.0).of(0.0);
386       assertThat(actualStats.min()).isWithin(ALLOWED_ERROR).of(expectedStats.min());
387       assertThat(actualStats.max()).isWithin(ALLOWED_ERROR).of(expectedStats.max());
388     } else {
389       assertThat(actualStats.mean()).isWithin(ALLOWED_ERROR).of(expectedStats.mean());
390       assertThat(actualStats.populationVariance())
391           .isWithin(ALLOWED_ERROR)
392           .of(expectedStats.populationVariance());
393       assertThat(actualStats.min()).isWithin(ALLOWED_ERROR).of(expectedStats.min());
394       assertThat(actualStats.max()).isWithin(ALLOWED_ERROR).of(expectedStats.max());
395     }
396   }
397 
398   /**
399    * Asserts that {@code transformation} is diagonal (i.e. neither horizontal or vertical) and
400    * passes through both {@code (x1, y1)} and {@code (x1 + xDelta, y1 + yDelta)}. Includes
401    * assertions about all the public instance methods of {@link LinearTransformation} (on both
402    * {@code transformation} and its inverse). Since the transformation is expected to be diagonal,
403    * neither {@code xDelta} nor {@code yDelta} may be zero.
404    */
assertDiagonalLinearTransformation( LinearTransformation transformation, double x1, double y1, double xDelta, double yDelta)405   static void assertDiagonalLinearTransformation(
406       LinearTransformation transformation, double x1, double y1, double xDelta, double yDelta) {
407     checkArgument(xDelta != 0.0);
408     checkArgument(yDelta != 0.0);
409     assertThat(transformation.isHorizontal()).isFalse();
410     assertThat(transformation.isVertical()).isFalse();
411     assertThat(transformation.inverse().isHorizontal()).isFalse();
412     assertThat(transformation.inverse().isVertical()).isFalse();
413     assertThat(transformation.transform(x1)).isWithin(ALLOWED_ERROR).of(y1);
414     assertThat(transformation.transform(x1 + xDelta)).isWithin(ALLOWED_ERROR).of(y1 + yDelta);
415     assertThat(transformation.inverse().transform(y1)).isWithin(ALLOWED_ERROR).of(x1);
416     assertThat(transformation.inverse().transform(y1 + yDelta))
417         .isWithin(ALLOWED_ERROR)
418         .of(x1 + xDelta);
419     assertThat(transformation.slope()).isWithin(ALLOWED_ERROR).of(yDelta / xDelta);
420     assertThat(transformation.inverse().slope()).isWithin(ALLOWED_ERROR).of(xDelta / yDelta);
421     assertThat(transformation.inverse()).isSameInstanceAs(transformation.inverse());
422     assertThat(transformation.inverse().inverse()).isSameInstanceAs(transformation);
423   }
424 
425   /**
426    * Asserts that {@code transformation} is horizontal with the given value of {@code y}. Includes
427    * assertions about all the public instance methods of {@link LinearTransformation}, including an
428    * assertion that {@link LinearTransformation#transform} and {@link LinearTransformation#slope} on
429    * its inverse throws as expected.
430    */
assertHorizontalLinearTransformation(LinearTransformation transformation, double y)431   static void assertHorizontalLinearTransformation(LinearTransformation transformation, double y) {
432     assertThat(transformation.isHorizontal()).isTrue();
433     assertThat(transformation.isVertical()).isFalse();
434     assertThat(transformation.inverse().isHorizontal()).isFalse();
435     assertThat(transformation.inverse().isVertical()).isTrue();
436     assertThat(transformation.transform(-1.0)).isWithin(ALLOWED_ERROR).of(y);
437     assertThat(transformation.transform(1.0)).isWithin(ALLOWED_ERROR).of(y);
438     try {
439       transformation.inverse().transform(0.0);
440       fail("Expected IllegalStateException");
441     } catch (IllegalStateException expected) {
442     }
443     assertThat(transformation.slope()).isWithin(ALLOWED_ERROR).of(0.0);
444     try {
445       transformation.inverse().slope();
446       fail("Expected IllegalStateException");
447     } catch (IllegalStateException expected) {
448     }
449     assertThat(transformation.inverse()).isSameInstanceAs(transformation.inverse());
450     assertThat(transformation.inverse().inverse()).isSameInstanceAs(transformation);
451   }
452 
453   /**
454    * Asserts that {@code transformation} is vertical with the given value of {@code x}. Includes
455    * assertions about all the public instance methods of {@link LinearTransformation}, including
456    * assertions that {@link LinearTransformation#slope} and {@link LinearTransformation#transform}
457    * throw as expected.
458    */
assertVerticalLinearTransformation(LinearTransformation transformation, double x)459   static void assertVerticalLinearTransformation(LinearTransformation transformation, double x) {
460     assertThat(transformation.isHorizontal()).isFalse();
461     assertThat(transformation.isVertical()).isTrue();
462     assertThat(transformation.inverse().isHorizontal()).isTrue();
463     assertThat(transformation.inverse().isVertical()).isFalse();
464     try {
465       transformation.transform(0.0);
466       fail("Expected IllegalStateException");
467     } catch (IllegalStateException expected) {
468     }
469     assertThat(transformation.inverse().transform(-1.0)).isWithin(ALLOWED_ERROR).of(x);
470     assertThat(transformation.inverse().transform(1.0)).isWithin(ALLOWED_ERROR).of(x);
471     try {
472       transformation.slope();
473       fail("Expected IllegalStateException");
474     } catch (IllegalStateException expected) {
475     }
476     assertThat(transformation.inverse().slope()).isWithin(ALLOWED_ERROR).of(0.0);
477     assertThat(transformation.inverse()).isSameInstanceAs(transformation.inverse());
478     assertThat(transformation.inverse().inverse()).isSameInstanceAs(transformation);
479   }
480 
481   /**
482    * Asserts that {@code transformation} behaves as expected for {@link
483    * LinearTransformation#forNaN}.
484    */
assertLinearTransformationNaN(LinearTransformation transformation)485   static void assertLinearTransformationNaN(LinearTransformation transformation) {
486     assertThat(transformation.isHorizontal()).isFalse();
487     assertThat(transformation.isVertical()).isFalse();
488     assertThat(transformation.slope()).isNaN();
489     assertThat(transformation.transform(0.0)).isNaN();
490     assertThat(transformation.inverse()).isSameInstanceAs(transformation);
491   }
492 
493   /**
494    * Creates a {@link PairedStats} from with the given lists of {@code x} and {@code y} values,
495    * which must be of the same size.
496    */
createPairedStatsOf(List<Double> xValues, List<Double> yValues)497   static PairedStats createPairedStatsOf(List<Double> xValues, List<Double> yValues) {
498     return createFilledPairedStatsAccumulator(xValues, yValues).snapshot();
499   }
500 
501   /**
502    * Creates a {@link PairedStatsAccumulator} filled with the given lists of {@code x} and {@code y}
503    * values, which must be of the same size.
504    */
createFilledPairedStatsAccumulator( List<Double> xValues, List<Double> yValues)505   static PairedStatsAccumulator createFilledPairedStatsAccumulator(
506       List<Double> xValues, List<Double> yValues) {
507     checkArgument(xValues.size() == yValues.size());
508     PairedStatsAccumulator accumulator = new PairedStatsAccumulator();
509     for (int index = 0; index < xValues.size(); index++) {
510       accumulator.add(xValues.get(index), yValues.get(index));
511     }
512     return accumulator;
513   }
514 
515   /**
516    * Creates a {@link PairedStatsAccumulator} filled with the given lists of {@code x} and {@code y}
517    * values, which must be of the same size, added in groups of {@code partitionSize} using {@link
518    * PairedStatsAccumulator#addAll(PairedStats)}.
519    */
createPartitionedFilledPairedStatsAccumulator( List<Double> xValues, List<Double> yValues, int partitionSize)520   static PairedStatsAccumulator createPartitionedFilledPairedStatsAccumulator(
521       List<Double> xValues, List<Double> yValues, int partitionSize) {
522     checkArgument(xValues.size() == yValues.size());
523     checkArgument(partitionSize > 0);
524     PairedStatsAccumulator accumulator = new PairedStatsAccumulator();
525     List<List<Double>> xPartitions = Lists.partition(xValues, partitionSize);
526     List<List<Double>> yPartitions = Lists.partition(yValues, partitionSize);
527     for (int index = 0; index < xPartitions.size(); index++) {
528       accumulator.addAll(createPairedStatsOf(xPartitions.get(index), yPartitions.get(index)));
529     }
530     return accumulator;
531   }
532 
StatsTesting()533   private StatsTesting() {}
534 }
535