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