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