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