RandomRegistry.java
001 /*
002  * Java Genetic Algorithm Library (jenetics-5.2.0).
003  * Copyright (c) 2007-2020 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.random(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.random(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 random() {
107         return CONTEXT.get().get();
108     }
109 
110     /**
111      * Return the global {@link Random} object.
112      *
113      @return the global {@link Random} object.
114      @deprecated Use {@link #random()} instead
115      */
116     @Deprecated
117     public static Random getRandom() {
118         return CONTEXT.get().get();
119     }
120 
121     /**
122      * Set the new global {@link Random} object for the GA. The given
123      {@link Random} <b>must</b> be thread safe, which is the case for the
124      * default Java {@code Random} implementation.
125      <p>
126      * Setting a <i>thread-local</i> random object leads, in general, to a faster
127      * PRN generation, because the given {@code Random} engine don't have to be
128      * thread-safe.
129      *
130      @see #random(ThreadLocal)
131      *
132      @param random the new global {@link Random} object for the GA.
133      @throws NullPointerException if the {@code random} object is {@code null}.
134      */
135     public static void random(final Random random) {
136         requireNonNull(random, "Random must not be null.");
137         CONTEXT.set(() -> random);
138     }
139 
140     /**
141      * Set the new global {@link Random} object for the GA. The given
142      {@link Random} <b>must</b> be thread safe, which is the case for the
143      * default Java {@code Random} implementation.
144      <p>
145      * Setting a <i>thread-local</i> random object leads, in general, to a faster
146      * PRN generation, because the given {@code Random} engine don't have to be
147      * thread-safe.
148      *
149      @see #random(ThreadLocal)
150      *
151      @param random the new global {@link Random} object for the GA.
152      @throws NullPointerException if the {@code random} object is {@code null}.
153      @deprecated Use {@link #random(Random)} instead
154      */
155     @Deprecated
156     public static void setRandom(final Random random) {
157         requireNonNull(random, "Random must not be null.");
158         CONTEXT.set(() -> random);
159     }
160 
161     /**
162      * Set the new global {@link Random} object for the GA. The given
163      {@link Random} don't have be thread safe, because the given
164      {@link ThreadLocal} wrapper guarantees thread safety. Setting a
165      <i>thread-local</i> random object leads, in general, to a faster
166      * PRN generation, when using a non-blocking PRNG. This is the preferred
167      * way for changing the PRNG.
168      *
169      @param random the thread-local random engine to use.
170      @throws NullPointerException if the {@code random} object is {@code null}.
171      */
172     @SuppressWarnings("unchecked")
173     public static void random(final ThreadLocal<? extends Random> random) {
174         requireNonNull(random, "Random must not be null.");
175         CONTEXT.set(random::get);
176     }
177 
178     /**
179      * Set the new global {@link Random} object for the GA. The given
180      {@link Random} don't have be thread safe, because the given
181      {@link ThreadLocal} wrapper guarantees thread safety. Setting a
182      <i>thread-local</i> random object leads, in general, to a faster
183      * PRN generation, when using a non-blocking PRNG. This is the preferred
184      * way for changing the PRNG.
185      *
186      @param random the thread-local random engine to use.
187      @throws NullPointerException if the {@code random} object is {@code null}.
188      @deprecated Use {@link #random(ThreadLocal)} instead
189      */
190     @Deprecated
191     @SuppressWarnings("unchecked")
192     public static void setRandom(final ThreadLocal<? extends Random> random) {
193         requireNonNull(random, "Random must not be null.");
194         CONTEXT.set(random::get);
195     }
196 
197     /**
198      * Set the random object to it's default value. The <i>default</i> used PRNG
199      * is the {@link ThreadLocalRandom} PRNG.
200      */
201     public static void reset() {
202         CONTEXT.reset();
203     }
204 
205     /**
206      * Executes the consumer code using the given {@code random} engine.
207      *
208      <pre>{@code
209      * final MSeq<Integer> seq = ...
210      * using(new Random(123), r -> {
211      *     seq.shuffle();
212      * });
213      * }</pre>
214      *
215      * The example above shuffles the given integer {@code seq} <i>using</i> the
216      * given {@code Random(123)} engine.
217      *
218      @since 3.0
219      *
220      @param random the PRNG used within the consumer
221      @param consumer the consumer which is executed with the <i>scope</i> of
222      *        the given {@code random} engine.
223      @param <R> the type of the random engine
224      @throws NullPointerException if one of the arguments is {@code null}
225      */
226     public static <R extends Random> void using(
227         final R random,
228         final Consumer<? super R> consumer
229     ) {
230         CONTEXT.with(() -> random, r -> {
231             consumer.accept(random);
232             return null;
233         });
234     }
235 
236     /**
237      * Executes the consumer code using the given {@code random} engine.
238      *
239      <pre>{@code
240      * final MSeq<Integer> seq = ...
241      * using(new LCG64ShiftRandom.ThreadLocal(), r -> {
242      *     seq.shuffle();
243      * });
244      * }</pre>
245      *
246      * The example above shuffles the given integer {@code seq} <i>using</i> the
247      * given {@code LCG64ShiftRandom.ThreadLocal()} engine.
248      *
249      @since 3.0
250      *
251      @param random the PRNG used within the consumer
252      @param consumer the consumer which is executed with the <i>scope</i> of
253      *        the given {@code random} engine.
254      @param <R> the type of the random engine
255      @throws NullPointerException if one of the arguments is {@code null}
256      */
257     public static <R extends Random> void using(
258         final ThreadLocal<R> random,
259         final Consumer<? super R> consumer
260     ) {
261         CONTEXT.with(random::get, r -> {
262             consumer.accept(random.get());
263             return null;
264         });
265     }
266 
267     /**
268      * Opens a new {@code Scope} with the given random engine and executes the
269      * given function within it. The following example shows how to create a
270      * reproducible list of genotypes:
271      <pre>{@code
272      * final List<Genotype<DoubleGene>> genotypes =
273      *     with(new LCG64ShiftRandom(123), r ->
274      *         Genotype.of(DoubleChromosome.of(0, 10)).instances()
275      *            .limit(50)
276      *            .collect(toList())
277      *     );
278      * }</pre>
279      *
280      @since 3.0
281      *
282      @param <R> the type of the random engine
283      @param <T> the function return type
284      @param random the PRNG used for the opened scope
285      @param function the function to apply within the random scope
286      @return the object returned by the given function
287      @throws NullPointerException if one of the arguments is {@code null}
288      */
289     public static <R extends Random, T> T with(
290         final R random,
291         final Function<? super R, ? extends T> function
292     ) {
293         return CONTEXT.with(() -> random, s -> function.apply(random));
294     }
295 
296     /**
297      * Opens a new {@code Scope} with the given random engine and executes the
298      * given function within it. The following example shows how to create a
299      * reproducible list of genotypes:
300      <pre>{@code
301      * final List<Genotype<DoubleGene>> genotypes =
302      *     with(new LCG64ShiftRandom.ThreadLocal(), random ->
303      *         Genotype.of(DoubleChromosome.of(0, 10)).instances()
304      *            .limit(50)
305      *            .collect(toList())
306      *     );
307      * }</pre>
308      *
309      @since 3.0
310      *
311      @param <R> the type of the random engine
312      @param <T> the function return type
313      @param random the PRNG used for the opened scope
314      @param function the function to apply within the random scope
315      @return the object returned by the given function
316      @throws NullPointerException if one of the arguments is {@code null}.
317      */
318     public static <R extends Random, T> T with(
319         final ThreadLocal<R> random,
320         final Function<? super R, ? extends T> function
321     ) {
322         return CONTEXT.with(random::get, s -> function.apply(random.get()));
323     }
324 
325 }