001 /*
002 * Java Genetic Algorithm Library (jenetics-4.3.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 static java.util.Objects.requireNonNull;
023
024 import java.util.Spliterator;
025 import java.util.function.Function;
026 import java.util.function.Supplier;
027
028 import io.jenetics.Gene;
029 import io.jenetics.engine.EvolutionInit;
030 import io.jenetics.engine.EvolutionResult;
031 import io.jenetics.engine.EvolutionStart;
032 import io.jenetics.engine.EvolutionStream;
033 import io.jenetics.engine.EvolutionStreamable;
034 import io.jenetics.internal.engine.EvolutionStreamImpl;
035
036 import io.jenetics.ext.internal.GeneratorSpliterator;
037
038 /**
039 * The {@code AdaptiveEngine} allows you to dynamically create engines with
040 * different configurations, depending on the last {@link EvolutionResult} of
041 * the previous evolution stream. It is therefore possible to increase the
042 * mutation probability if the population is converging to fast. The sketch
043 * below shows how the {@code AdaptiveEngine} is working.
044 *
045 * <pre> {@code
046 * +----------+
047 * | ES[i] |
048 * +-------------------------------+------+ |
049 * | +---+
050 * (Start) | EvolutionResult[i-1] -> Engine[i] |-----------+-->
051 * -----+-->| ^ | Result |
052 * ^ +-----------|--------------------------+ |
053 * | | |
054 * +---------------+--------------<-----------------------+
055 * }</pre>
056 *
057 *
058 * <pre>{@code
059 * public static void main(final String[] args) {
060 * final Problem<double[], DoubleGene, Double> problem = Problem.of(
061 * v -> Math.sin(v[0])*Math.cos(v[1]),
062 * Codecs.ofVector(DoubleRange.of(0, 2*Math.PI), 2)
063 * );
064 *
065 * final Engine.Builder<DoubleGene, Double> builder = Engine
066 * .builder(problem)
067 * .minimizing();
068 *
069 * final Genotype<DoubleGene> result =
070 * AdaptiveEngine.<DoubleGene, Double>of(er -> engine(er, builder))
071 * .stream()
072 * .limit(Limits.bySteadyFitness(50))
073 * .collect(EvolutionResult.toBestGenotype());
074 *
075 * System.out.println(result + ": " +
076 * problem.fitness().apply(problem.codec().decode(result)));
077 * }
078 *
079 * private static EvolutionStreamable<DoubleGene, Double> engine(
080 * final EvolutionResult<DoubleGene, Double> result,
081 * final Engine.Builder<DoubleGene, Double> builder
082 * ) {
083 * return var(result) < 0.2
084 * ? builder
085 * .alterers(new Mutator<>(0.5))
086 * .build()
087 * .limit(5)
088 * : builder
089 * .alterers(
090 * new Mutator<>(0.05),
091 * new MeanAlterer<>())
092 * .selector(new RouletteWheelSelector<>())
093 * .build()
094 * .limit(15);
095 * }
096 *
097 * private static double var(final EvolutionResult<DoubleGene, Double> result) {
098 * return result != null
099 * ? result.getPopulation().stream()
100 * .map(Phenotype::getFitness)
101 * .collect(DoubleMoments.toDoubleMoments(Double::doubleValue))
102 * .getVariance()
103 * : 0.0;
104 * }
105 * }</pre>
106 *
107 * @see ConcatEngine
108 * @see CyclicEngine
109 *
110 * @param <G> the gene type
111 * @param <C> the fitness type
112 *
113 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
114 * @version 4.1
115 * @since 4.1
116 */
117 public final class AdaptiveEngine<
118 G extends Gene<?, G>,
119 C extends Comparable<? super C>
120 >
121 implements EvolutionStreamable<G, C>
122 {
123
124 private final Function<
125 ? super EvolutionResult<G, C>,
126 ? extends EvolutionStreamable<G, C>> _engine;
127
128 /**
129 * Return a new adaptive evolution engine, with the given engine generation
130 * function.
131 *
132 * @param engine the engine generating function used for adapting the engines.
133 * @throws NullPointerException if the given {@code engine} is {@code null}
134 */
135 public AdaptiveEngine(
136 final Function<
137 ? super EvolutionResult<G, C>,
138 ? extends EvolutionStreamable<G, C>> engine
139 ) {
140 _engine = requireNonNull(engine);
141 }
142
143 @Override
144 public EvolutionStream<G, C>
145 stream(final Supplier<EvolutionStart<G, C>> start) {
146 return new EvolutionStreamImpl<G, C>(
147 new GeneratorSpliterator<>(result -> generate(start, result)),
148 false
149 );
150 }
151
152 private Spliterator<EvolutionResult<G, C>>
153 generate(
154 final Supplier<EvolutionStart<G, C>> start,
155 final EvolutionResult<G, C> result
156 ) {
157 final EvolutionStart<G, C> es = result == null
158 ? start.get()
159 : result.toEvolutionStart();
160
161 return _engine.apply(result)
162 .stream(es)
163 .spliterator();
164 }
165
166 @Override
167 public EvolutionStream<G, C> stream(final EvolutionInit<G> init) {
168 return new EvolutionStreamImpl<G, C>(
169 new GeneratorSpliterator<>(result -> generate(init, result)),
170 false
171 );
172 }
173
174 private Spliterator<EvolutionResult<G, C>>
175 generate(
176 final EvolutionInit<G> init,
177 final EvolutionResult<G, C> result
178 ) {
179 return result == null
180 ? _engine.apply(null)
181 .stream(init)
182 .spliterator()
183 : _engine.apply(result)
184 .stream(result.toEvolutionStart())
185 .spliterator();
186 }
187
188 /**
189 * Return a new adaptive evolution engine, with the given engine generation
190 * function.
191 *
192 * @param engine the engine generating function used for adapting the engines.
193 * <b>Be aware, that the {@code EvolutionResult} for the first created
194 * {@code Engine} is {@code null}.</b>
195 * @param <G> the gene type
196 * @param <C> the fitness type
197 * @return a new adaptive evolution engine
198 * @throws NullPointerException if the given {@code engine} is {@code null}
199 */
200 public static <G extends Gene<?, G>, C extends Comparable<? super C>>
201 AdaptiveEngine<G, C> of(
202 final Function<
203 ? super EvolutionResult<G, C>,
204 ? extends EvolutionStreamable<G, C>> engine
205 ) {
206 return new AdaptiveEngine<>(engine);
207 }
208
209 }
|