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;
18
19 import java.util.Objects;
20 import java.util.stream.DoubleStream;
21 import java.util.stream.IntStream;
22 import java.util.stream.LongStream;
23 import java.util.stream.Stream;
24 import java.util.stream.StreamSupport;
25
26 /**
27 * Applies to generators that can be split into two objects (the original and a new instance)
28 * each of which implements the same interface (and can be recursively split indefinitely).
29 * It is assumed that the two generators resulting from a split can be used concurrently on
30 * different threads.
31 *
32 * <p>Ideally all generators produced by recursive splitting from the original object are
33 * statistically independent and individually uniform. In this case it would be expected that
34 * the set of values collectively generated from a group of split generators would have the
35 * same statistical properties as the same number of values produced from a single generator
36 * object.
37 *
38 * @since 1.5
39 */
40 public interface SplittableUniformRandomProvider extends UniformRandomProvider {
41 /**
42 * Creates a new random generator, split off from this one, that implements
43 * the {@link SplittableUniformRandomProvider} interface.
44 *
45 * <p>The current generator may be used a source of randomness to initialise the new instance.
46 * In this case repeat invocations of this method will return objects with a different
47 * initial state that are expected to be statistically independent.
48 *
49 * @return A new instance.
50 */
51 default SplittableUniformRandomProvider split() {
52 return split(this);
53 }
54
55 /**
56 * Creates a new random generator, split off from this one, that implements
57 * the {@link SplittableUniformRandomProvider} interface.
58 *
59 * @param source A source of randomness used to initialise the new instance.
60 * @return A new instance.
61 * @throws NullPointerException if {@code source} is null
62 */
63 SplittableUniformRandomProvider split(UniformRandomProvider source);
64
65 /**
66 * Returns an effectively unlimited stream of new random generators, each of which
67 * implements the {@link SplittableUniformRandomProvider} interface.
68 *
69 * <p>The current generator may be used a source of randomness to initialise the new instances.
70 *
71 * @return a stream of random generators.
72 */
73 default Stream<SplittableUniformRandomProvider> splits() {
74 return splits(Long.MAX_VALUE, this);
75 }
76
77 /**
78 * Returns an effectively unlimited stream of new random generators, each of which
79 * implements the {@link SplittableUniformRandomProvider} interface.
80 *
81 * @param source A source of randomness used to initialise the new instances; this may
82 * be split to provide a source of randomness across a parallel stream.
83 * @return a stream of random generators.
84 * @throws NullPointerException if {@code source} is null
85 */
86 default Stream<SplittableUniformRandomProvider> splits(SplittableUniformRandomProvider source) {
87 return this.splits(Long.MAX_VALUE, source);
88 }
89
90 /**
91 * Returns a stream producing the given {@code streamSize} number of new random
92 * generators, each of which implements the {@link SplittableUniformRandomProvider}
93 * interface.
94 *
95 * <p>The current generator may be used a source of randomness to initialise the new instances.
96 *
97 * @param streamSize Number of objects to generate.
98 * @return a stream of random generators; the stream is limited to the given
99 * {@code streamSize}.
100 * @throws IllegalArgumentException if {@code streamSize} is negative.
101 */
102 default Stream<SplittableUniformRandomProvider> splits(long streamSize) {
103 return splits(streamSize, this);
104 }
105
106 /**
107 * Returns a stream producing the given {@code streamSize} number of new random
108 * generators, each of which implements the {@link SplittableUniformRandomProvider}
109 * interface.
110 *
111 * @param streamSize Number of objects to generate.
112 * @param source A source of randomness used to initialise the new instances; this may
113 * be split to provide a source of randomness across a parallel stream.
114 * @return a stream of random generators; the stream is limited to the given
115 * {@code streamSize}.
116 * @throws IllegalArgumentException if {@code streamSize} is negative.
117 * @throws NullPointerException if {@code source} is null
118 */
119 default Stream<SplittableUniformRandomProvider> splits(long streamSize,
120 SplittableUniformRandomProvider source) {
121 UniformRandomProviderSupport.validateStreamSize(streamSize);
122 Objects.requireNonNull(source, "source");
123 return StreamSupport.stream(
124 new UniformRandomProviderSupport.ProviderSplitsSpliterator(0, streamSize, source, this), false);
125 }
126
127 @Override
128 default IntStream ints() {
129 return ints(Long.MAX_VALUE);
130 }
131
132 @Override
133 default IntStream ints(int origin, int bound) {
134 return ints(Long.MAX_VALUE, origin, bound);
135 }
136
137 @Override
138 default IntStream ints(long streamSize) {
139 UniformRandomProviderSupport.validateStreamSize(streamSize);
140 return StreamSupport.intStream(
141 new UniformRandomProviderSupport.ProviderIntsSpliterator(
142 0, streamSize, this, UniformRandomProvider::nextInt), false);
143 }
144
145 @Override
146 default IntStream ints(long streamSize, int origin, int bound) {
147 UniformRandomProviderSupport.validateStreamSize(streamSize);
148 UniformRandomProviderSupport.validateRange(origin, bound);
149 return StreamSupport.intStream(
150 new UniformRandomProviderSupport.ProviderIntsSpliterator(
151 0, streamSize, this, rng -> rng.nextInt(origin, bound)), false);
152 }
153
154 @Override
155 default LongStream longs() {
156 return longs(Long.MAX_VALUE);
157 }
158
159 @Override
160 default LongStream longs(long origin, long bound) {
161 return longs(Long.MAX_VALUE, origin, bound);
162 }
163
164 @Override
165 default LongStream longs(long streamSize) {
166 UniformRandomProviderSupport.validateStreamSize(streamSize);
167 return StreamSupport.longStream(
168 new UniformRandomProviderSupport.ProviderLongsSpliterator(
169 0, streamSize, this, UniformRandomProvider::nextLong), false);
170 }
171
172 @Override
173 default LongStream longs(long streamSize, long origin, long bound) {
174 UniformRandomProviderSupport.validateStreamSize(streamSize);
175 UniformRandomProviderSupport.validateRange(origin, bound);
176 return StreamSupport.longStream(
177 new UniformRandomProviderSupport.ProviderLongsSpliterator(
178 0, streamSize, this, rng -> rng.nextLong(origin, bound)), false);
179 }
180
181 @Override
182 default DoubleStream doubles() {
183 return doubles(Long.MAX_VALUE);
184 }
185
186 @Override
187 default DoubleStream doubles(double origin, double bound) {
188 return doubles(Long.MAX_VALUE, origin, bound);
189 }
190
191 @Override
192 default DoubleStream doubles(long streamSize) {
193 UniformRandomProviderSupport.validateStreamSize(streamSize);
194 return StreamSupport.doubleStream(
195 new UniformRandomProviderSupport.ProviderDoublesSpliterator(
196 0, streamSize, this, UniformRandomProvider::nextDouble), false);
197 }
198
199 @Override
200 default DoubleStream doubles(long streamSize, double origin, double bound) {
201 UniformRandomProviderSupport.validateStreamSize(streamSize);
202 UniformRandomProviderSupport.validateRange(origin, bound);
203 return StreamSupport.doubleStream(
204 new UniformRandomProviderSupport.ProviderDoublesSpliterator(
205 0, streamSize, this, rng -> rng.nextDouble(origin, bound)), false);
206 }
207 }