001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.rng; 018 019import java.util.Objects; 020import java.util.stream.DoubleStream; 021import java.util.stream.IntStream; 022import java.util.stream.LongStream; 023import java.util.stream.Stream; 024import java.util.stream.StreamSupport; 025 026/** 027 * Applies to generators that can be split into two objects (the original and a new instance) 028 * each of which implements the same interface (and can be recursively split indefinitely). 029 * It is assumed that the two generators resulting from a split can be used concurrently on 030 * different threads. 031 * 032 * <p>Ideally all generators produced by recursive splitting from the original object are 033 * statistically independent and individually uniform. In this case it would be expected that 034 * the set of values collectively generated from a group of split generators would have the 035 * same statistical properties as the same number of values produced from a single generator 036 * object. 037 * 038 * @since 1.5 039 */ 040public interface SplittableUniformRandomProvider extends UniformRandomProvider { 041 /** 042 * Creates a new random generator, split off from this one, that implements 043 * the {@link SplittableUniformRandomProvider} interface. 044 * 045 * <p>The current generator may be used a source of randomness to initialise the new instance. 046 * In this case repeat invocations of this method will return objects with a different 047 * initial state that are expected to be statistically independent. 048 * 049 * @return A new instance. 050 */ 051 default SplittableUniformRandomProvider split() { 052 return split(this); 053 } 054 055 /** 056 * Creates a new random generator, split off from this one, that implements 057 * the {@link SplittableUniformRandomProvider} interface. 058 * 059 * @param source A source of randomness used to initialise the new instance. 060 * @return A new instance. 061 * @throws NullPointerException if {@code source} is null 062 */ 063 SplittableUniformRandomProvider split(UniformRandomProvider source); 064 065 /** 066 * Returns an effectively unlimited stream of new random generators, each of which 067 * implements the {@link SplittableUniformRandomProvider} interface. 068 * 069 * <p>The current generator may be used a source of randomness to initialise the new instances. 070 * 071 * @return a stream of random generators. 072 */ 073 default Stream<SplittableUniformRandomProvider> splits() { 074 return splits(Long.MAX_VALUE, this); 075 } 076 077 /** 078 * Returns an effectively unlimited stream of new random generators, each of which 079 * implements the {@link SplittableUniformRandomProvider} interface. 080 * 081 * @param source A source of randomness used to initialise the new instances; this may 082 * be split to provide a source of randomness across a parallel stream. 083 * @return a stream of random generators. 084 * @throws NullPointerException if {@code source} is null 085 */ 086 default Stream<SplittableUniformRandomProvider> splits(SplittableUniformRandomProvider source) { 087 return this.splits(Long.MAX_VALUE, source); 088 } 089 090 /** 091 * Returns a stream producing the given {@code streamSize} number of new random 092 * generators, each of which implements the {@link SplittableUniformRandomProvider} 093 * interface. 094 * 095 * <p>The current generator may be used a source of randomness to initialise the new instances. 096 * 097 * @param streamSize Number of objects to generate. 098 * @return a stream of random generators; the stream is limited to the given 099 * {@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}