RandomRegistry.java
001 /*
002  * Java Genetic Algorithm Library (jenetics-5.0.0).
003  * Copyright (c) 2007-2019 Franz Wilhelmstötter
004  *
005  * Licensed under the Apache License, Version 2.0 (the "License");
006  * you may not use this file except in compliance with the License.
007  * 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  *
017  * Author:
018  *    Franz Wilhelmstötter (franz.wilhelmstoetter@gmail.com)
019  */
020 package io.jenetics.util;
021 
022 import static java.util.Objects.requireNonNull;
023 
024 import java.util.Random;
025 import java.util.concurrent.ThreadLocalRandom;
026 import java.util.function.Consumer;
027 import java.util.function.Function;
028 import java.util.function.Supplier;
029 
030 /**
031  * This class holds the {@link Random} engine used for the GA. The
032  * {@code RandomRegistry} is thread safe. The registry is initialized with the
033  {@link ThreadLocalRandom} PRNG, which has a much better performance behavior
034  * than an instance of the {@code Random} class. Alternatively, you can
035  * initialize the registry with one of the PRNG, which are being part of the
036  * library.
037  <p>
038  *
039  <b>Setup of a <i>global</i> PRNG</b>
040  *
041  <pre>{@code
042  * public class GA {
043  *     public static void main(final String[] args) {
044  *         // Initialize the registry with a ThreadLocal instance of the PRGN.
045  *         // This is the preferred way setting a new PRGN.
046  *         RandomRegistry.setRandom(new LCG64ShiftRandom.ThreadLocal());
047  *
048  *         // Using a thread safe variant of the PRGN. Leads to slower PRN
049  *         // generation, but gives you the possibility to set a PRNG seed.
050  *         RandomRegistry.setRandom(new LCG64ShiftRandom.ThreadSafe(1234));
051  *
052  *         ...
053  *         final EvolutionResult<DoubleGene, Double> result = stream
054  *             .limit(100)
055  *             .collect(toBestEvolutionResult());
056  *     }
057  * }
058  * }</pre>
059  <p>
060  *
061  <b>Setup of a <i>local</i> PRNG</b><br>
062  *
063  * You can temporarily (and locally) change the implementation of the PRNG. E.g.
064  * for initialize the engine stream with the same initial population.
065  *
066  <pre>{@code
067  * public class GA {
068  *     public static void main(final String[] args) {
069  *         // Create a reproducible list of genotypes.
070  *         final List<Genotype<DoubleGene>> genotypes =
071  *             with(new LCG64ShiftRandom(123), r ->
072  *                 Genotype.of(DoubleChromosome.of(0, 10)).instances()
073  *                     .limit(50)
074  *                     .collect(toList())
075  *             );
076  *
077  *         final Engine<DoubleGene, Double> engine = ...;
078  *         final EvolutionResult<DoubleGene, Double> result = engine
079  *              // Initialize the evolution stream with the given genotypes.
080  *             .stream(genotypes)
081  *             .limit(100)
082  *             .collect(toBestEvolutionResult());
083  *     }
084  * }
085  * }</pre>
086  <p>
087  *
088  @see Random
089  @see ThreadLocalRandom
090  *
091  @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
092  @since 1.0
093  @version 3.0
094  */
095 public final class RandomRegistry {
096     private RandomRegistry() {}
097 
098     private static final Context<Supplier<Random>> CONTEXT =
099         new Context<>(ThreadLocalRandom::current);
100 
101     /**
102      * Return the global {@link Random} object.
103      *
104      @return the global {@link Random} object.
105      */
106     public static Random getRandom() {
107         return CONTEXT.get().get();
108     }
109 
110     static Random random() {
111         return CONTEXT.get().get();
112     }
113 
114     /**
115      * Set the new global {@link Random} object for the GA. The given
116      {@link Random} <b>must</b> be thread safe, which is the case for the
117      * default Java {@code Random} implementation.
118      <p>
119      * Setting a <i>thread-local</i> random object leads, in general, to a faster
120      * PRN generation, because the given {@code Random} engine don't have to be
121      * thread-safe.
122      *
123      @see #setRandom(ThreadLocal)
124      *
125      @param random the new global {@link Random} object for the GA.
126      @throws NullPointerException if the {@code random} object is {@code null}.
127      */
128     public static void setRandom(final Random random) {
129         requireNonNull(random, "Random must not be null.");
130         CONTEXT.set(() -> random);
131     }
132 
133     /**
134      * Set the new global {@link Random} object for the GA. The given
135      {@link Random} don't have be thread safe, because the given
136      {@link ThreadLocal} wrapper guarantees thread safety. Setting a
137      <i>thread-local</i> random object leads, in general, to a faster
138      * PRN generation, when using a non-blocking PRNG. This is the preferred
139      * way for changing the PRNG.
140      *
141      @param random the thread-local random engine to use.
142      @throws NullPointerException if the {@code random} object is {@code null}.
143      */
144     @SuppressWarnings("unchecked")
145     public static void setRandom(final ThreadLocal<? extends Random> random) {
146         requireNonNull(random, "Random must not be null.");
147         CONTEXT.set(random::get);
148     }
149 
150     /**
151      * Set the random object to it's default value. The <i>default</i> used PRNG
152      * is the {@link ThreadLocalRandom} PRNG.
153      */
154     public static void reset() {
155         CONTEXT.reset();
156     }
157 
158     /**
159      * Executes the consumer code using the given {@code random} engine.
160      *
161      <pre>{@code
162      * final MSeq<Integer> seq = ...
163      * using(new Random(123), r -> {
164      *     seq.shuffle();
165      * });
166      * }</pre>
167      *
168      * The example above shuffles the given integer {@code seq} <i>using</i> the
169      * given {@code Random(123)} engine.
170      *
171      @since 3.0
172      *
173      @param random the PRNG used within the consumer
174      @param consumer the consumer which is executed with the <i>scope</i> of
175      *        the given {@code random} engine.
176      @param <R> the type of the random engine
177      @throws NullPointerException if one of the arguments is {@code null}
178      */
179     public static <R extends Random> void using(
180         final R random,
181         final Consumer<? super R> consumer
182     ) {
183         CONTEXT.with(() -> random, r -> {
184             consumer.accept(random);
185             return null;
186         });
187     }
188 
189     /**
190      * Executes the consumer code using the given {@code random} engine.
191      *
192      <pre>{@code
193      * final MSeq<Integer> seq = ...
194      * using(new LCG64ShiftRandom.ThreadLocal(), r -> {
195      *     seq.shuffle();
196      * });
197      * }</pre>
198      *
199      * The example above shuffles the given integer {@code seq} <i>using</i> the
200      * given {@code LCG64ShiftRandom.ThreadLocal()} engine.
201      *
202      @since 3.0
203      *
204      @param random the PRNG used within the consumer
205      @param consumer the consumer which is executed with the <i>scope</i> of
206      *        the given {@code random} engine.
207      @param <R> the type of the random engine
208      @throws NullPointerException if one of the arguments is {@code null}
209      */
210     public static <R extends Random> void using(
211         final ThreadLocal<R> random,
212         final Consumer<? super R> consumer
213     ) {
214         CONTEXT.with(random::get, r -> {
215             consumer.accept(random.get());
216             return null;
217         });
218     }
219 
220     /**
221      * Opens a new {@code Scope} with the given random engine and executes the
222      * given function within it. The following example shows how to create a
223      * reproducible list of genotypes:
224      <pre>{@code
225      * final List<Genotype<DoubleGene>> genotypes =
226      *     with(new LCG64ShiftRandom(123), r ->
227      *         Genotype.of(DoubleChromosome.of(0, 10)).instances()
228      *            .limit(50)
229      *            .collect(toList())
230      *     );
231      * }</pre>
232      *
233      @since 3.0
234      *
235      @param <R> the type of the random engine
236      @param <T> the function return type
237      @param random the PRNG used for the opened scope
238      @param function the function to apply within the random scope
239      @return the object returned by the given function
240      @throws NullPointerException if one of the arguments is {@code null}
241      */
242     public static <R extends Random, T> T with(
243         final R random,
244         final Function<? super R, ? extends T> function
245     ) {
246         return CONTEXT.with(() -> random, s -> function.apply(random));
247     }
248 
249     /**
250      * Opens a new {@code Scope} with the given random engine and executes the
251      * given function within it. The following example shows how to create a
252      * reproducible list of genotypes:
253      <pre>{@code
254      * final List<Genotype<DoubleGene>> genotypes =
255      *     with(new LCG64ShiftRandom.ThreadLocal(), random ->
256      *         Genotype.of(DoubleChromosome.of(0, 10)).instances()
257      *            .limit(50)
258      *            .collect(toList())
259      *     );
260      * }</pre>
261      *
262      @since 3.0
263      *
264      @param <R> the type of the random engine
265      @param <T> the function return type
266      @param random the PRNG used for the opened scope
267      @param function the function to apply within the random scope
268      @return the object returned by the given function
269      @throws NullPointerException if one of the arguments is {@code null}.
270      */
271     public static <R extends Random, T> T with(
272         final ThreadLocal<R> random,
273         final Function<? super R, ? extends T> function
274     ) {
275         return CONTEXT.with(random::get, s -> function.apply(random.get()));
276     }
277 
278 }