001 /*
002 * Java Genetic Algorithm Library (jenetics-3.7.0).
003 * Copyright (c) 2007-2016 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 }
|