1 /*
2  * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 package test.java.util.Random;
24 
25 import java.util.ArrayList;
26 import java.util.List;
27 
28 import java.util.random.*;
29 
30 import java.util.Set;
31 import java.util.concurrent.CompletableFuture;
32 import java.util.concurrent.ExecutionException;
33 import java.util.concurrent.ThreadLocalRandom;
34 import java.util.concurrent.TimeUnit;
35 import java.util.concurrent.TimeoutException;
36 import java.util.function.DoubleSupplier;
37 import java.util.stream.Stream;
38 
39 import static java.util.stream.Collectors.toList;
40 import static java.util.stream.Collectors.toSet;
41 
42 /**
43  * @test
44  * @summary test bit sequences produced by clases that implement interface RandomGenerator
45  * @bug 8248862
46  * @run main RandomTestMoments
47  * @author Guy Steele
48  * @key randomness
49  */
50 
51 public class RandomTestMoments {
52 
53     static String currentRNG = "";
54     static int failCount = 0;
55 
exceptionOnFail()56     static void exceptionOnFail() {
57         if (failCount != 0) {
58             throw new RuntimeException(failCount + " fails detected");
59         }
60     }
61 
setRNG(String rng)62     static void setRNG(String rng) {
63         currentRNG = rng;
64     }
65 
fail(String format, Object... args)66     static void fail(String format, Object... args) {
67         if (currentRNG.length() != 0) {
68             System.err.println(currentRNG);
69             currentRNG = "";
70         }
71 
72         System.err.format("  " + format, args);
73         failCount++;
74     }
75 
76     static final int SEQUENCE_SIZE = 50000;
77 
78     // Moment k of uniform distribution over [0.0,1.0) is 1.0/(1+k).
79 
80     static double[][] momentsUniform = {
81        { 1.00000, 1.00000, 0.01000 },
82        { 0.500000, 0.500000, 0.0266265 },
83        { 0.333333, 0.333333, 0.0391128 },
84        { 0.250000, 0.250000, 0.0477151 },
85        { 0.200000, 0.200000, 0.0540496 },
86        { 0.166667, 0.166667, 0.0589355 },
87        { 0.142857, 0.142857, 0.0628462 },
88        { 0.125000, 0.125000, 0.0660693 },
89        { 0.111111, 0.111111, 0.0688036 },
90        { 0.100000, 0.100000, 0.0712002 },
91        { 0.0909091, 0.0909091, 0.0733755 },
92        { 0.0833333, 0.0833333, 0.0754172 },
93        { 0.0769231, 0.0769231, 0.0773868 },
94        { 0.0714286, 0.0714286, 0.0793244 },
95        { 0.0666667, 0.0666667, 0.0812526 },
96        { 0.0625000, 0.0625000, 0.0831806 },
97     };
98 
99     // Moment k of exponential distribution with mean 1 is k!.
100 
101     static double[][] momentsExponential = {
102        { 1.00000, 1.00000, 0.01000 },
103        { 1.00000, 1.00000, 0.0718997 },
104        { 2.00000, 2.00000, 0.153241 },
105        { 6.00000, 6.00000, 0.282813 },
106        { 24.0000, 24.0000, 0.503707 },
107     };
108 
109 
110     // Absolute moment k of Gaussian distribution with mean 0 and stddev 1 is
111     //    pow(2.0,k/2.0)*gamma((k+1)/2.0)/sqrt(PI)
112     // https://arxiv.org/pdf/1209.4340.pdf, equation (18)
113 
114     static double[][] absoluteMomentsGaussian = {
115        { 1.00000, 1.00000, 0.01 },
116        { 0.797885, 0.797885, 0.1 },
117        { 1.00000, 1.00000, 0.1 },
118        { 1.59577, 1.59577, 0.2 },
119        { 3.00000, 3.00000, 0.2 },
120        { 6.38308, 6.38308, 0.2 },
121        { 15.0000, 15.0000, 0.2 },
122        { 38.2985, 38.2985, 0.2 },
123        { 105.000, 105.000, 0.4 },
124     };
125 
checkMoments(String test, double[] measurements, double[][] standard)126     static void checkMoments(String test, double[] measurements, double[][] standard) {
127        for (int j = 0; j < measurements.length; j++) {
128            double actual = measurements[j];
129            double expected = standard[j][0];
130            double basis = standard[j][1];
131            double tolerance = standard[j][2];
132            if (!(Math.abs(actual - expected)/basis < tolerance)) {
133                fail("%s fail: actual=%f, expected=%f, basis=%f, tolerance=%f\n",
134                      test, actual, expected, basis, tolerance);
135            }
136        }
137     }
138 
testMomentsGaussian(DoubleSupplier theSupplier)139     static void testMomentsGaussian(DoubleSupplier theSupplier) {
140        int m = absoluteMomentsGaussian.length;
141        double[] absoluteMoments = new double[m];
142        for (int j = 0; j < SEQUENCE_SIZE; j++) {
143            double v = theSupplier.getAsDouble();
144            double z = 1.0;
145            for (int k = 0; k < m; k++) {
146                absoluteMoments[k] += Math.abs(z);
147                z *= v;
148            }
149        }
150        for (int k = 0; k < m; k++) {
151            absoluteMoments[k] /= SEQUENCE_SIZE;
152        }
153        checkMoments("Gaussian", absoluteMoments, absoluteMomentsGaussian);
154     }
155 
testMomentsExponential(DoubleSupplier theSupplier)156     static void testMomentsExponential(DoubleSupplier theSupplier) {
157        int m = momentsExponential.length;
158        double[] moments = new double[m];
159        for (int j = 0; j < SEQUENCE_SIZE; j++) {
160            double v = theSupplier.getAsDouble();
161            double z = 1.0;
162            for (int k = 0; k < m; k++) {
163                moments[k] += z;
164                z *= v;
165            }
166        }
167        for (int k = 0; k < m; k++) {
168            moments[k] /= SEQUENCE_SIZE;
169        }
170        checkMoments("Exponential", moments, momentsExponential);
171     }
172 
testMomentsUniform(DoubleSupplier theSupplier)173     static void testMomentsUniform(DoubleSupplier theSupplier) {
174        int m = momentsUniform.length;
175        double[] moments = new double[m];
176        for (int j = 0; j < SEQUENCE_SIZE; j++) {
177            double v = theSupplier.getAsDouble();
178            double z = 1.0;
179            for (int k = 0; k < m; k++) {
180                moments[k] += z;
181                z *= v;
182            }
183        }
184        for (int k = 0; k < m; k++) {
185            moments[k] /= SEQUENCE_SIZE;
186        }
187        checkMoments("Uniform", moments, momentsUniform);
188     }
189 
testOneRng(RandomGenerator rng)190     static void testOneRng(RandomGenerator rng) {
191         testMomentsGaussian(rng::nextGaussian);
192         testMomentsExponential(rng::nextExponential);
193         testMomentsUniform(rng::nextDouble);
194         testMomentsUniform(rng.doubles().iterator()::next);
195     }
196 
main(String[] args)197     public static void main(String[] args) {
198         RandomGeneratorFactory.all()
199                               .filter(f -> !f.name().equals("SecureRandom"))
200                               .forEach(factory -> {
201                 setRNG(factory.name());
202                 testOneRng(factory.create(325) );
203             });
204 
205         exceptionOnFail();
206     }
207 
208 }
209