View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  /*
19   * This is not the original file distributed by the Apache Software Foundation
20   * It has been modified by the Hipparchus project
21   */
22  
23  package org.hipparchus.distribution.continuous;
24  
25  import org.hipparchus.exception.MathIllegalArgumentException;
26  import org.junit.jupiter.api.BeforeEach;
27  import org.junit.jupiter.api.Test;
28  
29  import static org.junit.jupiter.api.Assertions.assertEquals;
30  import static org.junit.jupiter.api.Assertions.assertThrows;
31  import static org.junit.jupiter.api.Assertions.assertTrue;
32  
33  /**
34   * Test cases for {@link LogNormalDistribution}.
35   */
36  public class LogNormalDistributionTest extends RealDistributionAbstractTest {
37  
38      //-------------- Implementations for abstract methods -----------------------
39  
40      /** Creates the default real distribution instance to use in tests. */
41      @Override
42      public LogNormalDistribution makeDistribution() {
43          return new LogNormalDistribution(2.1, 1.4);
44      }
45  
46      /** Creates the default cumulative probability distribution test input values */
47      @Override
48      public double[] makeCumulativeTestPoints() {
49          // quantiles computed using R
50          return new double[] { -2.226325228634938, -1.156887023657177,
51                                -0.643949578356075, -0.2027950777320613,
52                                0.305827808237559, 6.42632522863494,
53                                5.35688702365718, 4.843949578356074,
54                                4.40279507773206, 3.89417219176244 };
55      }
56  
57      /** Creates the default cumulative probability density test expected values */
58      @Override
59      public double[] makeCumulativeTestValues() {
60          return new double[] { 0, 0, 0, 0, 0.00948199951485, 0.432056525076,
61                                0.381648158697, 0.354555726206, 0.329513316888,
62                                0.298422824228 };
63      }
64  
65      /** Creates the default probability density test expected values */
66      @Override
67      public double[] makeDensityTestValues() {
68          return new double[] { 0, 0, 0, 0, 0.0594218160072, 0.0436977691036,
69                                0.0508364857798, 0.054873528325, 0.0587182664085,
70                                0.0636229042785 };
71      }
72  
73      /**
74       * Creates the default inverse cumulative probability distribution test
75       * input values.
76       */
77      @Override
78      public double[] makeInverseCumulativeTestPoints() {
79          // Exclude the test points less than zero, as they have cumulative
80          // probability of zero, meaning the inverse returns zero, and not the
81          // points less than zero.
82          double[] points = makeCumulativeTestValues();
83          double[] points2 = new double[points.length - 4];
84          System.arraycopy(points, 4, points2, 0, points2.length - 4);
85          return points2;
86          //return Arrays.copyOfRange(points, 4, points.length - 4);
87      }
88  
89      /**
90       * Creates the default inverse cumulative probability test expected
91       * values.
92       */
93      @Override
94      public double[] makeInverseCumulativeTestValues() {
95          // Exclude the test points less than zero, as they have cumulative
96          // probability of zero, meaning the inverse returns zero, and not the
97          // points less than zero.
98          double[] points = makeCumulativeTestPoints();
99          double[] points2 = new double[points.length - 4];
100         System.arraycopy(points, 4, points2, 0, points2.length - 4);
101         return points2;
102         //return Arrays.copyOfRange(points, 1, points.length - 4);
103     }
104 
105     // --------------------- Override tolerance  --------------
106     @BeforeEach
107     @Override
108     public void setUp() {
109         super.setUp();
110         setTolerance(1e-9);
111     }
112 
113     //---------------------------- Additional test cases -------------------------
114 
115     private void verifyQuantiles() {
116         LogNormalDistribution distribution = (LogNormalDistribution)getDistribution();
117         double mu = distribution.getLocation();
118         double sigma = distribution.getShape();
119         setCumulativeTestPoints( new double[] { mu - 2 *sigma, mu - sigma,
120                                                 mu, mu + sigma, mu + 2 * sigma,
121                                                 mu + 3 * sigma,mu + 4 * sigma,
122                                                 mu + 5 * sigma });
123         verifyCumulativeProbabilities();
124     }
125 
126     @Test
127     void testQuantiles() {
128         setCumulativeTestValues(new double[] {0, 0.0396495152787,
129                                               0.16601209243, 0.272533253269,
130                                               0.357618409638, 0.426488363093,
131                                               0.483255136841, 0.530823013877});
132         setDensityTestValues(new double[] {0, 0.0873055825147, 0.0847676303432,
133                                            0.0677935186237, 0.0544105523058,
134                                            0.0444614628804, 0.0369750288945,
135                                            0.0312206409653});
136         verifyQuantiles();
137         verifyDensities();
138 
139         setDistribution(new LogNormalDistribution(0, 1));
140         setCumulativeTestValues(new double[] {0, 0, 0, 0.5, 0.755891404214,
141                                               0.864031392359, 0.917171480998,
142                                               0.946239689548});
143         setDensityTestValues(new double[] {0, 0, 0, 0.398942280401,
144                                            0.156874019279, 0.07272825614,
145                                            0.0381534565119, 0.0218507148303});
146         verifyQuantiles();
147         verifyDensities();
148 
149         setDistribution(new LogNormalDistribution(0, 0.1));
150         setCumulativeTestValues(new double[] {0, 0, 0, 1.28417563064e-117,
151                                               1.39679883412e-58,
152                                               1.09839325447e-33,
153                                               2.52587961726e-20,
154                                               2.0824223487e-12});
155         setDensityTestValues(new double[] {0, 0, 0, 2.96247992535e-114,
156                                            1.1283370232e-55, 4.43812313223e-31,
157                                            5.85346445002e-18,
158                                            2.9446618076e-10});
159         verifyQuantiles();
160         verifyDensities();
161     }
162 
163     @Test
164     void testInverseCumulativeProbabilityExtremes() {
165         setInverseCumulativeTestPoints(new double[] {0, 1});
166         setInverseCumulativeTestValues(
167                 new double[] {0, Double.POSITIVE_INFINITY});
168         verifyInverseCumulativeProbabilities();
169     }
170 
171     @Test
172     void testGetLocation() {
173         LogNormalDistribution distribution = (LogNormalDistribution)getDistribution();
174         assertEquals(2.1, distribution.getLocation(), 0);
175     }
176 
177     @Test
178     void testGetShape() {
179         LogNormalDistribution distribution = (LogNormalDistribution)getDistribution();
180         assertEquals(1.4, distribution.getShape(), 0);
181     }
182 
183     @Test
184     void testPreconditions() {
185         assertThrows(MathIllegalArgumentException.class, () -> {
186             new LogNormalDistribution(1, 0);
187         });
188     }
189 
190     @Test
191     void testDensity() {
192         double [] x = new double[]{-2, -1, 0, 1, 2};
193         // R 2.13: print(dlnorm(c(-2,-1,0,1,2)), digits=10)
194         checkDensity(0, 1, x, new double[] { 0.0000000000, 0.0000000000,
195                                              0.0000000000, 0.3989422804,
196                                              0.1568740193 });
197         // R 2.13: print(dlnorm(c(-2,-1,0,1,2), mean=1.1), digits=10)
198         checkDensity(1.1, 1, x, new double[] { 0.0000000000, 0.0000000000,
199                                                0.0000000000, 0.2178521770,
200                                                0.1836267118});
201     }
202 
203     private void checkDensity(double scale, double shape, double[] x,
204         double[] expected) {
205         LogNormalDistribution d = new LogNormalDistribution(scale, shape);
206         for (int i = 0; i < x.length; i++) {
207             assertEquals(expected[i], d.density(x[i]), 1e-9);
208         }
209     }
210 
211     /**
212      * Check to make sure top-coding of extreme values works correctly.
213      * Verifies fixes for JIRA MATH-167, MATH-414
214      */
215     @Test
216     void testExtremeValues() {
217         LogNormalDistribution d = new LogNormalDistribution(0, 1);
218         for (int i = 0; i < 1e5; i++) { // make sure no convergence exception
219             double upperTail = d.cumulativeProbability(i);
220             if (i <= 72) { // make sure not top-coded
221                 assertTrue(upperTail < 1.0d);
222             }
223             else { // make sure top coding not reversed
224                 assertTrue(upperTail > 0.99999);
225             }
226         }
227 
228         assertEquals(1, d.cumulativeProbability(Double.MAX_VALUE), 0);
229         assertEquals(0, d.cumulativeProbability(-Double.MAX_VALUE), 0);
230         assertEquals(1, d.cumulativeProbability(Double.POSITIVE_INFINITY), 0);
231         assertEquals(0, d.cumulativeProbability(Double.NEGATIVE_INFINITY), 0);
232     }
233 
234     @Test
235     void testMeanVariance() {
236         final double tol = 1e-9;
237         LogNormalDistribution dist;
238 
239         dist = new LogNormalDistribution(0, 1);
240         assertEquals(1.6487212707001282, dist.getNumericalMean(), tol);
241         assertEquals(
242             4.670774270471604, dist.getNumericalVariance(), tol);
243 
244         dist = new LogNormalDistribution(2.2, 1.4);
245         assertEquals(24.046753552064498, dist.getNumericalMean(), tol);
246         assertEquals(
247             3526.913651880464, dist.getNumericalVariance(), tol);
248 
249         dist = new LogNormalDistribution(-2000.9, 10.4);
250         assertEquals(0.0, dist.getNumericalMean(), tol);
251         assertEquals(0.0, dist.getNumericalVariance(), tol);
252     }
253 
254     @Test
255     void testTinyVariance() {
256         LogNormalDistribution dist = new LogNormalDistribution(0, 1e-9);
257         double t = dist.getNumericalVariance();
258         assertEquals(1e-18, t, 1e-20);
259     }
260 
261 }