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  package org.apache.commons.statistics.distribution;
19  
20  import java.util.stream.Stream;
21  import org.junit.jupiter.api.Assertions;
22  import org.junit.jupiter.params.ParameterizedTest;
23  import org.junit.jupiter.params.provider.Arguments;
24  import org.junit.jupiter.params.provider.CsvSource;
25  import org.junit.jupiter.params.provider.MethodSource;
26  
27  /**
28   * Test cases for {@link LogUniformDistribution}.
29   * Extends {@link BaseContinuousDistributionTest}. See javadoc of that class for details.
30   */
31  class LogUniformDistributionTest extends BaseContinuousDistributionTest {
32      @Override
33      ContinuousDistribution makeDistribution(Object... parameters) {
34          final double a = (Double) parameters[0];
35          final double b = (Double) parameters[1];
36          return LogUniformDistribution.of(a, b);
37      }
38  
39      @Override
40      Object[][] makeInvalidParameters() {
41          return new Object[][] {
42              // lower >= upper
43              {0.0, 0.0},
44              {1.0, 0.5},
45              // Range not finite
46              {Double.NaN, 1.0},
47              {0.5, Double.NaN},
48              // lower <= 0
49              {-1.0, 1.0},
50              {0.0, 1.0},
51          };
52      }
53  
54      @Override
55      String[] getParameterNames() {
56          return new String[] {"SupportLowerBound", "SupportUpperBound"};
57      }
58  
59      @Override
60      protected double getRelativeTolerance() {
61          return 5e-15;
62      }
63  
64      //-------------------- Additional test cases -------------------------------
65  
66      /**
67       * Test the moments using the canonical formulas (from the javadoc).
68       */
69      @ParameterizedTest
70      @MethodSource
71      void testAdditionalMoments(double a, double b) {
72          final double diff = b - a;
73          final double denom = Math.log(b / a);
74          final double mean = diff / denom;
75          // Note: b^2 - a^2 = (b-a)*(b+a)
76          final double variance = mean * (b + a) / 2 - mean * mean;
77          TestUtils.assertEquals(mean, LogUniformDistribution.of(a, b).getMean(),
78              DoubleTolerances.relative(1e-14), "Mean");
79          TestUtils.assertEquals(variance, LogUniformDistribution.of(a, b).getVariance(),
80              DoubleTolerances.relative(1e-10), "Variance");
81      }
82  
83      static Stream<Arguments> testAdditionalMoments() {
84          final Stream.Builder<Arguments> builder = Stream.builder();
85          for (final double a : new double[] {1, 10, 100}) {
86              for (final double x : new double[] {10, 20, 40}) {
87                  builder.add(Arguments.of(a, a + x));
88              }
89          }
90          return builder.build();
91      }
92  
93      /**
94       * Test the survival function for extreme values is computed using high precision,
95       * i.e. is not the default of 1 - CDF.
96       */
97      @ParameterizedTest
98      @CsvSource({
99          "1e-100, 1e100",
100         "1e-10, 1e10",
101     })
102     void testExtremeSurvivalFunction(double a, double b) {
103         final LogUniformDistribution d = LogUniformDistribution.of(a, b);
104         // Find a small non-zero survival probability
105         final double u = Math.ulp(b);
106         int i = 1;
107         double p;
108         do {
109             p = d.survivalProbability(b - i * u);
110             i *= 2;
111         } while (p == 0);
112         Assertions.assertTrue(p < 0x1.0p-53, "sf is not small enough for high precision");
113         Assertions.assertNotEquals(1 - d.cumulativeProbability(b - i * u), p, "sf is not high precision: sf == 1 - cdf");
114     }
115 }