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  
18  package org.apache.commons.rng.examples.jmh.sampling.distribution;
19  
20  import org.apache.commons.math3.distribution.LevyDistribution;
21  import org.apache.commons.rng.UniformRandomProvider;
22  import org.apache.commons.rng.sampling.distribution.ContinuousInverseCumulativeProbabilityFunction;
23  import org.apache.commons.rng.sampling.distribution.ContinuousSampler;
24  import org.apache.commons.rng.sampling.distribution.InverseTransformContinuousSampler;
25  import org.apache.commons.rng.sampling.distribution.LevySampler;
26  import org.apache.commons.rng.simple.RandomSource;
27  import org.openjdk.jmh.annotations.Benchmark;
28  import org.openjdk.jmh.annotations.BenchmarkMode;
29  import org.openjdk.jmh.annotations.Fork;
30  import org.openjdk.jmh.annotations.Measurement;
31  import org.openjdk.jmh.annotations.Mode;
32  import org.openjdk.jmh.annotations.OutputTimeUnit;
33  import org.openjdk.jmh.annotations.Param;
34  import org.openjdk.jmh.annotations.Scope;
35  import org.openjdk.jmh.annotations.Setup;
36  import org.openjdk.jmh.annotations.State;
37  import org.openjdk.jmh.annotations.Warmup;
38  
39  import java.util.concurrent.TimeUnit;
40  
41  /**
42   * Executes a benchmark to compare the speed of generation of Levy distributed random numbers
43   * using different methods.
44   */
45  @BenchmarkMode(Mode.AverageTime)
46  @OutputTimeUnit(TimeUnit.NANOSECONDS)
47  @Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
48  @Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
49  @State(Scope.Benchmark)
50  @Fork(value = 1, jvmArgs = {"-server", "-Xms128M", "-Xmx128M"})
51  public class LevySamplersPerformance {
52      /**
53       * The value.
54       *
55       * <p>This must NOT be final!</p>
56       */
57      private double value;
58  
59      /**
60       * The samplers's to use for testing. Defines the RandomSource  and the type of Levy sampler.
61       */
62      @State(Scope.Benchmark)
63      public static class Sources {
64          /**
65           * RNG providers.
66           *
67           * <p>Use different speeds.</p>
68           *
69           * @see <a href="https://commons.apache.org/proper/commons-rng/userguide/rng.html">
70           *      Commons RNG user guide</a>
71           */
72          @Param({"SPLIT_MIX_64",
73                  "MWC_256",
74                  "JDK"})
75          private String randomSourceName;
76  
77          /**
78           * The sampler type.
79           */
80          @Param({"LevySampler", "InverseTransformDiscreteSampler"})
81          private String samplerType;
82  
83          /** The sampler. */
84          private ContinuousSampler sampler;
85  
86          /**
87           * @return the sampler.
88           */
89          public ContinuousSampler getSampler() {
90              return sampler;
91          }
92  
93          /** Instantiates sampler. */
94          @Setup
95          public void setup() {
96              final RandomSource randomSource = RandomSource.valueOf(randomSourceName);
97              final UniformRandomProvider rng = randomSource.create();
98              final double location = 0.0;
99              final double scale = 1.0;
100             if ("LevySampler".equals(samplerType)) {
101                 sampler = LevySampler.of(rng, location, scale);
102             } else {
103                 final ContinuousInverseCumulativeProbabilityFunction levyFunction =
104                     new ContinuousInverseCumulativeProbabilityFunction() {
105                         /** Use CM for the inverse CDF. null is for the unused RNG. */
106                         private final LevyDistribution dist = new LevyDistribution(null, location, scale);
107                         @Override
108                         public double inverseCumulativeProbability(double p) {
109                             return dist.inverseCumulativeProbability(p);
110                         }
111                     };
112                 sampler = InverseTransformContinuousSampler.of(rng, levyFunction);
113             }
114         }
115     }
116 
117     /**
118      * Baseline for the JMH timing overhead for production of an {@code double} value.
119      *
120      * @return the {@code double} value
121      */
122     @Benchmark
123     public double baseline() {
124         return value;
125     }
126 
127     /**
128      * Run the sampler.
129      *
130      * @param sources Source of randomness.
131      * @return the sample value
132      */
133     @Benchmark
134     public double sample(Sources sources) {
135         return sources.getSampler().sample();
136     }
137 }