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