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    *      http://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  package org.apache.commons.rng.sampling.distribution;
18  
19  import java.util.List;
20  import java.util.ArrayList;
21  import java.util.Collections;
22  
23  import org.apache.commons.rng.UniformRandomProvider;
24  import org.apache.commons.rng.simple.RandomSource;
25  
26  /**
27   * List of samplers.
28   */
29  public final class ContinuousSamplersList {
30      /** List of all RNGs implemented in the library. */
31      private static final List<ContinuousSamplerTestData[]> LIST =
32          new ArrayList<ContinuousSamplerTestData[]>();
33  
34      static {
35          try {
36              // This test uses reference distributions from commons-math3 to compute the expected
37              // PMF. These distributions have a dual functionality to compute the PMF and perform
38              // sampling. When no sampling is needed for the created distribution, it is advised
39              // to pass null as the random generator via the appropriate constructors to avoid the
40              // additional initialisation overhead.
41              org.apache.commons.math3.random.RandomGenerator unusedRng = null;
42  
43              // List of distributions to test.
44  
45              // Gaussian ("inverse method").
46              final double meanNormal = -123.45;
47              final double sigmaNormal = 6.789;
48              add(LIST, new org.apache.commons.math3.distribution.NormalDistribution(unusedRng, meanNormal, sigmaNormal),
49                  RandomSource.create(RandomSource.KISS));
50              // Gaussian (DEPRECATED "Box-Muller").
51              add(LIST, new org.apache.commons.math3.distribution.NormalDistribution(unusedRng, meanNormal, sigmaNormal),
52                  new BoxMullerGaussianSampler(RandomSource.create(RandomSource.MT), meanNormal, sigmaNormal));
53              // Gaussian ("Box-Muller").
54              add(LIST, new org.apache.commons.math3.distribution.NormalDistribution(unusedRng, meanNormal, sigmaNormal),
55                  GaussianSampler.of(new BoxMullerNormalizedGaussianSampler(RandomSource.create(RandomSource.MT)),
56                                     meanNormal, sigmaNormal));
57              // Gaussian ("Marsaglia").
58              add(LIST, new org.apache.commons.math3.distribution.NormalDistribution(unusedRng, meanNormal, sigmaNormal),
59                  GaussianSampler.of(new MarsagliaNormalizedGaussianSampler(RandomSource.create(RandomSource.MT)),
60                                     meanNormal, sigmaNormal));
61              // Gaussian ("Ziggurat").
62              add(LIST, new org.apache.commons.math3.distribution.NormalDistribution(unusedRng, meanNormal, sigmaNormal),
63                  GaussianSampler.of(new ZigguratNormalizedGaussianSampler(RandomSource.create(RandomSource.MT)),
64                                     meanNormal, sigmaNormal));
65  
66              // Beta ("inverse method").
67              final double alphaBeta = 4.3;
68              final double betaBeta = 2.1;
69              add(LIST, new org.apache.commons.math3.distribution.BetaDistribution(unusedRng, alphaBeta, betaBeta),
70                  RandomSource.create(RandomSource.ISAAC));
71              // Beta ("Cheng").
72              add(LIST, new org.apache.commons.math3.distribution.BetaDistribution(unusedRng, alphaBeta, betaBeta),
73                  ChengBetaSampler.of(RandomSource.create(RandomSource.MWC_256), alphaBeta, betaBeta));
74              add(LIST, new org.apache.commons.math3.distribution.BetaDistribution(unusedRng, betaBeta, alphaBeta),
75                  ChengBetaSampler.of(RandomSource.create(RandomSource.WELL_19937_A), betaBeta, alphaBeta));
76              // Beta ("Cheng", alternate algorithm).
77              final double alphaBetaAlt = 0.5678;
78              final double betaBetaAlt = 0.1234;
79              add(LIST, new org.apache.commons.math3.distribution.BetaDistribution(unusedRng, alphaBetaAlt, betaBetaAlt),
80                  ChengBetaSampler.of(RandomSource.create(RandomSource.WELL_512_A), alphaBetaAlt, betaBetaAlt));
81              add(LIST, new org.apache.commons.math3.distribution.BetaDistribution(unusedRng, betaBetaAlt, alphaBetaAlt),
82                  ChengBetaSampler.of(RandomSource.create(RandomSource.WELL_19937_C), betaBetaAlt, alphaBetaAlt));
83  
84              // Cauchy ("inverse method").
85              final double medianCauchy = 0.123;
86              final double scaleCauchy = 4.5;
87              add(LIST, new org.apache.commons.math3.distribution.CauchyDistribution(unusedRng, medianCauchy, scaleCauchy),
88                  RandomSource.create(RandomSource.WELL_19937_C));
89  
90              // Chi-square ("inverse method").
91              final int dofChi2 = 12;
92              add(LIST, new org.apache.commons.math3.distribution.ChiSquaredDistribution(unusedRng, dofChi2),
93                  RandomSource.create(RandomSource.WELL_19937_A));
94  
95              // Exponential ("inverse method").
96              final double meanExp = 3.45;
97              add(LIST, new org.apache.commons.math3.distribution.ExponentialDistribution(unusedRng, meanExp),
98                  RandomSource.create(RandomSource.WELL_44497_A));
99              // Exponential.
100             add(LIST, new org.apache.commons.math3.distribution.ExponentialDistribution(unusedRng, meanExp),
101                 AhrensDieterExponentialSampler.of(RandomSource.create(RandomSource.MT), meanExp));
102 
103             // F ("inverse method").
104             final int numDofF = 4;
105             final int denomDofF = 7;
106             add(LIST, new org.apache.commons.math3.distribution.FDistribution(unusedRng, numDofF, denomDofF),
107                 RandomSource.create(RandomSource.MT_64));
108 
109             // Gamma ("inverse method").
110             final double alphaGammaSmallerThanOne = 0.1234;
111             final double alphaGammaLargerThanOne = 2.345;
112             final double thetaGamma = 3.456;
113             add(LIST, new org.apache.commons.math3.distribution.GammaDistribution(unusedRng, alphaGammaLargerThanOne, thetaGamma),
114                 RandomSource.create(RandomSource.SPLIT_MIX_64));
115             // Gamma (alpha < 1).
116             add(LIST, new org.apache.commons.math3.distribution.GammaDistribution(unusedRng, alphaGammaSmallerThanOne, thetaGamma),
117                 AhrensDieterMarsagliaTsangGammaSampler.of(RandomSource.create(RandomSource.XOR_SHIFT_1024_S),
118                                                            alphaGammaSmallerThanOne, thetaGamma));
119             // Gamma (alpha > 1).
120             add(LIST, new org.apache.commons.math3.distribution.GammaDistribution(unusedRng, alphaGammaLargerThanOne, thetaGamma),
121                 AhrensDieterMarsagliaTsangGammaSampler.of(RandomSource.create(RandomSource.WELL_44497_B),
122                                                            alphaGammaLargerThanOne, thetaGamma));
123 
124             // Gumbel ("inverse method").
125             final double muGumbel = -4.56;
126             final double betaGumbel = 0.123;
127             add(LIST, new org.apache.commons.math3.distribution.GumbelDistribution(unusedRng, muGumbel, betaGumbel),
128                 RandomSource.create(RandomSource.WELL_1024_A));
129 
130             // Laplace ("inverse method").
131             final double muLaplace = 12.3;
132             final double betaLaplace = 5.6;
133             add(LIST, new org.apache.commons.math3.distribution.LaplaceDistribution(unusedRng, muLaplace, betaLaplace),
134                 RandomSource.create(RandomSource.MWC_256));
135 
136             // Levy ("inverse method").
137             final double muLevy = -1.098;
138             final double cLevy = 0.76;
139             add(LIST, new org.apache.commons.math3.distribution.LevyDistribution(unusedRng, muLevy, cLevy),
140                 RandomSource.create(RandomSource.TWO_CMRES));
141 
142             // Log normal ("inverse method").
143             final double scaleLogNormal = 2.345;
144             final double shapeLogNormal = 0.1234;
145             add(LIST, new org.apache.commons.math3.distribution.LogNormalDistribution(unusedRng, scaleLogNormal, shapeLogNormal),
146                 RandomSource.create(RandomSource.KISS));
147             // Log-normal (DEPRECATED "Box-Muller").
148             add(LIST, new org.apache.commons.math3.distribution.LogNormalDistribution(unusedRng, scaleLogNormal, shapeLogNormal),
149                 new BoxMullerLogNormalSampler(RandomSource.create(RandomSource.XOR_SHIFT_1024_S), scaleLogNormal, shapeLogNormal));
150             // Log-normal ("Box-Muller").
151             add(LIST, new org.apache.commons.math3.distribution.LogNormalDistribution(unusedRng, scaleLogNormal, shapeLogNormal),
152                 LogNormalSampler.of(new BoxMullerNormalizedGaussianSampler(RandomSource.create(RandomSource.XOR_SHIFT_1024_S)),
153                                     scaleLogNormal, shapeLogNormal));
154             // Log-normal ("Marsaglia").
155             add(LIST, new org.apache.commons.math3.distribution.LogNormalDistribution(unusedRng, scaleLogNormal, shapeLogNormal),
156                 LogNormalSampler.of(new MarsagliaNormalizedGaussianSampler(RandomSource.create(RandomSource.MT_64)),
157                                     scaleLogNormal, shapeLogNormal));
158             // Log-normal ("Ziggurat").
159             add(LIST, new org.apache.commons.math3.distribution.LogNormalDistribution(unusedRng, scaleLogNormal, shapeLogNormal),
160                 LogNormalSampler.of(new ZigguratNormalizedGaussianSampler(RandomSource.create(RandomSource.MWC_256)),
161                                     scaleLogNormal, shapeLogNormal));
162 
163             // Logistic ("inverse method").
164             final double muLogistic = -123.456;
165             final double sLogistic = 7.89;
166             add(LIST, new org.apache.commons.math3.distribution.LogisticDistribution(unusedRng, muLogistic, sLogistic),
167                 RandomSource.create(RandomSource.TWO_CMRES_SELECT, null, 2, 6));
168 
169             // Nakagami ("inverse method").
170             final double muNakagami = 78.9;
171             final double omegaNakagami = 23.4;
172             final double inverseAbsoluteAccuracyNakagami = org.apache.commons.math3.distribution.NakagamiDistribution.DEFAULT_INVERSE_ABSOLUTE_ACCURACY;
173             add(LIST, new org.apache.commons.math3.distribution.NakagamiDistribution(unusedRng, muNakagami, omegaNakagami, inverseAbsoluteAccuracyNakagami),
174                 RandomSource.create(RandomSource.TWO_CMRES_SELECT, null, 5, 3));
175 
176             // Pareto ("inverse method").
177             final double scalePareto = 23.45;
178             final double shapePareto = 0.1234;
179             add(LIST, new org.apache.commons.math3.distribution.ParetoDistribution(unusedRng, scalePareto, shapePareto),
180                 RandomSource.create(RandomSource.TWO_CMRES_SELECT, null, 9, 11));
181             // Pareto.
182             add(LIST, new org.apache.commons.math3.distribution.ParetoDistribution(unusedRng, scalePareto, shapePareto),
183                 InverseTransformParetoSampler.of(RandomSource.create(RandomSource.XOR_SHIFT_1024_S), scalePareto, shapePareto));
184 
185             // T ("inverse method").
186             final double dofT = 0.76543;
187             add(LIST, new org.apache.commons.math3.distribution.TDistribution(unusedRng, dofT),
188                 RandomSource.create(RandomSource.ISAAC));
189 
190             // Triangular ("inverse method").
191             final double aTriangle = -0.76543;
192             final double cTriangle = -0.65432;
193             final double bTriangle = -0.54321;
194             add(LIST, new org.apache.commons.math3.distribution.TriangularDistribution(unusedRng, aTriangle, cTriangle, bTriangle),
195                 RandomSource.create(RandomSource.MT));
196 
197             // Uniform ("inverse method").
198             final double loUniform = -1.098;
199             final double hiUniform = 0.76;
200             add(LIST, new org.apache.commons.math3.distribution.UniformRealDistribution(unusedRng, loUniform, hiUniform),
201                 RandomSource.create(RandomSource.TWO_CMRES));
202             // Uniform.
203             add(LIST, new org.apache.commons.math3.distribution.UniformRealDistribution(unusedRng, loUniform, hiUniform),
204                 ContinuousUniformSampler.of(RandomSource.create(RandomSource.MT_64), loUniform, hiUniform));
205 
206             // Weibull ("inverse method").
207             final double alphaWeibull = 678.9;
208             final double betaWeibull = 98.76;
209             add(LIST, new org.apache.commons.math3.distribution.WeibullDistribution(unusedRng, alphaWeibull, betaWeibull),
210                 RandomSource.create(RandomSource.WELL_44497_B));
211         } catch (Exception e) {
212             // CHECKSTYLE: stop Regexp
213             System.err.println("Unexpected exception while creating the list of samplers: " + e);
214             e.printStackTrace(System.err);
215             // CHECKSTYLE: resume Regexp
216             throw new RuntimeException(e);
217         }
218     }
219 
220     /**
221      * Class contains only static methods.
222      */
223     private ContinuousSamplersList() {}
224 
225     /**
226      * @param list List of data (one the "parameters" tested by the Junit parametric test).
227      * @param dist Distribution to which the samples are supposed to conform.
228      * @param rng Generator of uniformly distributed sequences.
229      */
230     private static void add(List<ContinuousSamplerTestData[]> list,
231                             final org.apache.commons.math3.distribution.RealDistribution dist,
232                             UniformRandomProvider rng) {
233         final ContinuousSampler inverseMethodSampler =
234             InverseTransformContinuousSampler.of(rng,
235                 new ContinuousInverseCumulativeProbabilityFunction() {
236                     @Override
237                     public double inverseCumulativeProbability(double p) {
238                         return dist.inverseCumulativeProbability(p);
239                     }
240                     @Override
241                     public String toString() {
242                         return dist.toString();
243                     }
244                 });
245         list.add(new ContinuousSamplerTestData[] {new ContinuousSamplerTestData(inverseMethodSampler,
246                                                                                 getDeciles(dist))});
247     }
248 
249     /**
250      * @param list List of data (one the "parameters" tested by the Junit parametric test).
251      * @param dist Distribution to which the samples are supposed to conform.
252      * @param sampler Sampler.
253      */
254     private static void add(List<ContinuousSamplerTestData[]> list,
255                             final org.apache.commons.math3.distribution.RealDistribution dist,
256                             final ContinuousSampler sampler) {
257         list.add(new ContinuousSamplerTestData[] {new ContinuousSamplerTestData(sampler,
258                                                                                 getDeciles(dist))});
259     }
260 
261     /**
262      * Subclasses that are "parametric" tests can forward the call to
263      * the "@Parameters"-annotated method to this method.
264      *
265      * @return the list of all generators.
266      */
267     public static Iterable<ContinuousSamplerTestData[]> list() {
268         return Collections.unmodifiableList(LIST);
269     }
270 
271     /**
272      * @param dist Distribution.
273      * @return the deciles of the given distribution.
274      */
275     private static double[] getDeciles(org.apache.commons.math3.distribution.RealDistribution dist) {
276         final int last = 9;
277         final double[] deciles = new double[last];
278         final double ten = 10;
279         for (int i = 0; i < last; i++) {
280             deciles[i] = dist.inverseCumulativeProbability((i + 1) / ten);
281         }
282         return deciles;
283     }
284 }