001 /*
002 * Java Genetic Algorithm Library (jenetics-5.1.0).
003 * Copyright (c) 2007-2019 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.Alterer;
029 import io.jenetics.Gene;
030 import io.jenetics.engine.Engine;
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 import io.jenetics.util.DoubleRange;
038
039 import io.jenetics.ext.internal.GeneratorSpliterator;
040
041 /**
042 * The {@code AdaptiveEngine} allows you to dynamically create engines with
043 * different configurations, depending on the last {@link EvolutionResult} of
044 * the previous evolution stream. It is therefore possible to increase the
045 * mutation probability if the population is converging to fast. The sketch
046 * below shows how the {@code AdaptiveEngine} is working.
047 *
048 * <pre> {@code
049 * +----------+
050 * | ES[i] |
051 * +-------------------------------+------+ |
052 * | +---+
053 * (Start) | EvolutionResult[i-1] -> Engine[i] |-----------+-->
054 * -----+-->| ^ | Result |
055 * ^ +-----------|--------------------------+ |
056 * | | |
057 * +---------------+--------------<-----------------------+
058 * }</pre>
059 *
060 *
061 * <pre>{@code
062 * public static void main(final String[] args) {
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.Builder<DoubleGene, Double> builder = Engine
069 * .builder(problem)
070 * .minimizing();
071 *
072 * final Genotype<DoubleGene> result =
073 * AdaptiveEngine.<DoubleGene, Double>of(er -> engine(er, builder))
074 * .stream()
075 * .limit(Limits.bySteadyFitness(50))
076 * .collect(EvolutionResult.toBestGenotype());
077 *
078 * System.out.println(result + ": " +
079 * problem.fitness().apply(problem.codec().decode(result)));
080 * }
081 *
082 * private static EvolutionStreamable<DoubleGene, Double> engine(
083 * final EvolutionResult<DoubleGene, Double> result,
084 * final Engine.Builder<DoubleGene, Double> builder
085 * ) {
086 * return var(result) < 0.2
087 * ? builder
088 * .alterers(new Mutator<>(0.5))
089 * .build()
090 * .limit(5)
091 * : builder
092 * .alterers(
093 * new Mutator<>(0.05),
094 * new MeanAlterer<>())
095 * .selector(new RouletteWheelSelector<>())
096 * .build()
097 * .limit(15);
098 * }
099 *
100 * private static double var(final EvolutionResult<DoubleGene, Double> result) {
101 * return result != null
102 * ? result.getPopulation().stream()
103 * .map(Phenotype::getFitness)
104 * .collect(DoubleMoments.toDoubleMoments(Double::doubleValue))
105 * .getVariance()
106 * : 0.0;
107 * }
108 * }</pre>
109 *
110 * @see ConcatEngine
111 * @see CyclicEngine
112 *
113 * @param <G> the gene type
114 * @param <C> the fitness type
115 *
116 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
117 * @version 5.1
118 * @since 4.1
119 *
120 * @deprecated Use {@link io.jenetics.engine.EvolutionStream#ofAdjustableEvolution(Supplier, Function)}
121 * instead.
122 */
123 @Deprecated
124 public final class AdaptiveEngine<
125 G extends Gene<?, G>,
126 C extends Comparable<? super C>
127 >
128 implements EvolutionStreamable<G, C>
129 {
130
131 private final Function<
132 ? super EvolutionResult<G, C>,
133 ? extends EvolutionStreamable<G, C>> _engine;
134
135 /**
136 * Return a new adaptive evolution engine, with the given engine generation
137 * function.
138 *
139 * @param engine the engine generating function used for adapting the engines.
140 * @throws NullPointerException if the given {@code engine} is {@code null}
141 */
142 public AdaptiveEngine(
143 final Function<
144 ? super EvolutionResult<G, C>,
145 ? extends EvolutionStreamable<G, C>> engine
146 ) {
147 _engine = requireNonNull(engine);
148 }
149
150 @Override
151 public EvolutionStream<G, C>
152 stream(final Supplier<EvolutionStart<G, C>> start) {
153 return new EvolutionStreamImpl<G, C>(
154 new GeneratorSpliterator<>(result -> generate(start, result)),
155 false
156 );
157 }
158
159 private Spliterator<EvolutionResult<G, C>>
160 generate(
161 final Supplier<EvolutionStart<G, C>> start,
162 final EvolutionResult<G, C> result
163 ) {
164 final EvolutionStart<G, C> es = result == null
165 ? start.get()
166 : result.toEvolutionStart();
167
168 return _engine.apply(result)
169 .stream(es)
170 .spliterator();
171 }
172
173 @Override
174 public EvolutionStream<G, C> stream(final EvolutionInit<G> init) {
175 return new EvolutionStreamImpl<G, C>(
176 new GeneratorSpliterator<>(result -> generate(init, result)),
177 false
178 );
179 }
180
181 private Spliterator<EvolutionResult<G, C>>
182 generate(
183 final EvolutionInit<G> init,
184 final EvolutionResult<G, C> result
185 ) {
186 return result == null
187 ? _engine.apply(null)
188 .stream(init)
189 .spliterator()
190 : _engine.apply(result)
191 .stream(result.toEvolutionStart())
192 .spliterator();
193 }
194
195 /**
196 * Return a new adaptive evolution engine, which tries to keep the
197 * population's fitness variance within the given {@code variance} range. If
198 * the population fitness variance is below the desired value, the
199 * {@code enlarge} alterer is used for introduce more diversity in the
200 * population fitness. And if the fitness variance is above the desired
201 * variance, the {@code narrow} alterer is used for reducing the population
202 * diversity.
203 *
204 * @since 5.0
205 *
206 * @param variance the desired fitness variance range for the population's
207 * fitness
208 * @param builder the engine builder template used for creating new new
209 * evolution engines with the different alterers
210 * @param narrow the narrowing alterer
211 * @param enlarge the alterer used for introducing a more divers population
212 * @param <G> the gene type
213 * @param <N> the fitness value type
214 * @return a new adaptive evolution engine which maintains the given fitness
215 * variance
216 * @throws NullPointerException if one of the arguments is {@code null}
217 */
218 public static
219 <G extends Gene<?, G>, N extends Number & Comparable<? super N>>
220 AdaptiveEngine<G, N> byFitnessVariance(
221 final DoubleRange variance,
222 final Engine.Builder<G, N> builder,
223 final Alterer<G, N> narrow,
224 final Alterer<G, N> enlarge
225 ) {
226 return new AdaptiveEngine<>(new FitnessVarianceAdaptiveEngine<>(
227 variance, builder, narrow, enlarge
228 ));
229 }
230
231 }
|