001 /*
002 * Java Genetic Algorithm Library (jenetics-4.2.0).
003 * Copyright (c) 2007-2018 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.ext.engine;
021
022 import java.util.Arrays;
023 import java.util.List;
024 import java.util.Spliterator;
025 import java.util.concurrent.atomic.AtomicBoolean;
026 import java.util.concurrent.atomic.AtomicReference;
027 import java.util.function.Supplier;
028 import java.util.stream.Collectors;
029
030 import io.jenetics.Gene;
031 import io.jenetics.engine.EvolutionInit;
032 import io.jenetics.engine.EvolutionResult;
033 import io.jenetics.engine.EvolutionStart;
034 import io.jenetics.engine.EvolutionStream;
035 import io.jenetics.engine.EvolutionStreamable;
036 import io.jenetics.internal.engine.EvolutionStreamImpl;
037
038 import io.jenetics.ext.internal.CyclicSpliterator;
039
040 /**
041 * The {@code CyclicEngine} lets you concatenate two (or more) evolution
042 * {@link io.jenetics.engine.Engine}, with different configurations, and let it
043 * use as <em>one</em> engine {@link EvolutionStreamable}. If the last evolution
044 * stream terminates, it's <em>final</em> result is fed back to first engine.
045 *
046 * <pre> {@code
047 * +----------+ +----------+
048 * | ES | | ES |
049 * +------------+ | +------------+ |
050 * (Start) | |-----+ Start | |-----+
051 * ---+---->| Engine 1 |------------>| Engine 2 | --------+
052 * ^ | | Result | | |
053 * | +------------+ +------------+ |
054 * | |
055 * +------------------------------<------------------------+
056 * Result
057 * }</pre>
058 *
059 * The {@code CyclicEngine} allows to do an broad search-fine search-cycle
060 * as long as you want.
061 *
062 * <pre>{@code
063 * final Problem<double[], DoubleGene, Double> problem = Problem.of(
064 * v -> Math.sin(v[0])*Math.cos(v[1]),
065 * Codecs.ofVector(DoubleRange.of(0, 2*Math.PI), 2)
066 * );
067 *
068 * final Engine<DoubleGene, Double> engine1 = Engine.builder(problem)
069 * .minimizing()
070 * .alterers(new Mutator<>(0.2))
071 * .selector(new MonteCarloSelector<>())
072 * .build();
073 *
074 * final Engine<DoubleGene, Double> engine2 = Engine.builder(problem)
075 * .minimizing()
076 * .alterers(
077 * new Mutator<>(0.1),
078 * new MeanAlterer<>())
079 * .selector(new RouletteWheelSelector<>())
080 * .build();
081 *
082 * final Genotype<DoubleGene> result =
083 * CyclicEngine.of(
084 * engine1.limit(50),
085 * engine2.limit(() -> Limits.bySteadyFitness(30)))
086 * .stream()
087 * .limit(Limits.bySteadyFitness(1000))
088 * .collect(EvolutionResult.toBestGenotype());
089 *
090 * System.out.println(result + ": " +
091 * problem.fitness().apply(problem.codec().decode(result)));
092 * }</pre>
093 *
094 * When using a {@code CyclicEnginePool}, you have to limit the final evolution
095 * stream, additionally to the defined limits on the used partial engines.
096 *
097 * @see AdaptiveEngine
098 * @see ConcatEngine
099 *
100 * @param <G> the gene type
101 * @param <C> the fitness type
102 *
103 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
104 * @version 4.1
105 * @since 4.1
106 */
107 public final class CyclicEngine<
108 G extends Gene<?, G>,
109 C extends Comparable<? super C>
110 >
111 extends EnginePool<G, C>
112 {
113
114 /**
115 * Create a new cycling evolution engine with the given list of
116 * {@code engines}.
117 *
118 * @param engines the evolution engines which are part of the cycling engine
119 * @throws NullPointerException if the {@code engines} or one of it's
120 * elements is {@code null}
121 */
122 public CyclicEngine(
123 final List<? extends EvolutionStreamable<G, C>> engines
124 ) {
125 super(engines);
126 }
127
128 @Override
129 public EvolutionStream<G, C>
130 stream(final Supplier<EvolutionStart<G, C>> start) {
131 final AtomicReference<EvolutionStart<G, C>> other =
132 new AtomicReference<>(null);
133
134 return new EvolutionStreamImpl<G, C>(
135 new CyclicSpliterator<>(
136 _engines.stream()
137 .map(engine -> toSpliterator(engine, start, other))
138 .collect(Collectors.toList())
139 ),
140 false
141 );
142 }
143
144 private Supplier<Spliterator<EvolutionResult<G, C>>> toSpliterator(
145 final EvolutionStreamable<G, C> engine,
146 final Supplier<EvolutionStart<G, C>> start,
147 final AtomicReference<EvolutionStart<G, C>> other
148 ) {
149 return () -> engine.stream(() -> start(start, other))
150 .peek(result -> other.set(result.toEvolutionStart()))
151 .spliterator();
152 }
153
154 private EvolutionStart<G, C> start(
155 final Supplier<EvolutionStart<G, C>> first,
156 final AtomicReference<EvolutionStart<G, C>> other
157 ) {
158 return other.get() != null ? other.get() : first.get();
159 }
160
161 @Override
162 public EvolutionStream<G, C> stream(final EvolutionInit<G> init) {
163 final AtomicBoolean first = new AtomicBoolean(true);
164 final AtomicReference<EvolutionStart<G, C>> other =
165 new AtomicReference<>(null);
166
167 return new EvolutionStreamImpl<G, C>(
168 new CyclicSpliterator<>(
169 _engines.stream()
170 .map(engine -> toSpliterator(engine, init, other, first))
171 .collect(Collectors.toList())
172 ),
173 false
174 );
175 }
176
177 private Supplier<Spliterator<EvolutionResult<G, C>>> toSpliterator(
178 final EvolutionStreamable<G, C> engine,
179 final EvolutionInit<G> init,
180 final AtomicReference<EvolutionStart<G, C>> other,
181 final AtomicBoolean first
182 ) {
183 return () -> {
184 if (first.get()) {
185 first.set(false);
186 return engine.stream(init)
187 .peek(result -> other.set(result.toEvolutionStart()))
188 .spliterator();
189 } else {
190 return engine.stream(other::get)
191 .peek(result -> other.set(result.toEvolutionStart()))
192 .spliterator();
193 }
194 };
195
196 }
197
198 /**
199 * Create a new cycling evolution engine with the given array of
200 * {@code engines}.
201 *
202 * @param engines the evolution engines which are part of the cycling engine
203 * @param <G> the gene type
204 * @param <C> the fitness type
205 * @return a new concatenating evolution engine
206 * @throws NullPointerException if the {@code engines} or one of it's
207 * elements is {@code null}
208 */
209 @SafeVarargs
210 public static <G extends Gene<?, G>, C extends Comparable<? super C>>
211 CyclicEngine<G, C> of(final EvolutionStreamable<G, C>... engines) {
212 return new CyclicEngine<>(Arrays.asList(engines));
213 }
214
215 }
|