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.engine;
021
022 import java.util.function.Function;
023 import java.util.function.Predicate;
024 import java.util.function.Supplier;
025 import java.util.stream.Stream;
026
027 import io.jenetics.Gene;
028 import io.jenetics.internal.engine.EvolutionStreamImpl;
029
030 /**
031 * The {@code EvolutionStream} class extends the Java {@link Stream} and adds a
032 * method for limiting the evolution by a given predicate.
033 *
034 * @implNote Collecting an <em>empty</em> {@code EvolutionStream} will return
035 * {@code null}.
036 * <pre>{@code
037 * final EvolutionResult<DoubleGene, Double> result = engine.stream()
038 * .limit(0)
039 * .collect(toBestEvolutionResult());
040 *
041 * assert result == null;
042 * }</pre>
043 *
044 * @see java.util.stream.Stream
045 * @see Engine
046 * @see EvolutionStreamable
047 *
048 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
049 * @since 3.0
050 * @version 5.1
051 */
052 public interface EvolutionStream<
053 G extends Gene<?, G>,
054 C extends Comparable<? super C>
055 >
056 extends Stream<EvolutionResult<G, C>>
057 {
058
059 /**
060 * Returns a stream consisting of the elements of this stream, truncated
061 * when the given {@code proceed} predicate returns {@code false}.
062 * <p>
063 * <i>General usage example:</i>
064 * <pre>{@code
065 * final Phenotype<DoubleGene, Double> result = engine.stream()
066 * // Truncate the evolution stream after 5 "steady" generations.
067 * .limit(bySteadyFitness(5))
068 * // The evolution will stop after maximal 100 generations.
069 * .limit(100)
070 * .collect(toBestPhenotype());
071 * }</pre>
072 *
073 * <b>Note:</b>
074 * The evolution result may be {@code null}, if your <em>truncation</em>
075 * predicate returns {@code false} for the initial population.
076 * <pre>{@code
077 * final EvolutionResult<DoubleGene, Double> result = engine.stream()
078 * .limit(er -> false)
079 * .collect(toBestEvolutionResult());
080 *
081 * assert result == null;
082 * }</pre>
083 *
084 * @see Limits
085 *
086 * @param proceed the predicate which determines whether the stream is
087 * truncated or not. <i>If the predicate returns {@code false}, the
088 * evolution stream is truncated.</i>
089 * @return the new stream
090 * @throws NullPointerException if the given predicate is {@code null}.
091 */
092 public EvolutionStream<G, C>
093 limit(final Predicate<? super EvolutionResult<G, C>> proceed);
094
095 /**
096 * Create a new {@code EvolutionStream} from the given {@code start}
097 * population and {@code evolution} function. The main purpose of this
098 * factory method is to simplify the creation of an {@code EvolutionStream}
099 * from an own evolution (GA) engine.
100 *
101 * @since 3.1
102 *
103 * @see #ofEvolution(Supplier, Evolution)
104 *
105 * @param <G> the gene type
106 * @param <C> the fitness type
107 * @param start the evolution start
108 * @param evolution the evolution function
109 * @return a new {@code EvolutionStream} with the given {@code start} and
110 * {@code evolution} function
111 * @throws java.lang.NullPointerException if one of the arguments is
112 * {@code null}
113 *
114 * @deprecated Will be removed, use {@link #ofEvolution(Supplier, Evolution)}
115 * instead
116 */
117 @Deprecated
118 public static <G extends Gene<?, G>, C extends Comparable<? super C>>
119 EvolutionStream<G, C> of(
120 final Supplier<EvolutionStart<G, C>> start,
121 final Function<? super EvolutionStart<G, C>, EvolutionResult<G, C>> evolution
122 ) {
123 return new EvolutionStreamImpl<>(start, evolution::apply);
124 }
125
126 /**
127 * Create a new {@code EvolutionStream} from the given {@code start}
128 * population and {@code evolution} function. The main purpose of this
129 * factory method is to simplify the creation of an {@code EvolutionStream}
130 * from an own evolution (GA) engine.
131 *
132 * <pre>{@code
133 * final Supplier<EvolutionStart<DoubleGene, Double>> start = ...
134 * final EvolutionStream<DoubleGene, Double> stream =
135 * EvolutionStream.of(start, new MySpecialEngine());
136 * }</pre>
137 *
138 * A more complete example for would look like as:
139 *
140 * <pre>{@code
141 * public final class SpecialEngine {
142 *
143 * // The fitness function.
144 * private static Double fitness(final Genotype<DoubleGene> gt) {
145 * return gt.getGene().getAllele();
146 * }
147 *
148 * // Create new evolution start object.
149 * private static EvolutionStart<DoubleGene, Double>
150 * start(final int populationSize, final long generation) {
151 * final Population<DoubleGene, Double> population =
152 * Genotype.of(DoubleChromosome.of(0, 1)).instances()
153 * .map(gt -> Phenotype.of(gt, generation, SpecialEngine::fitness))
154 * .limit(populationSize)
155 * .collect(Population.toPopulation());
156 *
157 * return EvolutionStart.of(population, generation);
158 * }
159 *
160 * // The special evolution function.
161 * private static EvolutionResult<DoubleGene, Double>
162 * evolve(final EvolutionStart<DoubleGene, Double> start) {
163 * // Your special evolution implementation comes here!
164 * return null;
165 * }
166 *
167 * public static void main(final String[] args) {
168 * final Genotype<DoubleGene> best = EvolutionStream
169 * .ofEvolution(() -> start(50, 0), SpecialEngine::evolve)
170 * .limit(Limits.bySteadyFitness(10))
171 * .limit(1000)
172 * .collect(EvolutionResult.toBestGenotype());
173 *
174 * System.out.println(String.format("Best Genotype: %s", best));
175 * }
176 * }
177 * }</pre>
178 *
179 *
180 * @since 5.1
181 *
182 * @see #ofAdjustableEvolution(Supplier, Function)
183 *
184 * @param <G> the gene type
185 * @param <C> the fitness type
186 * @param start the evolution start
187 * @param evolution the evolution function
188 * @return a new {@code EvolutionStream} with the given {@code start} and
189 * {@code evolution} function
190 * @throws java.lang.NullPointerException if one of the arguments is
191 * {@code null}
192 */
193 public static <G extends Gene<?, G>, C extends Comparable<? super C>>
194 EvolutionStream<G, C> ofEvolution(
195 final Supplier<EvolutionStart<G, C>> start,
196 final Evolution<G, C> evolution
197 ) {
198 return new EvolutionStreamImpl<>(start, evolution);
199 }
200
201 /**
202 * Create a new evolution stream with an <em>adjustable</em> evolution
203 * function.
204 *
205 * <pre>{@code
206 * public static void main(final String[] args) {
207 * final Problem<double[], DoubleGene, Double> problem = Problem.of(
208 * v -> Math.sin(v[0])*Math.cos(v[1]),
209 * Codecs.ofVector(DoubleRange.of(0, 2*Math.PI), 2)
210 * );
211 *
212 * // Engine builder template.
213 * final Engine.Builder<DoubleGene, Double> builder = Engine
214 * .builder(problem)
215 * .minimizing();
216 *
217 * // Evolution used for low fitness variance.
218 * final Evolution<DoubleGene, Double> lowVar = builder.copy()
219 * .alterers(new Mutator<>(0.5))
220 * .selector(new MonteCarloSelector<>())
221 * .build();
222 *
223 * // Evolution used for high fitness variance.
224 * final Evolution<DoubleGene, Double> highVar = builder.copy()
225 * .alterers(
226 * new Mutator<>(0.05),
227 * new MeanAlterer<>())
228 * .selector(new RouletteWheelSelector<>())
229 * .build();
230 *
231 * final EvolutionStream<DoubleGene, Double> stream =
232 * EvolutionStream.ofAdjustableEvolution(
233 * EvolutionStart::empty,
234 * er -> var(er) < 0.2 ? lowVar : highVar
235 * );
236 *
237 * final Genotype<DoubleGene> result = stream
238 * .limit(Limits.bySteadyFitness(50))
239 * .collect(EvolutionResult.toBestGenotype());
240 *
241 * System.out.println(result + ": " +
242 * problem.fitness().apply(problem.codec().decode(result)));
243 * }
244 *
245 * private static double var(final EvolutionStart<DoubleGene, Double> result) {
246 * return result != null
247 * ? result.getPopulation().stream()
248 * .map(Phenotype::getFitness)
249 * .collect(DoubleMoments.toDoubleMoments())
250 * .getVariance()
251 * : 0.0;
252 * }
253 * }</pre>
254 *
255 * @see #ofEvolution(Supplier, Evolution)
256 *
257 * @param start the evolution start object
258 * @param evolution the adaptable evolution function
259 * @param <G> the gene type
260 * @param <C> the fitness type
261 * @return a new {@code EvolutionStream} with the given {@code start} and
262 * {@code evolution} function
263 * @throws java.lang.NullPointerException if one of the arguments is
264 * {@code null}
265 */
266 public static <G extends Gene<?, G>, C extends Comparable<? super C>>
267 EvolutionStream<G, C> ofAdjustableEvolution(
268 final Supplier<EvolutionStart<G, C>> start,
269 final Function<
270 ? super EvolutionStart<G, C>,
271 ? extends Evolution<G, C>> evolution
272 ) {
273 return EvolutionStreamImpl.of(start, evolution);
274 }
275
276 }
|