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;
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 }