1 package org.djutils.means;
2
3 import static org.junit.Assert.assertEquals;
4 import static org.junit.Assert.assertTrue;
5 import static org.junit.Assert.fail;
6
7 import java.util.ArrayList;
8 import java.util.Arrays;
9 import java.util.HashMap;
10 import java.util.List;
11 import java.util.Map;
12
13 import org.junit.Test;
14
15
16
17
18
19
20
21
22
23
24
25 public class MeansTests
26 {
27
28 private static Double[] testValues = {10.0, Math.PI, Math.E, 1234.};
29
30
31 private static Double[] testWeights = {1.0, 2.0, Math.PI, 1.0};
32
33
34
35
36 @Test
37 public final void testMeansWithUnityWeights()
38 {
39 ArithmeticMean<Double, Double> am = new ArithmeticMean<Double, Double>();
40 double sum = 0;
41 for (int i = 0; i < testValues.length; i++)
42 {
43 double testValue = testValues[i];
44 assertEquals("add returns object for method chaining", am, am.add(testValue));
45 sum += testValue;
46 assertEquals("sum", sum, am.getSum(), sum / 99999999);
47 assertEquals("arithmetic mean", sum / (i + 1), am.getMean(), sum / (i + 1) / 99999999);
48 }
49 am = new ArithmeticMean<Double, Double>();
50 assertEquals("add returns object for method chaining", am, am.add(testValues));
51 assertEquals("arithmetic mean", sum / testValues.length, am.getMean(), sum / testValues.length / 99999999);
52
53 am = new ArithmeticMean<Double, Double>();
54 assertEquals("add returns object for method chaining", am, am.add(new ArrayList<Double>(Arrays.asList(testValues))));
55 assertEquals("arithmetic mean", sum / testValues.length, am.getMean(), sum / testValues.length / 99999999);
56 }
57
58
59
60
61 @SuppressWarnings("checkstyle:methodlength")
62 @Test
63 public final void testMeansWithWeights()
64 {
65 ArithmeticMean<Double, Double> am = new ArithmeticMean<Double, Double>();
66 assertEquals("Initial sum is 0", 0, am.getSum(), 0.00000);
67 assertEquals("Initial sum of weights is 0", 0, am.getSumOfWeights(), 0.00000);
68 assertTrue("Initial mean is NaN", Double.isNaN(am.getMean()));
69 HarmonicMean<Double, Double> hm = new HarmonicMean<Double, Double>();
70 assertEquals("Initial sum is 0", 0, hm.getSum(), 0.00000);
71 assertEquals("Initial sum of weights is 0", 0, hm.getSumOfWeights(), 0.00000);
72 assertTrue("Initial mean is NaN", Double.isNaN(hm.getMean()));
73 GeometricMean<Double, Double> gm = new GeometricMean<Double, Double>();
74 assertEquals("Initial sum is 0", 0, gm.getSum(), 0.00000);
75 assertEquals("Initial sum of weights is 0", 0, gm.getSumOfWeights(), 0.00000);
76 assertTrue("Initial mean is NaN", Double.isNaN(gm.getMean()));
77 double sum = 0;
78 double sumWeights = 0;
79 double recipSum = 0;
80 double product = 1;
81 double geometricMean = 0;
82 Map<Double, Double> map = new HashMap<>();
83 for (int i = 0; i < testValues.length; i++)
84 {
85 double testValue = testValues[i];
86 double testWeight = testWeights[i];
87 map.put(testValue, testWeight);
88 assertEquals("add returns object for method chaining", am, am.add(testValue, testWeight));
89 hm.add(testValue, testWeight);
90 gm.add(testValue, testWeight);
91 sum += testValue * testWeight;
92 recipSum += testWeight / testValue;
93 product *= Math.pow(testValue, testWeight);
94 sumWeights += testWeight;
95 if (0 == i)
96 {
97 assertEquals("mean of one value equals value", testValue, am.getMean(), testValue / 99999999);
98 assertEquals("mean of one value equals value", testValue, hm.getMean(), testValue / 99999999);
99 assertEquals("mean of one value equals value", testValue, gm.getMean(), testValue / 99999999);
100 }
101 assertEquals("sum", sum, am.getSum(), sum / 99999999);
102 assertEquals("sum of weights", sumWeights, am.getSumOfWeights(), sumWeights / 99999999);
103 assertEquals("arithmetic mean", sum / sumWeights, am.getMean(), sum / sumWeights / 99999999);
104 assertEquals("sum", recipSum, hm.getSum(), recipSum / 99999999);
105 assertEquals("sum of weights", sumWeights, hm.getSumOfWeights(), sumWeights / 99999999);
106 assertEquals("harmonic mean", sumWeights / recipSum, hm.getMean(), sumWeights / recipSum / 999999999);
107 geometricMean = Math.pow(product, 1 / sumWeights);
108 assertEquals("check with alternative way to compute geometric mean", geometricMean, gm.getMean(),
109 geometricMean / 99999999);
110 }
111
112
113 am = new ArithmeticMean<Double, Double>();
114 hm = new HarmonicMean<Double, Double>();
115 gm = new GeometricMean<Double, Double>();
116 am.add(testValues[0], 123.456);
117 hm.add(testValues[0], 123.456);
118 gm.add(testValues[0], 123.456);
119 assertEquals("One value, any weight has mean equal to value", testValues[0], am.getMean(), testValues[0] / 99999999);
120 assertEquals("One value, any weight has mean equal to value", testValues[0], hm.getMean(), testValues[0] / 99999999);
121 assertEquals("One value, any weight has mean equal to value", testValues[0], gm.getMean(), testValues[0] / 99999999);
122 am = new ArithmeticMean<Double, Double>();
123 hm = new HarmonicMean<Double, Double>();
124 gm = new GeometricMean<Double, Double>();
125 assertEquals("add returns object for method chaining", am, am.add(testValues, testWeights));
126 assertEquals("arithmetic mean", sum / sumWeights, am.getMean(), sum / sumWeights / 99999999);
127 hm.add(testValues, testWeights);
128 assertEquals("harmonic mean", sumWeights / recipSum, hm.getMean(), sumWeights / recipSum / 999999999);
129 gm.add(testValues, testWeights);
130 assertEquals("geometric mean", geometricMean, gm.getMean(), geometricMean / 99999999);
131 Double[] shortArray = Arrays.copyOfRange(testValues, 0, 2);
132 try
133 {
134 am.add(shortArray, testWeights);
135 fail("Short array of values should have thrown an IllegalArgumentException");
136 }
137 catch (IllegalArgumentException iae)
138 {
139
140 }
141 shortArray = Arrays.copyOfRange(testWeights, 0, 2);
142 try
143 {
144 am.add(testValues, shortArray);
145 fail("Short array of weights should have thrown an IllegalArgumentException");
146 }
147 catch (IllegalArgumentException iae)
148 {
149
150 }
151 am = new ArithmeticMean<Double, Double>();
152 hm = new HarmonicMean<Double, Double>();
153 gm = new GeometricMean<Double, Double>();
154 assertEquals("add returns object for method chaining", am,
155 am.add(new ArrayList<Double>(Arrays.asList(testValues)), new ArrayList<Double>(Arrays.asList(testWeights))));
156 assertEquals("arithmetic mean", sum / sumWeights, am.getMean(), sum / sumWeights / 99999999);
157 hm.add(new ArrayList<Double>(Arrays.asList(testValues)), new ArrayList<Double>(Arrays.asList(testWeights)));
158 assertEquals("harmonic mean", sumWeights / recipSum, hm.getMean(), sumWeights / recipSum / 999999999);
159 gm.add(new ArrayList<Double>(Arrays.asList(testValues)), new ArrayList<Double>(Arrays.asList(testWeights)));
160 assertEquals("geometric mean", geometricMean, gm.getMean(), geometricMean / 99999999);
161
162 List<Double> shortList = new ArrayList<Double>(Arrays.asList(testValues));
163 shortList.remove(2);
164 try
165 {
166 am.add(shortList, new ArrayList<Double>(Arrays.asList(testWeights)));
167 fail("Short list of values should have thrown an IllegalArgumentException");
168 }
169 catch (IllegalArgumentException iae)
170 {
171
172 }
173 shortList = new ArrayList<Double>(Arrays.asList(testWeights));
174 shortList.remove(2);
175 try
176 {
177 am.add(new ArrayList<Double>(Arrays.asList(testValues)), shortList);
178 fail("Short list of weights should have thrown an IllegalArgumentException");
179 }
180 catch (IllegalArgumentException iae)
181 {
182
183 }
184
185 am = new ArithmeticMean<Double, Double>();
186 hm = new HarmonicMean<Double, Double>();
187 gm = new GeometricMean<Double, Double>();
188 assertEquals("add returns object for method chaining", am, am.add(map));
189 assertEquals("arithmetic mean", sum / sumWeights, am.getMean(), sum / sumWeights / 99999999);
190 hm.add(map);
191 assertEquals("harmonic mean", sumWeights / recipSum, hm.getMean(), sumWeights / recipSum / 999999999);
192 gm.add(map);
193 assertEquals("geometric mean", geometricMean, gm.getMean(), geometricMean / 99999999);
194
195 am = new ArithmeticMean<Double, Double>();
196 hm = new HarmonicMean<Double, Double>();
197 gm = new GeometricMean<Double, Double>();
198 assertEquals("add returns object for method chaining", am,
199 am.add(new ArrayList<Double>(Arrays.asList(testValues)), (Double v) -> map.get(v)));
200 assertEquals("arithmetic mean", sum / sumWeights, am.getMean(), sum / sumWeights / 99999999);
201 hm.add(new ArrayList<Double>(Arrays.asList(testValues)), (Double v) -> map.get(v));
202 assertEquals("harmonic mean", sumWeights / recipSum, hm.getMean(), sumWeights / recipSum / 999999999);
203 gm.add(new ArrayList<Double>(Arrays.asList(testValues)), (Double v) -> map.get(v));
204 assertEquals("geometric mean", geometricMean, gm.getMean(), geometricMean / 99999999);
205
206 am = new ArithmeticMean<Double, Double>();
207 hm = new HarmonicMean<Double, Double>();
208 gm = new GeometricMean<Double, Double>();
209 Integer[] indices = new Integer[] {0, 1, 2, 3};
210 List<Integer> indexList = new ArrayList<>(Arrays.asList(indices));
211 assertEquals("add returns object for method chaining", am,
212 am.add(indexList, (Integer i) -> testValues[i], (Integer i) -> testWeights[i]));
213 assertEquals("arithmetic mean", sum / sumWeights, am.getMean(), sum / sumWeights / 99999999);
214 hm.add(indexList, (Integer i) -> testValues[i], (Integer i) -> testWeights[i]);
215 assertEquals("harmonic mean", sumWeights / recipSum, hm.getMean(), sumWeights / recipSum / 999999999);
216 gm.add(indexList, (Integer i) -> testValues[i], (Integer i) -> testWeights[i]);
217 assertEquals("geometric mean", geometricMean, gm.getMean(), geometricMean / 99999999);
218
219 assertTrue("toString method returns something descriptive", am.toString().contains("ArithmeticMean"));
220 assertTrue("toString method returns something descriptive", hm.toString().contains("HarmonicMean"));
221 assertTrue("toString method returns something descriptive", gm.toString().contains("GeometricMean"));
222 }
223
224 }