1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 package org.hipparchus;
24
25 import org.hipparchus.complex.Complex;
26 import org.hipparchus.complex.ComplexFormat;
27 import org.hipparchus.complex.FieldComplex;
28 import org.hipparchus.distribution.RealDistribution;
29 import org.hipparchus.distribution.continuous.ChiSquaredDistribution;
30 import org.hipparchus.linear.BlockRealMatrix;
31 import org.hipparchus.linear.FieldMatrix;
32 import org.hipparchus.linear.RealMatrix;
33 import org.hipparchus.linear.RealVector;
34 import org.hipparchus.util.Binary64;
35 import org.hipparchus.util.FastMath;
36 import org.hipparchus.util.Precision;
37
38 import java.io.ByteArrayInputStream;
39 import java.io.ByteArrayOutputStream;
40 import java.io.IOException;
41 import java.io.ObjectInputStream;
42 import java.io.ObjectOutputStream;
43 import java.text.DecimalFormat;
44 import java.util.ArrayList;
45 import java.util.Arrays;
46 import java.util.HashMap;
47 import java.util.List;
48 import java.util.Map;
49
50 import static org.junit.jupiter.api.Assertions.assertEquals;
51 import static org.junit.jupiter.api.Assertions.assertNotNull;
52 import static org.junit.jupiter.api.Assertions.assertTrue;
53 import static org.junit.jupiter.api.Assertions.fail;
54
55
56
57 public class UnitTestUtils {
58
59
60
61 private UnitTestUtils() {
62 super();
63 }
64
65
66
67
68
69 public static void customAssertEquals(double expected, double actual, double delta) {
70 assertEquals(expected, actual, delta);
71 }
72
73
74
75
76
77 public static void customAssertEquals(String msg, double expected, double actual, double delta) {
78
79 if(Double.isNaN(expected)){
80 assertTrue(Double.isNaN(actual),
81 "" + actual + " is not NaN.");
82 } else {
83 assertEquals(expected, actual, delta, msg);
84 }
85 }
86
87
88
89
90
91 public static void customAssertSame(double expected, double actual) {
92 assertEquals(expected, actual, 0);
93 }
94
95
96
97
98
99 public static void customAssertSame(Complex expected, Complex actual) {
100 customAssertSame(expected.getRealPart(), actual.getRealPart());
101 customAssertSame(expected.getImaginaryPart(), actual.getImaginaryPart());
102 }
103
104
105
106
107
108 public static void customAssertEquals(Complex expected, Complex actual, double delta) {
109 assertEquals(expected.getRealPart(), actual.getRealPart(), delta);
110 assertEquals(expected.getImaginaryPart(), actual.getImaginaryPart(), delta);
111 }
112
113
114
115
116
117 public static void customAssertEquals(FieldComplex<Binary64> expected, FieldComplex<Binary64> actual, double delta) {
118 assertEquals(expected.getRealPart().getReal(), actual.getRealPart().getReal(), delta);
119 assertEquals(expected.getImaginaryPart().getReal(), actual.getImaginaryPart().getReal(), delta);
120 }
121
122
123
124
125
126 public static void customAssertSame(FieldComplex<Binary64> expected, FieldComplex<Binary64> actual) {
127 customAssertSame(expected.getRealPart().getReal(), actual.getRealPart().getReal());
128 customAssertSame(expected.getImaginaryPart().getReal(), actual.getImaginaryPart().getReal());
129 }
130
131
132
133
134 public static void customAssertEquals(double[] expected, double[] observed, double tolerance) {
135 customAssertEquals("Array comparison failure", expected, observed, tolerance);
136 }
137
138
139
140
141
142
143
144
145 public static Object serializeAndRecover(Object o) {
146 try {
147
148 ByteArrayOutputStream bos = new ByteArrayOutputStream();
149 ObjectOutputStream so = new ObjectOutputStream(bos);
150 so.writeObject(o);
151
152
153 ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
154 ObjectInputStream si = new ObjectInputStream(bis);
155 return si.readObject();
156 } catch (IOException ioe) {
157 return null;
158 } catch (ClassNotFoundException cnfe) {
159 return null;
160 }
161 }
162
163
164
165
166
167
168
169 public static void checkSerializedEquality(Object object) {
170 Object object2 = serializeAndRecover(object);
171 assertEquals(object, object2, "Equals check");
172 assertEquals(object.hashCode(), object2.hashCode(), "HashCode check");
173 }
174
175
176
177
178
179
180
181
182
183
184 public static void customAssertRelativelyEquals(double expected, double actual,
185 double relativeError) {
186 customAssertRelativelyEquals(null, expected, actual, relativeError);
187 }
188
189
190
191
192
193
194
195
196
197
198
199 public static void customAssertRelativelyEquals(String msg, double expected,
200 double actual, double relativeError) {
201 if (Double.isNaN(expected)) {
202 assertTrue(Double.isNaN(actual), msg);
203 } else if (Double.isNaN(actual)) {
204 assertTrue(Double.isNaN(expected), msg);
205 } else if (Double.isInfinite(actual) || Double.isInfinite(expected)) {
206 assertEquals(expected, actual, relativeError);
207 } else if (expected == 0.0) {
208 assertEquals(actual, expected, relativeError, msg);
209 } else {
210 double absError = FastMath.abs(expected) * relativeError;
211 assertEquals(expected, actual, absError, msg);
212 }
213 }
214
215
216
217
218
219
220
221
222
223 public static void customAssertContains(String msg, Complex[] values,
224 Complex z, double epsilon) {
225 for (Complex value : values) {
226 if (Precision.equals(value.getReal(), z.getReal(), epsilon) &&
227 Precision.equals(value.getImaginary(), z.getImaginary(), epsilon)) {
228 return;
229 }
230 }
231 fail(msg + " Unable to find " + (new ComplexFormat()).format(z));
232 }
233
234
235
236
237
238
239
240
241 public static void customAssertContains(Complex[] values,
242 Complex z, double epsilon) {
243 customAssertContains(null, values, z, epsilon);
244 }
245
246
247
248
249
250
251
252
253
254 public static void customAssertContains(String msg, double[] values,
255 double x, double epsilon) {
256 for (double value : values) {
257 if (Precision.equals(value, x, epsilon)) {
258 return;
259 }
260 }
261 fail(msg + " Unable to find " + x);
262 }
263
264
265
266
267
268
269
270
271 public static void customAssertContains(double[] values, double x,
272 double epsilon) {
273 customAssertContains(null, values, x, epsilon);
274 }
275
276
277
278
279
280
281
282
283
284
285
286
287 public static void customAssertEquals(final String message,
288 final double[] expected, final RealVector actual, final double delta) {
289 final String msgAndSep = message.equals("") ? "" : message + ", ";
290 assertEquals(expected.length,
291 actual.getDimension(),
292 msgAndSep + "dimension");
293 for (int i = 0; i < expected.length; i++) {
294 assertEquals(expected[i],
295 actual.getEntry(i), delta, msgAndSep + "entry #" + i);
296 }
297 }
298
299
300
301
302
303
304
305
306
307
308
309
310 public static void customAssertEquals(final String message,
311 final RealVector expected, final RealVector actual, final double delta) {
312 final String msgAndSep = message.equals("") ? "" : message + ", ";
313 assertEquals(expected.getDimension(),
314 actual.getDimension(),
315 msgAndSep + "dimension");
316 final int dim = expected.getDimension();
317 for (int i = 0; i < dim; i++) {
318 assertEquals(expected.getEntry(i), actual.getEntry(i), delta, msgAndSep + "entry #" + i);
319 }
320 }
321
322
323 public static void customAssertEquals(String msg, RealMatrix expected, RealMatrix observed, double tolerance) {
324
325 assertNotNull(observed,msg + "\nObserved should not be null");
326
327 if (expected.getColumnDimension() != observed.getColumnDimension() ||
328 expected.getRowDimension() != observed.getRowDimension()) {
329 StringBuilder messageBuffer = new StringBuilder(msg);
330 messageBuffer.append("\nObserved has incorrect dimensions.");
331 messageBuffer.append("\nobserved is " + observed.getRowDimension() +
332 " x " + observed.getColumnDimension());
333 messageBuffer.append("\nexpected " + expected.getRowDimension() +
334 " x " + expected.getColumnDimension());
335 fail(messageBuffer.toString());
336 }
337
338 RealMatrix delta = expected.subtract(observed);
339 if (delta.getNorm1() >= tolerance) {
340 StringBuilder messageBuffer = new StringBuilder(msg);
341 messageBuffer.append("\nExpected: " + expected);
342 messageBuffer.append("\nObserved: " + observed);
343 messageBuffer.append("\nexpected - observed: " + delta);
344 fail(messageBuffer.toString());
345 }
346 }
347
348
349 public static void customAssertEquals(FieldMatrix<? extends FieldElement<?>> expected,
350 FieldMatrix<? extends FieldElement<?>> observed) {
351
352 assertNotNull(observed,"Observed should not be null");
353
354 if (expected.getColumnDimension() != observed.getColumnDimension() ||
355 expected.getRowDimension() != observed.getRowDimension()) {
356 StringBuilder messageBuffer = new StringBuilder();
357 messageBuffer.append("Observed has incorrect dimensions.");
358 messageBuffer.append("\nobserved is " + observed.getRowDimension() +
359 " x " + observed.getColumnDimension());
360 messageBuffer.append("\nexpected " + expected.getRowDimension() +
361 " x " + expected.getColumnDimension());
362 fail(messageBuffer.toString());
363 }
364
365 for (int i = 0; i < expected.getRowDimension(); ++i) {
366 for (int j = 0; j < expected.getColumnDimension(); ++j) {
367 FieldElement<?> eij = expected.getEntry(i, j);
368 FieldElement<?> oij = observed.getEntry(i, j);
369 assertEquals(eij, oij);
370 }
371 }
372 }
373
374
375 public static void customAssertEquals(String msg, double[] expected, double[] observed, double tolerance) {
376 StringBuilder out = new StringBuilder(msg);
377 if (expected.length != observed.length) {
378 out.append("\n Arrays not same length. \n");
379 out.append("expected has length ");
380 out.append(expected.length);
381 out.append(" observed length = ");
382 out.append(observed.length);
383 fail(out.toString());
384 }
385 boolean failure = false;
386 for (int i=0; i < expected.length; i++) {
387 if (!Precision.equalsIncludingNaN(expected[i], observed[i], tolerance)) {
388 failure = true;
389 out.append("\n Elements at index ");
390 out.append(i);
391 out.append(" differ. ");
392 out.append(" expected = ");
393 out.append(expected[i]);
394 out.append(" observed = ");
395 out.append(observed[i]);
396 }
397 }
398 if (failure) {
399 fail(out.toString());
400 }
401 }
402
403
404 public static void customAssertEquals(int[] expected, int[] observed) {
405 StringBuilder out = new StringBuilder();
406 if (expected.length != observed.length) {
407 out.append("\n Arrays not same length. \n");
408 out.append("expected has length ");
409 out.append(expected.length);
410 out.append(" observed length = ");
411 out.append(observed.length);
412 fail(out.toString());
413 }
414 boolean failure = false;
415 for (int i=0; i < expected.length; i++) {
416 if (expected[i] != observed[i]) {
417 failure = true;
418 out.append("\n Elements at index ");
419 out.append(i);
420 out.append(" differ. ");
421 out.append(" expected = ");
422 out.append(expected[i]);
423 out.append(" observed = ");
424 out.append(observed[i]);
425 }
426 }
427 if (failure) {
428 fail(out.toString());
429 }
430 }
431
432
433
434
435
436 public static void customAssertContains(double[][] expected, double[] observed, double epsilon) {
437 StringBuilder out = new StringBuilder();
438 if (expected.length != observed.length) {
439 out.append("\n Arrays not same length. \n");
440 out.append("expected has length ");
441 out.append(expected.length);
442 out.append(" observed length = ");
443 out.append(observed.length);
444 fail(out.toString());
445 }
446 boolean failure = false;
447 for (int i = 0; i < expected.length; i++) {
448 boolean found = false;
449 for (int j = 0; j < expected[i].length; j++) {
450 if (Precision.equalsIncludingNaN(expected[i][j], observed[i], epsilon)) {
451 found = true;
452 break;
453 }
454 }
455 if (!found) {
456 out.append("\n Observed element at index ");
457 out.append(i);
458 out.append(" is not among the expected values. ");
459 out.append(" expected = " + Arrays.toString(expected[i]));
460 out.append(" observed = ");
461 out.append(observed[i]);
462 failure = true;
463 }
464 }
465 if (failure) {
466 fail(out.toString());
467 }
468 }
469
470
471
472
473 public static void customAssertEquals(long[] expected, long[] observed) {
474 StringBuilder out = new StringBuilder();
475 if (expected.length != observed.length) {
476 out.append("\n Arrays not same length. \n");
477 out.append("expected has length ");
478 out.append(expected.length);
479 out.append(" observed length = ");
480 out.append(observed.length);
481 fail(out.toString());
482 }
483 boolean failure = false;
484 for (int i=0; i < expected.length; i++) {
485 if (expected[i] != observed[i]) {
486 failure = true;
487 out.append("\n Elements at index ");
488 out.append(i);
489 out.append(" differ. ");
490 out.append(" expected = ");
491 out.append(expected[i]);
492 out.append(" observed = ");
493 out.append(observed[i]);
494 }
495 }
496 if (failure) {
497 fail(out.toString());
498 }
499 }
500
501
502 public static <T extends FieldElement<T>> void customAssertEquals(T[] m, T[] n) {
503 if (m.length != n.length) {
504 fail("vectors not same length");
505 }
506 for (int i = 0; i < m.length; i++) {
507 assertEquals(m[i],n[i]);
508 }
509 }
510
511
512
513
514
515
516
517
518 public static double sumSquareDev(double[] values, double target) {
519 double sumsq = 0d;
520 for (int i = 0; i < values.length; i++) {
521 final double dev = values[i] - target;
522 sumsq += (dev * dev);
523 }
524 return sumsq;
525 }
526
527
528
529
530
531
532
533
534
535
536 public static void customAssertChiSquareAccept(String[] valueLabels, double[] expected, long[] observed, double alpha) {
537
538
539 if (chiSquareTest(expected, observed) <= alpha) {
540 StringBuilder msgBuffer = new StringBuilder();
541 DecimalFormat df = new DecimalFormat("#.##");
542 msgBuffer.append("Chisquare test failed");
543 msgBuffer.append(" p-value = ");
544 msgBuffer.append(chiSquareTest(expected, observed));
545 msgBuffer.append(" chisquare statistic = ");
546 msgBuffer.append(chiSquare(expected, observed));
547 msgBuffer.append(". \n");
548 msgBuffer.append("value\texpected\tobserved\n");
549 for (int i = 0; i < expected.length; i++) {
550 msgBuffer.append(valueLabels[i]);
551 msgBuffer.append("\t");
552 msgBuffer.append(df.format(expected[i]));
553 msgBuffer.append("\t\t");
554 msgBuffer.append(observed[i]);
555 msgBuffer.append("\n");
556 }
557 msgBuffer.append("This test can fail randomly due to sampling error with probability ");
558 msgBuffer.append(alpha);
559 msgBuffer.append(".");
560 fail(msgBuffer.toString());
561 }
562 }
563
564
565
566
567
568
569
570
571
572
573 public static void customAssertChiSquareAccept(int[] values, double[] expected, long[] observed, double alpha) {
574 String[] labels = new String[values.length];
575 for (int i = 0; i < values.length; i++) {
576 labels[i] = Integer.toString(values[i]);
577 }
578 customAssertChiSquareAccept(labels, expected, observed, alpha);
579 }
580
581
582
583
584
585
586
587
588
589 public static void customAssertChiSquareAccept(double[] expected, long[] observed, double alpha) {
590 String[] labels = new String[expected.length];
591 for (int i = 0; i < labels.length; i++) {
592 labels[i] = Integer.toString(i + 1);
593 }
594 customAssertChiSquareAccept(labels, expected, observed, alpha);
595 }
596
597
598
599
600
601
602
603
604 public static void customAssertGTest(final RealDistribution expectedDistribution, final double[] values, double alpha) {
605 final int numBins = values.length / 30;
606 final double[] breaks = new double[numBins];
607 for (int b = 0; b < breaks.length; b++) {
608 breaks[b] = expectedDistribution.inverseCumulativeProbability((double) b / numBins);
609 }
610
611 final long[] observed = new long[numBins];
612 for (final double value : values) {
613 int b = 0;
614 do {
615 b++;
616 } while (b < numBins && value >= breaks[b]);
617
618 observed[b - 1]++;
619 }
620
621 final double[] expected = new double[numBins];
622 Arrays.fill(expected, (double) values.length / numBins);
623
624 customAssertGTest(expected, observed, alpha);
625 }
626
627
628
629
630
631
632
633
634
635 public static void customAssertGTest(final double[] expected, long[] observed, double alpha) {
636 if (gTest(expected, observed) < alpha) {
637 StringBuilder msgBuffer = new StringBuilder();
638 DecimalFormat df = new DecimalFormat("#.##");
639 msgBuffer.append("G test failed");
640 msgBuffer.append(" p-value = ");
641 msgBuffer.append(gTest(expected, observed));
642 msgBuffer.append(". \n");
643 msgBuffer.append("value\texpected\tobserved\n");
644 for (int i = 0; i < expected.length; i++) {
645 msgBuffer.append(df.format(expected[i]));
646 msgBuffer.append("\t\t");
647 msgBuffer.append(observed[i]);
648 msgBuffer.append("\n");
649 }
650 msgBuffer.append("This test can fail randomly due to sampling error with probability ");
651 msgBuffer.append(alpha);
652 msgBuffer.append(".");
653 fail(msgBuffer.toString());
654 }
655 }
656
657
658
659
660
661 public static double[] getDistributionQuartiles(RealDistribution distribution) {
662 double[] quantiles = new double[3];
663 quantiles[0] = distribution.inverseCumulativeProbability(0.25d);
664 quantiles[1] = distribution.inverseCumulativeProbability(0.5d);
665 quantiles[2] = distribution.inverseCumulativeProbability(0.75d);
666 return quantiles;
667 }
668
669
670
671
672
673 public static void updateCounts(double value, long[] counts, double[] quartiles) {
674 if (value < quartiles[0]) {
675 counts[0]++;
676 } else if (value > quartiles[2]) {
677 counts[3]++;
678 } else if (value > quartiles[1]) {
679 counts[2]++;
680 } else {
681 counts[1]++;
682 }
683 }
684
685
686
687
688
689
690
691 public static int eliminateZeroMassPoints(int[] densityPoints, double[] densityValues) {
692 int positiveMassCount = 0;
693 for (int i = 0; i < densityValues.length; i++) {
694 if (densityValues[i] > 0) {
695 positiveMassCount++;
696 }
697 }
698 if (positiveMassCount < densityValues.length) {
699 int[] newPoints = new int[positiveMassCount];
700 double[] newValues = new double[positiveMassCount];
701 int j = 0;
702 for (int i = 0; i < densityValues.length; i++) {
703 if (densityValues[i] > 0) {
704 newPoints[j] = densityPoints[i];
705 newValues[j] = densityValues[i];
706 j++;
707 }
708 }
709 System.arraycopy(newPoints,0,densityPoints,0,positiveMassCount);
710 System.arraycopy(newValues,0,densityValues,0,positiveMassCount);
711 }
712 return positiveMassCount;
713 }
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732 public static double chiSquareTest(final double[] expected, final long[] observed) {
733 final org.hipparchus.distribution.continuous.ChiSquaredDistribution distribution =
734 new ChiSquaredDistribution(expected.length - 1.0);
735 return 1.0 - distribution.cumulativeProbability(chiSquare(expected, observed));
736 }
737
738
739
740
741
742
743
744
745
746 public static double chiSquare(final double[] expected, final long[] observed) {
747 double sumExpected = 0d;
748 double sumObserved = 0d;
749 for (int i = 0; i < observed.length; i++) {
750 sumExpected += expected[i];
751 sumObserved += observed[i];
752 }
753 double ratio = 1.0d;
754 boolean rescale = false;
755 if (FastMath.abs(sumExpected - sumObserved) > 10E-6) {
756 ratio = sumObserved / sumExpected;
757 rescale = true;
758 }
759 double sumSq = 0.0d;
760 for (int i = 0; i < observed.length; i++) {
761 if (rescale) {
762 final double dev = observed[i] - ratio * expected[i];
763 sumSq += dev * dev / (ratio * expected[i]);
764 } else {
765 final double dev = observed[i] - expected[i];
766 sumSq += dev * dev / expected[i];
767 }
768 }
769 return sumSq;
770
771 }
772
773
774
775
776
777
778
779 private static double g(final double[] expected, final long[] observed) {
780 double sumExpected = 0d;
781 double sumObserved = 0d;
782 for (int i = 0; i < observed.length; i++) {
783 sumExpected += expected[i];
784 sumObserved += observed[i];
785 }
786 double ratio = 1d;
787 boolean rescale = false;
788 if (FastMath.abs(sumExpected - sumObserved) > 10E-6) {
789 ratio = sumObserved / sumExpected;
790 rescale = true;
791 }
792 double sum = 0d;
793 for (int i = 0; i < observed.length; i++) {
794 final double dev = rescale ?
795 FastMath.log(observed[i] / (ratio * expected[i])) :
796 FastMath.log(observed[i] / expected[i]);
797 sum += (observed[i]) * dev;
798 }
799 return 2d * sum;
800 }
801
802
803
804
805
806
807
808
809 private static double gTest(final double[] expected, final long[] observed) {
810 final ChiSquaredDistribution distribution =
811 new ChiSquaredDistribution(expected.length - 1.0);
812 return 1.0 - distribution.cumulativeProbability(g(expected, observed));
813 }
814
815
816
817
818
819
820
821 public static double mean(final double[] values) {
822 double sum = 0;
823 for (double val : values) {
824 sum += val;
825 }
826 return sum / values.length;
827 }
828
829
830
831
832
833
834
835 public static double variance(final double[] values) {
836 final int length = values.length;
837 final double mean = mean(values);
838 double var = Double.NaN;
839 if (length == 1) {
840 var = 0.0;
841 } else if (length > 1) {
842 double accum = 0.0;
843 double dev = 0.0;
844 double accum2 = 0.0;
845 for (int i = 0; i < length; i++) {
846 dev = values[i] - mean;
847 accum += dev * dev;
848 accum2 += dev;
849 }
850 final double len = length;
851 var = (accum - (accum2 * accum2 / len)) / (len - 1.0);
852 }
853 return var;
854 }
855
856
857
858
859
860
861
862 public static double standardDeviation(final double[] values) {
863 return FastMath.sqrt(variance(values));
864 }
865
866
867
868
869
870
871
872 public static double median(final double[] values) {
873 final int len = values.length;
874 final double[] sortedValues = Arrays.copyOf(values, len);
875 Arrays.sort(sortedValues);
876 if (len % 2 == 0) {
877 return ((double)sortedValues[len/2] + (double)sortedValues[len/2 - 1])/2;
878 } else {
879 return (double) sortedValues[len/2];
880 }
881 }
882
883
884
885
886
887
888
889
890 public static double covariance(final double[] xArray, final double[] yArray) {
891 double result = 0d;
892 final int length = xArray.length;
893 final double xMean = mean(xArray);
894 final double yMean = mean(yArray);
895 for (int i = 0; i < length; i++) {
896 final double xDev = xArray[i] - xMean;
897 final double yDev = yArray[i] - yMean;
898 result += (xDev * yDev - result) / (i + 1);
899 }
900 return result * ((double) length / (double)(length - 1));
901 }
902
903
904
905
906
907
908
909 public static RealMatrix covarianceMatrix(RealMatrix matrix) {
910 int dimension = matrix.getColumnDimension();
911 final RealMatrix outMatrix = new BlockRealMatrix(dimension, dimension);
912 for (int i = 0; i < dimension; i++) {
913 for (int j = 0; j < i; j++) {
914 final double cov = covariance(matrix.getColumn(i), matrix.getColumn(j));
915 outMatrix.setEntry(i, j, cov);
916 outMatrix.setEntry(j, i, cov);
917 }
918 outMatrix.setEntry(i, i, variance(matrix.getColumn(i)));
919 }
920 return outMatrix;
921 }
922
923 public static double min(final double[] values) {
924 double min = values[0];
925 for (int i = 1; i < values.length; i++) {
926 if (values[i] < min) {
927 min = values[i];
928 }
929 }
930 return min;
931 }
932
933
934
935
936
937
938
939 public static double max(final double[] values) {
940 double max = values[0];
941 for (int i = 1; i < values.length; i++) {
942 if (values[i] > max) {
943 max = values[i];
944 }
945 }
946 return max;
947 }
948
949
950
951
952
953
954
955 private static double[] unpack(List<Double> values) {
956 int n = values.size();
957 if (values == null || n == 0) {
958 return new double[] {};
959 }
960 double[] out = new double[n];
961 for (int i = 0; i < n; i++) {
962 out[i] = values.get(i);
963 }
964 return out;
965 }
966
967
968
969
970
971
972
973 public static class Frequency<T> {
974 private Map<T, Integer> counts = new HashMap<>();
975 public void addValue(T value) {
976 Integer old = counts.put(value, 0);
977 if (old != null) {
978 counts.put(value, old++);
979 }
980 }
981 public int getCount(T value) {
982 Integer ret = counts.get(value);
983 return ret == null ? 0 : ret;
984 }
985 }
986
987
988
989
990
991 public static class SimpleStatistics {
992 private final List<Double> values = new ArrayList<>();
993 public void addValue(double value) {
994 values.add(value);
995 }
996 public double getMean() {
997 return mean(unpack(values));
998 }
999 public double getStandardDeviation() {
1000 return standardDeviation(unpack(values));
1001 }
1002 public double getMin() {
1003 return min(unpack(values));
1004 }
1005 public double getMax() {
1006 return max(unpack(values));
1007 }
1008 public double getMedian() {
1009 return median(unpack(values));
1010 }
1011 public double getVariance() {
1012 return variance(unpack(values));
1013 }
1014 public long getN() {
1015 return values.size();
1016 }
1017 }
1018
1019
1020
1021
1022
1023
1024 public static class SimpleRegression {
1025 private double sumX = 0d;
1026 private double sumXX = 0d;
1027 private double sumY = 0d;
1028 private double sumXY = 0d;
1029 private long n = 0;
1030 private double xbar = 0;
1031 private double ybar = 0;
1032
1033 public void addData(double x, double y) {
1034 if (n == 0) {
1035 xbar = x;
1036 ybar = y;
1037 } else {
1038 final double fact1 = 1.0 + n;
1039 final double fact2 = n / (1.0 + n);
1040 final double dx = x - xbar;
1041 final double dy = y - ybar;
1042 sumXX += dx * dx * fact2;
1043 sumXY += dx * dy * fact2;
1044 xbar += dx / fact1;
1045 ybar += dy / fact1;
1046 }
1047 sumX += x;
1048 sumY += y;
1049 n++;
1050 }
1051
1052 public double getSlope() {
1053 if (n < 2) {
1054 return Double.NaN;
1055 }
1056 if (FastMath.abs(sumXX) < 10 * Double.MIN_VALUE) {
1057 return Double.NaN;
1058 }
1059 return sumXY / sumXX;
1060 }
1061
1062 public double getIntercept() {
1063 return (sumY - getSlope() * sumX) / n;
1064 }
1065 }
1066 }