001/*
002 * Java Genetic Algorithm Library (jenetics-7.2.0).
003 * Copyright (c) 2007-2023 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 */
020package io.jenetics.engine;
021
022import java.util.function.Function;
023import java.util.function.Predicate;
024import java.util.function.Supplier;
025import java.util.stream.Stream;
026
027import io.jenetics.Gene;
028import 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 6.0
051 */
052public 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        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         * <pre>{@code
102         * final Supplier<EvolutionStart<DoubleGene, Double>> start = ...
103         * final EvolutionStream<DoubleGene, Double> stream =
104         *     EvolutionStream.of(start, new MySpecialEngine());
105         * }</pre>
106         *
107         * A more complete example for would look like as:
108         *
109         * <pre>{@code
110         * public final class SpecialEngine {
111         *
112         *     // The fitness function.
113         *     private static Double fitness(final Genotype<DoubleGene> gt) {
114         *         return gt.gene().allele();
115         *     }
116         *
117         *     // Create new evolution start object.
118         *     private static EvolutionStart<DoubleGene, Double>
119         *     start(final int populationSize, final long generation) {
120         *         final Population<DoubleGene, Double> population =
121         *             Genotype.of(DoubleChromosome.of(0, 1)).instances()
122         *                 .map(gt -> Phenotype.of(gt, generation, SpecialEngine::fitness))
123         *                 .limit(populationSize)
124         *                 .collect(Population.toPopulation());
125         *
126         *         return EvolutionStart.of(population, generation);
127         *     }
128         *
129         *     // The special evolution function.
130         *     private static EvolutionResult<DoubleGene, Double>
131         *     evolve(final EvolutionStart<DoubleGene, Double> start) {
132         *         // Your special evolution implementation comes here!
133         *         return null;
134         *     }
135         *
136         *     public static void main(final String[] args) {
137         *         final Genotype<DoubleGene> best = EvolutionStream
138         *             .ofEvolution(() -> start(50, 0), SpecialEngine::evolve)
139         *             .limit(Limits.bySteadyFitness(10))
140         *             .limit(1000)
141         *             .collect(EvolutionResult.toBestGenotype());
142         *
143         *         System.out.println(String.format("Best Genotype: %s", best));
144         *     }
145         * }
146         * }</pre>
147         *
148         *
149         * @since 5.1
150         *
151         * @see #ofAdjustableEvolution(Supplier, Function)
152         *
153         * @param <G> the gene type
154         * @param <C> the fitness type
155         * @param start the evolution start
156         * @param evolution the evolution function
157         * @return a new {@code EvolutionStream} with the given {@code start} and
158         *         {@code evolution} function
159         * @throws java.lang.NullPointerException if one of the arguments is
160         *         {@code null}
161         */
162        static <G extends Gene<?, G>, C extends Comparable<? super C>>
163        EvolutionStream<G, C> ofEvolution(
164                final Supplier<EvolutionStart<G, C>> start,
165                final Evolution<G, C> evolution
166        ) {
167                return new EvolutionStreamImpl<>(start, evolution);
168        }
169
170        /**
171         * Create a new evolution stream with an <em>adjustable</em> evolution
172         * function.
173         *
174         * <pre>{@code
175         * public static void main(final String[] args) {
176         *     final Problem<double[], DoubleGene, Double> problem = Problem.of(
177         *         v -> Math.sin(v[0])*Math.cos(v[1]),
178         *         Codecs.ofVector(DoubleRange.of(0, 2*Math.PI), 2)
179         *     );
180         *
181         *     // Engine builder template.
182         *     final Engine.Builder<DoubleGene, Double> builder = Engine
183         *         .builder(problem)
184         *         .minimizing();
185         *
186         *     // Evolution used for low fitness variance.
187         *     final Evolution<DoubleGene, Double> lowVar = builder.copy()
188         *         .alterers(new Mutator<>(0.5))
189         *         .selector(new MonteCarloSelector<>())
190         *         .build();
191         *
192         *     // Evolution used for high fitness variance.
193         *     final Evolution<DoubleGene, Double> highVar = builder.copy()
194         *         .alterers(
195         *             new Mutator<>(0.05),
196         *             new MeanAlterer<>())
197         *         .selector(new RouletteWheelSelector<>())
198         *         .build();
199         *
200         *     final EvolutionStream<DoubleGene, Double> stream =
201         *         EvolutionStream.ofAdjustableEvolution(
202         *             EvolutionStart::empty,
203         *             er -> var(er) < 0.2 ? lowVar : highVar
204         *         );
205         *
206         *     final Genotype<DoubleGene> result = stream
207         *         .limit(Limits.bySteadyFitness(50))
208         *         .collect(EvolutionResult.toBestGenotype());
209         *
210         *     System.out.println(result + ": " +
211         *         problem.fitness().apply(problem.codec().decode(result)));
212         * }
213         *
214         * private static double var(final EvolutionStart<DoubleGene, Double> result) {
215         *     return result != null
216         *         ? result.getPopulation().stream()
217         *             .map(Phenotype::fitness)
218         *             .collect(DoubleMoments.toDoubleMoments())
219         *             .variance()
220         *         : 0.0;
221         * }
222         * }</pre>
223         *
224         * @see #ofEvolution(Supplier, Evolution)
225         *
226         * @param start the evolution start object
227         * @param evolution the adaptable evolution function
228         * @param <G> the gene type
229         * @param <C> the fitness type
230         * @return a new {@code EvolutionStream} with the given {@code start} and
231         *         {@code evolution} function
232         * @throws java.lang.NullPointerException if one of the arguments is
233         *         {@code null}
234         */
235        static <G extends Gene<?, G>, C extends Comparable<? super C>>
236        EvolutionStream<G, C> ofAdjustableEvolution(
237                final Supplier<EvolutionStart<G, C>> start,
238                final Function<
239                        ? super EvolutionStart<G, C>,
240                        ? extends Evolution<G, C>> evolution
241        ) {
242                return EvolutionStreamImpl.of(start, evolution);
243        }
244
245}