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