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