• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 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.math.StatsTesting.ALLOWED_ERROR;
20 import static com.google.common.math.StatsTesting.ALL_MANY_VALUES;
21 import static com.google.common.math.StatsTesting.ALL_PAIRED_STATS;
22 import static com.google.common.math.StatsTesting.CONSTANT_VALUES_PAIRED_STATS;
23 import static com.google.common.math.StatsTesting.DUPLICATE_MANY_VALUES_PAIRED_STATS;
24 import static com.google.common.math.StatsTesting.EMPTY_PAIRED_STATS;
25 import static com.google.common.math.StatsTesting.EMPTY_STATS_ITERABLE;
26 import static com.google.common.math.StatsTesting.HORIZONTAL_VALUES_PAIRED_STATS;
27 import static com.google.common.math.StatsTesting.MANY_VALUES;
28 import static com.google.common.math.StatsTesting.MANY_VALUES_COUNT;
29 import static com.google.common.math.StatsTesting.MANY_VALUES_PAIRED_STATS;
30 import static com.google.common.math.StatsTesting.MANY_VALUES_STATS_ITERABLE;
31 import static com.google.common.math.StatsTesting.MANY_VALUES_STATS_VARARGS;
32 import static com.google.common.math.StatsTesting.MANY_VALUES_SUM_OF_PRODUCTS_OF_DELTAS;
33 import static com.google.common.math.StatsTesting.ONE_VALUE_PAIRED_STATS;
34 import static com.google.common.math.StatsTesting.ONE_VALUE_STATS;
35 import static com.google.common.math.StatsTesting.OTHER_MANY_VALUES;
36 import static com.google.common.math.StatsTesting.OTHER_MANY_VALUES_STATS;
37 import static com.google.common.math.StatsTesting.OTHER_ONE_VALUE_STATS;
38 import static com.google.common.math.StatsTesting.OTHER_TWO_VALUES_STATS;
39 import static com.google.common.math.StatsTesting.TWO_VALUES_PAIRED_STATS;
40 import static com.google.common.math.StatsTesting.TWO_VALUES_STATS;
41 import static com.google.common.math.StatsTesting.TWO_VALUES_SUM_OF_PRODUCTS_OF_DELTAS;
42 import static com.google.common.math.StatsTesting.VERTICAL_VALUES_PAIRED_STATS;
43 import static com.google.common.math.StatsTesting.assertDiagonalLinearTransformation;
44 import static com.google.common.math.StatsTesting.assertHorizontalLinearTransformation;
45 import static com.google.common.math.StatsTesting.assertLinearTransformationNaN;
46 import static com.google.common.math.StatsTesting.assertStatsApproxEqual;
47 import static com.google.common.math.StatsTesting.assertVerticalLinearTransformation;
48 import static com.google.common.math.StatsTesting.createPairedStatsOf;
49 import static com.google.common.truth.Truth.assertThat;
50 import static com.google.common.truth.Truth.assertWithMessage;
51 import static org.junit.Assert.assertThrows;
52 
53 import com.google.common.collect.ImmutableList;
54 import com.google.common.math.StatsTesting.ManyValues;
55 import com.google.common.testing.EqualsTester;
56 import com.google.common.testing.SerializableTester;
57 import java.nio.ByteBuffer;
58 import java.nio.ByteOrder;
59 import junit.framework.TestCase;
60 
61 /**
62  * Tests for {@link PairedStats}. This tests instances created by {@link
63  * PairedStatsAccumulator#snapshot}.
64  *
65  * @author Pete Gillin
66  */
67 public class PairedStatsTest extends TestCase {
68 
testCount()69   public void testCount() {
70     assertThat(EMPTY_PAIRED_STATS.count()).isEqualTo(0);
71     assertThat(ONE_VALUE_PAIRED_STATS.count()).isEqualTo(1);
72     assertThat(TWO_VALUES_PAIRED_STATS.count()).isEqualTo(2);
73     assertThat(MANY_VALUES_PAIRED_STATS.count()).isEqualTo(MANY_VALUES_COUNT);
74   }
75 
testXStats()76   public void testXStats() {
77     assertStatsApproxEqual(EMPTY_STATS_ITERABLE, EMPTY_PAIRED_STATS.xStats());
78     assertStatsApproxEqual(ONE_VALUE_STATS, ONE_VALUE_PAIRED_STATS.xStats());
79     assertStatsApproxEqual(TWO_VALUES_STATS, TWO_VALUES_PAIRED_STATS.xStats());
80     assertStatsApproxEqual(MANY_VALUES_STATS_ITERABLE, MANY_VALUES_PAIRED_STATS.xStats());
81   }
82 
testYStats()83   public void testYStats() {
84     assertStatsApproxEqual(EMPTY_STATS_ITERABLE, EMPTY_PAIRED_STATS.yStats());
85     assertStatsApproxEqual(OTHER_ONE_VALUE_STATS, ONE_VALUE_PAIRED_STATS.yStats());
86     assertStatsApproxEqual(OTHER_TWO_VALUES_STATS, TWO_VALUES_PAIRED_STATS.yStats());
87     assertStatsApproxEqual(OTHER_MANY_VALUES_STATS, MANY_VALUES_PAIRED_STATS.yStats());
88   }
89 
testPopulationCovariance()90   public void testPopulationCovariance() {
91     assertThrows(IllegalStateException.class, () -> EMPTY_PAIRED_STATS.populationCovariance());
92     assertThat(ONE_VALUE_PAIRED_STATS.populationCovariance()).isEqualTo(0.0);
93     assertThat(createSingleStats(Double.POSITIVE_INFINITY, 1.23).populationCovariance()).isNaN();
94     assertThat(createSingleStats(Double.NEGATIVE_INFINITY, 1.23).populationCovariance()).isNaN();
95     assertThat(createSingleStats(Double.NaN, 1.23).populationCovariance()).isNaN();
96     assertThat(TWO_VALUES_PAIRED_STATS.populationCovariance())
97         .isWithin(ALLOWED_ERROR)
98         .of(TWO_VALUES_SUM_OF_PRODUCTS_OF_DELTAS / 2);
99     // For datasets of many double values, we test many combinations of finite and non-finite
100     // x-values:
101     for (ManyValues values : ALL_MANY_VALUES) {
102       PairedStats stats = createPairedStatsOf(values.asIterable(), OTHER_MANY_VALUES);
103       double populationCovariance = stats.populationCovariance();
104       if (values.hasAnyNonFinite()) {
105         assertWithMessage("population covariance of " + values).that(populationCovariance).isNaN();
106       } else {
107         assertWithMessage("population covariance of " + values)
108             .that(populationCovariance)
109             .isWithin(ALLOWED_ERROR)
110             .of(MANY_VALUES_SUM_OF_PRODUCTS_OF_DELTAS / MANY_VALUES_COUNT);
111       }
112     }
113     assertThat(HORIZONTAL_VALUES_PAIRED_STATS.populationCovariance())
114         .isWithin(ALLOWED_ERROR)
115         .of(0.0);
116     assertThat(VERTICAL_VALUES_PAIRED_STATS.populationCovariance()).isWithin(ALLOWED_ERROR).of(0.0);
117     assertThat(CONSTANT_VALUES_PAIRED_STATS.populationCovariance()).isWithin(ALLOWED_ERROR).of(0.0);
118   }
119 
testSampleCovariance()120   public void testSampleCovariance() {
121     assertThrows(IllegalStateException.class, () -> EMPTY_PAIRED_STATS.sampleCovariance());
122     assertThrows(IllegalStateException.class, () -> ONE_VALUE_PAIRED_STATS.sampleCovariance());
123     assertThat(TWO_VALUES_PAIRED_STATS.sampleCovariance())
124         .isWithin(ALLOWED_ERROR)
125         .of(TWO_VALUES_SUM_OF_PRODUCTS_OF_DELTAS);
126     assertThat(MANY_VALUES_PAIRED_STATS.sampleCovariance())
127         .isWithin(ALLOWED_ERROR)
128         .of(MANY_VALUES_SUM_OF_PRODUCTS_OF_DELTAS / (MANY_VALUES_COUNT - 1));
129     assertThat(HORIZONTAL_VALUES_PAIRED_STATS.sampleCovariance()).isWithin(ALLOWED_ERROR).of(0.0);
130     assertThat(VERTICAL_VALUES_PAIRED_STATS.sampleCovariance()).isWithin(ALLOWED_ERROR).of(0.0);
131     assertThat(CONSTANT_VALUES_PAIRED_STATS.sampleCovariance()).isWithin(ALLOWED_ERROR).of(0.0);
132   }
133 
testPearsonsCorrelationCoefficient()134   public void testPearsonsCorrelationCoefficient() {
135     assertThrows(
136         IllegalStateException.class, () -> EMPTY_PAIRED_STATS.pearsonsCorrelationCoefficient());
137     assertThrows(
138         IllegalStateException.class, () -> ONE_VALUE_PAIRED_STATS.pearsonsCorrelationCoefficient());
139     assertThrows(
140         IllegalStateException.class,
141         () -> createSingleStats(Double.POSITIVE_INFINITY, 1.23).pearsonsCorrelationCoefficient());
142     assertThat(TWO_VALUES_PAIRED_STATS.pearsonsCorrelationCoefficient())
143         .isWithin(ALLOWED_ERROR)
144         .of(
145             TWO_VALUES_PAIRED_STATS.populationCovariance()
146                 / (TWO_VALUES_PAIRED_STATS.xStats().populationStandardDeviation()
147                     * TWO_VALUES_PAIRED_STATS.yStats().populationStandardDeviation()));
148     // For datasets of many double values, we test many combinations of finite and non-finite
149     // y-values:
150     for (ManyValues values : ALL_MANY_VALUES) {
151       PairedStats stats = createPairedStatsOf(MANY_VALUES, values.asIterable());
152       double pearsonsCorrelationCoefficient = stats.pearsonsCorrelationCoefficient();
153       if (values.hasAnyNonFinite()) {
154         assertWithMessage("Pearson's correlation coefficient of " + values)
155             .that(pearsonsCorrelationCoefficient)
156             .isNaN();
157       } else {
158         assertWithMessage("Pearson's correlation coefficient of " + values)
159             .that(pearsonsCorrelationCoefficient)
160             .isWithin(ALLOWED_ERROR)
161             .of(
162                 stats.populationCovariance()
163                     / (stats.xStats().populationStandardDeviation()
164                         * stats.yStats().populationStandardDeviation()));
165       }
166     }
167     assertThrows(
168         IllegalStateException.class,
169         () -> HORIZONTAL_VALUES_PAIRED_STATS.pearsonsCorrelationCoefficient());
170     assertThrows(
171         IllegalStateException.class,
172         () -> VERTICAL_VALUES_PAIRED_STATS.pearsonsCorrelationCoefficient());
173     assertThrows(
174         IllegalStateException.class,
175         () -> CONSTANT_VALUES_PAIRED_STATS.pearsonsCorrelationCoefficient());
176   }
177 
testLeastSquaresFit()178   public void testLeastSquaresFit() {
179     assertThrows(IllegalStateException.class, () -> EMPTY_PAIRED_STATS.leastSquaresFit());
180     assertThrows(IllegalStateException.class, () -> ONE_VALUE_PAIRED_STATS.leastSquaresFit());
181     assertThrows(
182         IllegalStateException.class,
183         () -> createSingleStats(Double.POSITIVE_INFINITY, 1.23).leastSquaresFit());
184     assertDiagonalLinearTransformation(
185         TWO_VALUES_PAIRED_STATS.leastSquaresFit(),
186         TWO_VALUES_PAIRED_STATS.xStats().mean(),
187         TWO_VALUES_PAIRED_STATS.yStats().mean(),
188         TWO_VALUES_PAIRED_STATS.xStats().populationVariance(),
189         TWO_VALUES_PAIRED_STATS.populationCovariance());
190     // For datasets of many double values, we test many combinations of finite and non-finite
191     // x-values:
192     for (ManyValues values : ALL_MANY_VALUES) {
193       PairedStats stats = createPairedStatsOf(values.asIterable(), OTHER_MANY_VALUES);
194       LinearTransformation fit = stats.leastSquaresFit();
195       if (values.hasAnyNonFinite()) {
196         assertLinearTransformationNaN(fit);
197       } else {
198         assertDiagonalLinearTransformation(
199             fit,
200             stats.xStats().mean(),
201             stats.yStats().mean(),
202             stats.xStats().populationVariance(),
203             stats.populationCovariance());
204       }
205     }
206     assertHorizontalLinearTransformation(
207         HORIZONTAL_VALUES_PAIRED_STATS.leastSquaresFit(),
208         HORIZONTAL_VALUES_PAIRED_STATS.yStats().mean());
209     assertVerticalLinearTransformation(
210         VERTICAL_VALUES_PAIRED_STATS.leastSquaresFit(),
211         VERTICAL_VALUES_PAIRED_STATS.xStats().mean());
212     assertThrows(IllegalStateException.class, () -> CONSTANT_VALUES_PAIRED_STATS.leastSquaresFit());
213   }
214 
testEqualsAndHashCode()215   public void testEqualsAndHashCode() {
216     new EqualsTester()
217         .addEqualityGroup(
218             MANY_VALUES_PAIRED_STATS,
219             DUPLICATE_MANY_VALUES_PAIRED_STATS,
220             SerializableTester.reserialize(MANY_VALUES_PAIRED_STATS))
221         .addEqualityGroup(
222             new PairedStats(MANY_VALUES_STATS_ITERABLE, OTHER_MANY_VALUES_STATS, 1.23),
223             new PairedStats(MANY_VALUES_STATS_VARARGS, OTHER_MANY_VALUES_STATS, 1.23))
224         .addEqualityGroup(
225             new PairedStats(OTHER_MANY_VALUES_STATS, MANY_VALUES_STATS_ITERABLE, 1.23))
226         .addEqualityGroup(
227             new PairedStats(MANY_VALUES_STATS_ITERABLE, MANY_VALUES_STATS_ITERABLE, 1.23))
228         .addEqualityGroup(new PairedStats(TWO_VALUES_STATS, MANY_VALUES_STATS_ITERABLE, 1.23))
229         .addEqualityGroup(new PairedStats(MANY_VALUES_STATS_ITERABLE, ONE_VALUE_STATS, 1.23))
230         .addEqualityGroup(
231             new PairedStats(MANY_VALUES_STATS_ITERABLE, MANY_VALUES_STATS_ITERABLE, 1.234))
232         .testEquals();
233   }
234 
testSerializable()235   public void testSerializable() {
236     SerializableTester.reserializeAndAssert(MANY_VALUES_PAIRED_STATS);
237   }
238 
testToString()239   public void testToString() {
240     assertThat(EMPTY_PAIRED_STATS.toString())
241         .isEqualTo("PairedStats{xStats=Stats{count=0}, yStats=Stats{count=0}}");
242     assertThat(MANY_VALUES_PAIRED_STATS.toString())
243         .isEqualTo(
244             "PairedStats{xStats="
245                 + MANY_VALUES_PAIRED_STATS.xStats()
246                 + ", yStats="
247                 + MANY_VALUES_PAIRED_STATS.yStats()
248                 + ", populationCovariance="
249                 + MANY_VALUES_PAIRED_STATS.populationCovariance()
250                 + "}");
251   }
252 
createSingleStats(double x, double y)253   private PairedStats createSingleStats(double x, double y) {
254     return createPairedStatsOf(ImmutableList.of(x), ImmutableList.of(y));
255   }
256 
testToByteArrayAndFromByteArrayRoundTrip()257   public void testToByteArrayAndFromByteArrayRoundTrip() {
258     for (PairedStats pairedStats : ALL_PAIRED_STATS) {
259       byte[] pairedStatsByteArray = pairedStats.toByteArray();
260 
261       // Round trip to byte array and back
262       assertThat(PairedStats.fromByteArray(pairedStatsByteArray)).isEqualTo(pairedStats);
263     }
264   }
265 
testFromByteArray_withNullInputThrowsNullPointerException()266   public void testFromByteArray_withNullInputThrowsNullPointerException() {
267     assertThrows(NullPointerException.class, () -> PairedStats.fromByteArray(null));
268   }
269 
testFromByteArray_withEmptyArrayInputThrowsIllegalArgumentException()270   public void testFromByteArray_withEmptyArrayInputThrowsIllegalArgumentException() {
271     assertThrows(IllegalArgumentException.class, () -> PairedStats.fromByteArray(new byte[0]));
272   }
273 
testFromByteArray_withTooLongArrayInputThrowsIllegalArgumentException()274   public void testFromByteArray_withTooLongArrayInputThrowsIllegalArgumentException() {
275     byte[] buffer = MANY_VALUES_PAIRED_STATS.toByteArray();
276     byte[] tooLongByteArray =
277         ByteBuffer.allocate(buffer.length + 2)
278             .order(ByteOrder.LITTLE_ENDIAN)
279             .put(buffer)
280             .putChar('.')
281             .array();
282     assertThrows(IllegalArgumentException.class, () -> PairedStats.fromByteArray(tooLongByteArray));
283   }
284 
testFromByteArrayWithTooShortArrayInputThrowsIllegalArgumentException()285   public void testFromByteArrayWithTooShortArrayInputThrowsIllegalArgumentException() {
286     byte[] buffer = MANY_VALUES_PAIRED_STATS.toByteArray();
287     byte[] tooShortByteArray =
288         ByteBuffer.allocate(buffer.length - 1)
289             .order(ByteOrder.LITTLE_ENDIAN)
290             .put(buffer, 0, buffer.length - 1)
291             .array();
292     assertThrows(
293         IllegalArgumentException.class, () -> PairedStats.fromByteArray(tooShortByteArray));
294   }
295 }
296