SplittableUniformRandomProvider.java

  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. import java.util.Objects;
  19. import java.util.stream.DoubleStream;
  20. import java.util.stream.IntStream;
  21. import java.util.stream.LongStream;
  22. import java.util.stream.Stream;
  23. import java.util.stream.StreamSupport;

  24. /**
  25.  * Applies to generators that can be split into two objects (the original and a new instance)
  26.  * each of which implements the same interface (and can be recursively split indefinitely).
  27.  * It is assumed that the two generators resulting from a split can be used concurrently on
  28.  * different threads.
  29.  *
  30.  * <p>Ideally all generators produced by recursive splitting from the original object are
  31.  * statistically independent and individually uniform. In this case it would be expected that
  32.  * the set of values collectively generated from a group of split generators would have the
  33.  * same statistical properties as the same number of values produced from a single generator
  34.  * object.
  35.  *
  36.  * @since 1.5
  37.  */
  38. public interface SplittableUniformRandomProvider extends UniformRandomProvider {
  39.     /**
  40.      * Creates a new random generator, split off from this one, that implements
  41.      * the {@link SplittableUniformRandomProvider} interface.
  42.      *
  43.      * <p>The current generator may be used a source of randomness to initialise the new instance.
  44.      * In this case repeat invocations of this method will return objects with a different
  45.      * initial state that are expected to be statistically independent.
  46.      *
  47.      * @return A new instance.
  48.      */
  49.     default SplittableUniformRandomProvider split() {
  50.         return split(this);
  51.     }

  52.     /**
  53.      * Creates a new random generator, split off from this one, that implements
  54.      * the {@link SplittableUniformRandomProvider} interface.
  55.      *
  56.      * @param source A source of randomness used to initialise the new instance.
  57.      * @return A new instance.
  58.      * @throws NullPointerException if {@code source} is null
  59.      */
  60.     SplittableUniformRandomProvider split(UniformRandomProvider source);

  61.     /**
  62.      * Returns an effectively unlimited stream of new random generators, each of which
  63.      * implements the {@link SplittableUniformRandomProvider} interface.
  64.      *
  65.      * <p>The current generator may be used a source of randomness to initialise the new instances.
  66.      *
  67.      * @return a stream of random generators.
  68.      */
  69.     default Stream<SplittableUniformRandomProvider> splits() {
  70.         return splits(Long.MAX_VALUE, this);
  71.     }

  72.     /**
  73.      * Returns an effectively unlimited stream of new random generators, each of which
  74.      * implements the {@link SplittableUniformRandomProvider} interface.
  75.      *
  76.      * @param source A source of randomness used to initialise the new instances; this may
  77.      * be split to provide a source of randomness across a parallel stream.
  78.      * @return a stream of random generators.
  79.      * @throws NullPointerException if {@code source} is null
  80.      */
  81.     default Stream<SplittableUniformRandomProvider> splits(SplittableUniformRandomProvider source) {
  82.         return this.splits(Long.MAX_VALUE, source);
  83.     }

  84.     /**
  85.      * Returns a stream producing the given {@code streamSize} number of new random
  86.      * generators, each of which implements the {@link SplittableUniformRandomProvider}
  87.      * interface.
  88.      *
  89.      * <p>The current generator may be used a source of randomness to initialise the new instances.
  90.      *
  91.      * @param streamSize Number of objects to generate.
  92.      * @return a stream of random generators; the stream is limited to the given
  93.      * {@code streamSize}.
  94.      * @throws IllegalArgumentException if {@code streamSize} is negative.
  95.      */
  96.     default Stream<SplittableUniformRandomProvider> splits(long streamSize) {
  97.         return splits(streamSize, this);
  98.     }

  99.     /**
  100.      * Returns a stream producing the given {@code streamSize} number of new random
  101.      * generators, each of which implements the {@link SplittableUniformRandomProvider}
  102.      * interface.
  103.      *
  104.      * @param streamSize Number of objects to generate.
  105.      * @param source A source of randomness used to initialise the new instances; this may
  106.      * be split to provide a source of randomness across a parallel stream.
  107.      * @return a stream of random generators; the stream is limited to the given
  108.      * {@code streamSize}.
  109.      * @throws IllegalArgumentException if {@code streamSize} is negative.
  110.      * @throws NullPointerException if {@code source} is null
  111.      */
  112.     default Stream<SplittableUniformRandomProvider> splits(long streamSize,
  113.                                                            SplittableUniformRandomProvider source) {
  114.         UniformRandomProviderSupport.validateStreamSize(streamSize);
  115.         Objects.requireNonNull(source, "source");
  116.         return StreamSupport.stream(
  117.             new UniformRandomProviderSupport.ProviderSplitsSpliterator(0, streamSize, source, this), false);
  118.     }

  119.     @Override
  120.     default IntStream ints() {
  121.         return ints(Long.MAX_VALUE);
  122.     }

  123.     @Override
  124.     default IntStream ints(int origin, int bound) {
  125.         return ints(Long.MAX_VALUE, origin, bound);
  126.     }

  127.     @Override
  128.     default IntStream ints(long streamSize) {
  129.         UniformRandomProviderSupport.validateStreamSize(streamSize);
  130.         return StreamSupport.intStream(
  131.             new UniformRandomProviderSupport.ProviderIntsSpliterator(
  132.                 0, streamSize, this, UniformRandomProvider::nextInt), false);
  133.     }

  134.     @Override
  135.     default IntStream ints(long streamSize, int origin, int bound) {
  136.         UniformRandomProviderSupport.validateStreamSize(streamSize);
  137.         UniformRandomProviderSupport.validateRange(origin, bound);
  138.         return StreamSupport.intStream(
  139.             new UniformRandomProviderSupport.ProviderIntsSpliterator(
  140.                 0, streamSize, this, rng -> rng.nextInt(origin, bound)), false);
  141.     }

  142.     @Override
  143.     default LongStream longs() {
  144.         return longs(Long.MAX_VALUE);
  145.     }

  146.     @Override
  147.     default LongStream longs(long origin, long bound) {
  148.         return longs(Long.MAX_VALUE, origin, bound);
  149.     }

  150.     @Override
  151.     default LongStream longs(long streamSize) {
  152.         UniformRandomProviderSupport.validateStreamSize(streamSize);
  153.         return StreamSupport.longStream(
  154.             new UniformRandomProviderSupport.ProviderLongsSpliterator(
  155.                 0, streamSize, this, UniformRandomProvider::nextLong), false);
  156.     }

  157.     @Override
  158.     default LongStream longs(long streamSize, long origin, long bound) {
  159.         UniformRandomProviderSupport.validateStreamSize(streamSize);
  160.         UniformRandomProviderSupport.validateRange(origin, bound);
  161.         return StreamSupport.longStream(
  162.             new UniformRandomProviderSupport.ProviderLongsSpliterator(
  163.                 0, streamSize, this, rng -> rng.nextLong(origin, bound)), false);
  164.     }

  165.     @Override
  166.     default DoubleStream doubles() {
  167.         return doubles(Long.MAX_VALUE);
  168.     }

  169.     @Override
  170.     default DoubleStream doubles(double origin, double bound) {
  171.         return doubles(Long.MAX_VALUE, origin, bound);
  172.     }

  173.     @Override
  174.     default DoubleStream doubles(long streamSize) {
  175.         UniformRandomProviderSupport.validateStreamSize(streamSize);
  176.         return StreamSupport.doubleStream(
  177.             new UniformRandomProviderSupport.ProviderDoublesSpliterator(
  178.                 0, streamSize, this, UniformRandomProvider::nextDouble), false);
  179.     }

  180.     @Override
  181.     default DoubleStream doubles(long streamSize, double origin, double bound) {
  182.         UniformRandomProviderSupport.validateStreamSize(streamSize);
  183.         UniformRandomProviderSupport.validateRange(origin, bound);
  184.         return StreamSupport.doubleStream(
  185.             new UniformRandomProviderSupport.ProviderDoublesSpliterator(
  186.                 0, streamSize, this, rng -> rng.nextDouble(origin, bound)), false);
  187.     }
  188. }