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.distribution.continuous;
24
25 import java.io.BufferedReader;
26 import java.io.IOException;
27 import java.io.InputStream;
28 import java.io.InputStreamReader;
29
30 import org.hipparchus.UnitTestUtils;
31 import org.hipparchus.exception.MathIllegalArgumentException;
32 import org.hipparchus.special.Gamma;
33 import org.hipparchus.util.FastMath;
34 import org.junit.Assert;
35 import org.junit.Test;
36
37
38
39
40 public class GammaDistributionTest extends RealDistributionAbstractTest {
41
42
43
44
45 @Override
46 public GammaDistribution makeDistribution() {
47 return new GammaDistribution(4d, 2d);
48 }
49
50
51 @Override
52 public double[] makeCumulativeTestPoints() {
53
54 return new double[] {0.857104827257, 1.64649737269, 2.17973074725, 2.7326367935, 3.48953912565,
55 26.1244815584, 20.0902350297, 17.5345461395, 15.5073130559, 13.3615661365};
56 }
57
58
59 @Override
60 public double[] makeCumulativeTestValues() {
61 return new double[] {0.001, 0.01, 0.025, 0.05, 0.1, 0.999, 0.990, 0.975, 0.950, 0.900};
62 }
63
64
65 @Override
66 public double[] makeDensityTestValues() {
67 return new double[] {0.00427280075546, 0.0204117166709, 0.0362756163658, 0.0542113174239, 0.0773195272491,
68 0.000394468852816, 0.00366559696761, 0.00874649473311, 0.0166712508128, 0.0311798227954};
69 }
70
71
72 @Override
73 public void setUp() {
74 super.setUp();
75 setTolerance(1e-9);
76 }
77
78
79 @Test
80 public void testParameterAccessors() {
81 GammaDistribution distribution = (GammaDistribution) getDistribution();
82 Assert.assertEquals(4d, distribution.getShape(), 0);
83 Assert.assertEquals(2d, distribution.getScale(), 0);
84 }
85
86 @Test
87 public void testPreconditions() {
88 try {
89 new GammaDistribution(0, 1);
90 Assert.fail("Expecting MathIllegalArgumentException for alpha = 0");
91 } catch (MathIllegalArgumentException ex) {
92
93 }
94 try {
95 new GammaDistribution(1, 0);
96 Assert.fail("Expecting MathIllegalArgumentException for alpha = 0");
97 } catch (MathIllegalArgumentException ex) {
98
99 }
100 }
101
102 @Test
103 public void testProbabilities() {
104 testProbability(-1.000, 4.0, 2.0, .0000);
105 testProbability(15.501, 4.0, 2.0, .9499);
106 testProbability(0.504, 4.0, 1.0, .0018);
107 testProbability(10.011, 1.0, 2.0, .9933);
108 testProbability(5.000, 2.0, 2.0, .7127);
109 }
110
111 @Test
112 public void testValues() {
113 testValue(15.501, 4.0, 2.0, .9499);
114 testValue(0.504, 4.0, 1.0, .0018);
115 testValue(10.011, 1.0, 2.0, .9933);
116 testValue(5.000, 2.0, 2.0, .7127);
117 }
118
119 private void testProbability(double x, double a, double b, double expected) {
120 GammaDistribution distribution = new GammaDistribution( a, b );
121 double actual = distribution.cumulativeProbability(x);
122 Assert.assertEquals("probability for " + x, expected, actual, 10e-4);
123 }
124
125 private void testValue(double expected, double a, double b, double p) {
126 GammaDistribution distribution = new GammaDistribution( a, b );
127 double actual = distribution.inverseCumulativeProbability(p);
128 Assert.assertEquals("critical value for " + p, expected, actual, 10e-4);
129 }
130
131 @Test
132 public void testDensity() {
133 double[] x = new double[]{-0.1, 1e-6, 0.5, 1, 2, 5};
134
135 checkDensity(1, 1, x, new double[]{0.000000000000, 0.999999000001, 0.606530659713, 0.367879441171, 0.135335283237, 0.006737946999});
136
137 checkDensity(2, 1, x, new double[]{0.000000000000, 0.000000999999, 0.303265329856, 0.367879441171, 0.270670566473, 0.033689734995});
138
139 checkDensity(4, 1, x, new double[]{0.000000000e+00, 1.666665000e-19, 1.263605541e-02, 6.131324020e-02, 1.804470443e-01, 1.403738958e-01});
140
141 checkDensity(4, 10, x, new double[]{0.000000000e+00, 1.666650000e-15, 1.403738958e+00, 7.566654960e-02, 2.748204830e-05, 4.018228850e-17});
142
143 checkDensity(0.1, 10, x, new double[]{0.000000000e+00, 3.323953832e+04, 1.663849010e-03, 6.007786726e-06, 1.461647647e-10, 5.996008322e-24});
144
145 checkDensity(0.1, 20, x, new double[]{0.000000000e+00, 3.562489883e+04, 1.201557345e-05, 2.923295295e-10, 3.228910843e-19, 1.239484589e-45});
146
147 checkDensity(0.1, 4, x, new double[]{0.000000000e+00, 3.032938388e+04, 3.049322494e-02, 2.211502311e-03, 2.170613371e-05, 5.846590589e-11});
148
149 checkDensity(0.1, 1, x, new double[]{0.000000000e+00, 2.640334143e+04, 1.189704437e-01, 3.866916944e-02, 7.623306235e-03, 1.663849010e-04});
150 }
151
152 private void checkDensity(double alpha, double rate, double[] x, double[] expected) {
153 GammaDistribution d = new GammaDistribution(alpha, 1 / rate);
154 for (int i = 0; i < x.length; i++) {
155 Assert.assertEquals(expected[i], d.density(x[i]), 1e-5);
156 }
157 }
158
159 @Test
160 public void testInverseCumulativeProbabilityExtremes() {
161 setInverseCumulativeTestPoints(new double[] {0, 1});
162 setInverseCumulativeTestValues(new double[] {0, Double.POSITIVE_INFINITY});
163 verifyInverseCumulativeProbabilities();
164 }
165
166 @Test
167 public void testMoments() {
168 final double tol = 1e-9;
169 GammaDistribution dist;
170
171 dist = new GammaDistribution(1, 2);
172 Assert.assertEquals(dist.getNumericalMean(), 2, tol);
173 Assert.assertEquals(dist.getNumericalVariance(), 4, tol);
174
175 dist = new GammaDistribution(1.1, 4.2);
176 Assert.assertEquals(dist.getNumericalMean(), 1.1d * 4.2d, tol);
177 Assert.assertEquals(dist.getNumericalVariance(), 1.1d * 4.2d * 4.2d, tol);
178 }
179
180 private static final double HALF_LOG_2_PI = 0.5 * FastMath.log(2.0 * FastMath.PI);
181
182 public static double logGamma(double x) {
183
184
185
186
187
188 double ret;
189
190 if (Double.isNaN(x) || (x <= 0.0)) {
191 ret = Double.NaN;
192 } else {
193 double sum = Gamma.lanczos(x);
194 double tmp = x + Gamma.LANCZOS_G + .5;
195 ret = ((x + .5) * FastMath.log(tmp)) - tmp +
196 HALF_LOG_2_PI + FastMath.log(sum / x);
197 }
198
199 return ret;
200 }
201
202 public static double density(final double x, final double shape,
203 final double scale) {
204
205
206
207
208
209 if (x < 0) {
210 return 0;
211 }
212 return FastMath.pow(x / scale, shape - 1) / scale *
213 FastMath.exp(-x / scale) / FastMath.exp(logGamma(shape));
214 }
215
216
217
218
219
220
221
222
223 private void doTestMath753(final double shape,
224 final double meanNoOF, final double sdNoOF,
225 final double meanOF, final double sdOF,
226 final String resourceName) throws IOException {
227 final GammaDistribution distribution = new GammaDistribution(shape, 1.0);
228 final UnitTestUtils.SimpleStatistics statOld = new UnitTestUtils.SimpleStatistics();
229 final UnitTestUtils.SimpleStatistics statNewNoOF = new UnitTestUtils.SimpleStatistics();
230 final UnitTestUtils.SimpleStatistics statNewOF = new UnitTestUtils.SimpleStatistics();
231
232 final InputStream resourceAsStream;
233 resourceAsStream = this.getClass().getResourceAsStream(resourceName);
234 Assert.assertNotNull("Could not find resource " + resourceName,
235 resourceAsStream);
236 final BufferedReader in;
237 in = new BufferedReader(new InputStreamReader(resourceAsStream));
238
239 try {
240 for (String line = in.readLine(); line != null; line = in.readLine()) {
241 if (line.startsWith("#")) {
242 continue;
243 }
244 final String[] tokens = line.split(", ");
245 Assert.assertTrue("expected two floating-point values",
246 tokens.length == 2);
247 final double x = Double.parseDouble(tokens[0]);
248 final String msg = "x = " + x + ", shape = " + shape +
249 ", scale = 1.0";
250 final double expected = Double.parseDouble(tokens[1]);
251 final double ulp = FastMath.ulp(expected);
252 final double actualOld = density(x, shape, 1.0);
253 final double actualNew = distribution.density(x);
254 final double errOld, errNew;
255 errOld = FastMath.abs((actualOld - expected) / ulp);
256 errNew = FastMath.abs((actualNew - expected) / ulp);
257
258 if (Double.isNaN(actualOld) || Double.isInfinite(actualOld)) {
259 Assert.assertFalse(msg, Double.isNaN(actualNew));
260 Assert.assertFalse(msg, Double.isInfinite(actualNew));
261 statNewOF.addValue(errNew);
262 } else {
263 statOld.addValue(errOld);
264 statNewNoOF.addValue(errNew);
265 }
266 }
267 if (statOld.getN() != 0) {
268
269
270
271
272 final StringBuilder sb = new StringBuilder("shape = ");
273 sb.append(shape);
274 sb.append(", scale = 1.0\n");
275 sb.append("Old implementation\n");
276 sb.append("------------------\n");
277 sb.append(statOld.toString());
278 sb.append("New implementation\n");
279 sb.append("------------------\n");
280 sb.append(statNewNoOF.toString());
281 final String msg = sb.toString();
282
283 final double oldMin = statOld.getMin();
284 final double newMin = statNewNoOF.getMin();
285 Assert.assertTrue(msg, newMin <= oldMin);
286
287 final double oldMax = statOld.getMax();
288 final double newMax = statNewNoOF.getMax();
289 Assert.assertTrue(msg, newMax <= oldMax);
290
291 final double oldMean = statOld.getMean();
292 final double newMean = statNewNoOF.getMean();
293 Assert.assertTrue(msg, newMean <= oldMean);
294
295 final double oldSd = statOld.getStandardDeviation();
296 final double newSd = statNewNoOF.getStandardDeviation();
297 Assert.assertTrue(msg, newSd <= oldSd);
298
299 Assert.assertTrue(msg, newMean <= meanNoOF);
300 Assert.assertTrue(msg, newSd <= sdNoOF);
301 }
302 if (statNewOF.getN() != 0) {
303 final double newMean = statNewOF.getMean();
304 final double newSd = statNewOF.getStandardDeviation();
305
306 final StringBuilder sb = new StringBuilder("shape = ");
307 sb.append(shape);
308 sb.append(", scale = 1.0");
309 sb.append(", max. mean error (ulps) = ");
310 sb.append(meanOF);
311 sb.append(", actual mean error (ulps) = ");
312 sb.append(newMean);
313 sb.append(", max. sd of error (ulps) = ");
314 sb.append(sdOF);
315 sb.append(", actual sd of error (ulps) = ");
316 sb.append(newSd);
317 final String msg = sb.toString();
318
319 Assert.assertTrue(msg, newMean <= meanOF);
320 Assert.assertTrue(msg, newSd <= sdOF);
321 }
322 } catch (IOException e) {
323 Assert.fail(e.getMessage());
324 } finally {
325 in.close();
326 }
327 }
328
329
330 @Test
331 public void testMath753Shape1() throws IOException {
332 doTestMath753(1.0, 1.5, 0.5, 0.0, 0.0, "gamma-distribution-shape-1.csv");
333 }
334
335 @Test
336 public void testMath753Shape8() throws IOException {
337 doTestMath753(8.0, 1.5, 1.0, 0.0, 0.0, "gamma-distribution-shape-8.csv");
338 }
339
340 @Test
341 public void testMath753Shape10() throws IOException {
342 doTestMath753(10.0, 1.0, 1.0, 0.0, 0.0, "gamma-distribution-shape-10.csv");
343 }
344
345 @Test
346 public void testMath753Shape100() throws IOException {
347 doTestMath753(100.0, 1.5, 1.0, 0.0, 0.0, "gamma-distribution-shape-100.csv");
348 }
349
350 @Test
351 public void testMath753Shape142() throws IOException {
352 doTestMath753(142.0, 3.3, 1.6, 40.0, 40.0, "gamma-distribution-shape-142.csv");
353 }
354
355 @Test
356 public void testMath753Shape1000() throws IOException {
357 doTestMath753(1000.0, 1.0, 1.0, 160.0, 220.0, "gamma-distribution-shape-1000.csv");
358 }
359 }