AdaptiveEngine.java
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     extends Gene<?, G>,
126     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 }