001/*
002 * Java Genetic Algorithm Library (jenetics-7.1.0).
003 * Copyright (c) 2007-2022 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 static java.util.Objects.requireNonNull;
023
024import java.util.function.Predicate;
025import java.util.function.Supplier;
026
027import io.jenetics.Gene;
028import io.jenetics.Genotype;
029import io.jenetics.Phenotype;
030import io.jenetics.util.ISeq;
031
032/**
033 * This interface defines the capability of creating {@link EvolutionStream}s
034 * from a given {@link EvolutionStart} object. It also decouples the engine's
035 * capability from the capability to create evolution streams. The purpose of
036 * this interface is similar to the {@link Iterable} interface.
037 *
038 * @see EvolutionStream
039 *
040 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
041 * @version 4.1
042 * @since 4.1
043 */
044public interface EvolutionStreamable<
045        G extends Gene<?, G>,
046        C extends Comparable<? super C>
047> {
048
049        /**
050         * Create a new, possibly <em>infinite</em>, evolution stream with the given
051         * evolution start. If an empty {@code Population} is given, the engine's
052         * genotype factory is used for creating the population. The given
053         * population might be the result of another engine and this method allows
054         * to start the evolution with the outcome of a different engine.
055         * The fitness function is replaced by the one defined for this engine.
056         *
057         * @param start the data the evolution stream starts with
058         * @return a new <b>infinite</b> evolution stream
059         * @throws java.lang.NullPointerException if the given evolution
060         *         {@code start} is {@code null}.
061         */
062        EvolutionStream<G, C>
063        stream(final Supplier<EvolutionStart<G, C>> start);
064
065        /**
066         * Create a new, possibly <em>infinite</em>, evolution stream with the given
067         * initial value. If an empty {@code Population} is given, the engines genotype
068         * factory is used for creating the population. The given population might
069         * be the result of another engine and this method allows to start the
070         * evolution with the outcome of a different engine. The fitness function
071         * is replaced by the one defined for this engine.
072         *
073         * @param init the data the evolution stream is initialized with
074         * @return a new <b>infinite</b> evolution stream
075         * @throws java.lang.NullPointerException if the given evolution
076         *         {@code start} is {@code null}.
077         */
078        EvolutionStream<G, C> stream(final EvolutionInit<G> init);
079
080
081        /* *************************************************************************
082         * Default interface methods.
083         * ************************************************************************/
084
085        /**
086         * Create a new, possibly <em>infinite</em>, evolution stream with a newly
087         * created population. This method is a shortcut for
088         * <pre>{@code
089         * final EvolutionStream<G, C> stream = streamable
090         *     .stream(() -> EvolutionStart.of(ISeq.empty(), 1));
091         * }</pre>
092         *
093         * @return a new evolution stream.
094         */
095        default EvolutionStream<G, C> stream() {
096                return stream((Supplier<EvolutionStart<G, C>>)EvolutionStart::empty);
097        }
098
099        /**
100         * Create a new, possibly <em>infinite</em>, evolution stream with the given
101         * evolution start. If an empty {@code Population} is given, the engine's genotype
102         * factory is used for creating the population. The given population might
103         * be the result of another engine and this method allows to start the
104         * evolution with the outcome of a different engine. The fitness function
105         * is replaced by the one defined for this engine.
106         *
107         * @param start the data the evolution stream starts with
108         * @return a new <b>infinite</b> evolution iterator
109         * @throws java.lang.NullPointerException if the given evolution
110         *         {@code start} is {@code null}.
111         */
112        default EvolutionStream<G, C>
113        stream(final EvolutionStart<G, C> start) {
114                return stream(() -> start);
115        }
116
117        /**
118         * Create a new {@code EvolutionStream} starting with a previously evolved
119         * {@link EvolutionResult}. The stream is initialized with the population
120         * of the given {@code result} and its total generation
121         * {@link EvolutionResult#totalGenerations()}.
122         *
123         * <pre>{@code
124         * private static final Problem<Double, DoubleGene, Double>
125         * PROBLEM = Problem.of(
126         *     x -> cos(0.5 + sin(x))*cos(x),
127         *     Codecs.ofScalar(DoubleRange.of(0.0, 2.0*PI))
128         * );
129         *
130         * private static final Engine<DoubleGene, Double>
131         * ENGINE = Engine.builder(PROBLEM)
132         *     .optimize(Optimize.MINIMUM)
133         *     .offspringSelector(new RouletteWheelSelector<>())
134         *     .build();
135         *
136         * public static void main(final String[] args) throws IOException {
137         *     // Result of the first evolution run.
138         *     final EvolutionResult<DoubleGene, Double> rescue = ENGINE.stream()
139         *         .limit(Limits.bySteadyFitness(10))
140         *         .collect(EvolutionResult.toBestEvolutionResult());
141         *
142         *     // Save the result of the first run into a file.
143         *     final Path path = Paths.get("result.bin");
144         *     IO.object.write(rescue, path);
145         *
146         *     // Load the previous result and continue evolution.
147         *     \@SuppressWarnings("unchecked")
148         *     final EvolutionResult<DoubleGene, Double> result = ENGINE
149         *         .stream((EvolutionResult<DoubleGene, Double>)IO.object.read(path))
150         *         .limit(Limits.bySteadyFitness(20))
151         *         .collect(EvolutionResult.toBestEvolutionResult());
152         *
153         *     System.out.println(result.bestPhenotype());
154         * }
155         * }</pre>
156         *
157         * The example above shows how to save an {@link EvolutionResult} from a
158         * first run, save it to disk and continue the evolution.
159         *
160         * @param result the previously evolved {@code EvolutionResult}
161         * @return a new evolution stream, which continues a previous one
162         * @throws NullPointerException if the given evolution {@code result} is
163         *         {@code null}
164         */
165        default EvolutionStream<G, C>
166        stream(final EvolutionResult<G, C> result) {
167                return stream(EvolutionStart.of(
168                        result.population(),
169                        result.generation()
170                ));
171        }
172
173        /**
174         * Create a new, possibly <em>infinite</em>, evolution stream with the given
175         * initial population. If an empty {@code Population} is given, the engine's
176         * genotype factory is used for creating the population. The given population
177         * might be the result of a other engine and this method allows to start the
178         * evolution with the outcome of a different engine. The fitness function
179         * is replaced by the one defined for this engine.
180         *
181         * @param population the initial individuals used for the evolution stream.
182         *        Missing individuals are created and individuals not needed are
183         *        skipped.
184         * @param generation the generation the stream starts from; must be greater
185         *        than zero.
186         * @return a new evolution stream.
187         * @throws java.lang.NullPointerException if the given {@code population} is
188         *         {@code null}.
189         * @throws IllegalArgumentException if the given {@code generation} is
190         *         smaller then one
191         */
192        default EvolutionStream<G, C> stream(
193                final ISeq<Phenotype<G, C>> population,
194                final long generation
195        ) {
196                return stream(EvolutionStart.of(population, generation));
197        }
198
199        /**
200         * Create a new, possibly <em>infinite</em>, evolution stream with the given
201         * initial population. If an empty {@code Population} is given, the engine's
202         * genotype factory is used for creating the population. The given population
203         * might be the result of a other engine and this method allows to start the
204         * evolution with the outcome of a different engine. The fitness function
205         * is replaced by the one defined for this engine.
206         *
207         * @param population the initial individuals used for the evolution stream.
208         *        Missing individuals are created and individuals not needed are
209         *        skipped.
210         * @return a new evolution stream.
211         * @throws java.lang.NullPointerException if the given {@code population} is
212         *         {@code null}.
213         */
214        default EvolutionStream<G, C> stream(final ISeq<Phenotype<G, C>> population) {
215                return stream(EvolutionStart.of(population, 1));
216        }
217
218        /**
219         * Create a new, possibly <em>infinite</em>, evolution stream with the given
220         * initial individuals. If an empty {@code Iterable} is given, the engine's
221         * genotype factory is used for creating the population.
222         *
223         * @param genotypes the initial individuals used for the evolution stream.
224         *        Missing individuals are created and individuals not needed are
225         *        skipped.
226         * @param generation the generation the stream starts from; must be greater
227         *        than zero.
228         * @return a new evolution stream.
229         * @throws java.lang.NullPointerException if the given {@code genotypes} is
230         *         {@code null}.
231         * @throws IllegalArgumentException if the given {@code generation} is
232         *         smaller then one
233         */
234        default EvolutionStream<G, C> stream(
235                final Iterable<Genotype<G>> genotypes,
236                final long generation
237        ) {
238                return stream(EvolutionInit.of(ISeq.of(genotypes), generation));
239        }
240
241        /**
242         * Create a new, possibly <em>infinite</em>, evolution stream with the given
243         * initial individuals. If an empty {@code Iterable} is given, the engine's
244         * genotype factory is used for creating the population.
245         *
246         * @param genotypes the initial individuals used for the evolution stream.
247         *        Missing individuals are created and individuals not needed are
248         *        skipped.
249         * @return a new evolution stream.
250         * @throws java.lang.NullPointerException if the given {@code genotypes} is
251         *         {@code null}.
252         */
253        default EvolutionStream<G, C>
254        stream(final Iterable<Genotype<G>> genotypes) {
255                return stream(genotypes, 1);
256        }
257
258        /**
259         * Return a new {@code EvolutionStreamable} instance where all created
260         * {@code EvolutionStream}s are limited by the given predicate. Since some
261         * predicates has to maintain internal state, a predicate {@code Supplier}
262         * must be given instead a plain limiting predicate.
263         *
264         * @param proceed the limiting predicate supplier.
265         * @return a new evolution streamable object
266         * @throws NullPointerException if the give {@code predicate} is {@code null}
267         */
268        default EvolutionStreamable<G, C>
269        limit(final Supplier<? extends Predicate<? super EvolutionResult<G, C>>> proceed) {
270                requireNonNull(proceed);
271
272                return new EvolutionStreamable<>() {
273                        @Override
274                        public EvolutionStream<G, C>
275                        stream(final Supplier<EvolutionStart<G, C>> start) {
276                                return EvolutionStreamable.this.stream(start).limit(proceed.get());
277                        }
278
279                        @Override
280                        public EvolutionStream<G, C> stream(final EvolutionInit<G> init) {
281                                return EvolutionStreamable.this.stream(init).limit(proceed.get());
282                        }
283                };
284        }
285
286        /**
287         * Return a new {@code EvolutionStreamable} instance where all created
288         * {@code EvolutionStream}s are limited to the given number of generations.
289         *
290         * @param generations the number of generations after the created evolution
291         *        streams are truncated
292         * @return a new evolution streamable object
293         * @throws IllegalArgumentException if the given {@code generations} is
294         *         smaller than zero.
295         */
296        default EvolutionStreamable<G, C> limit(final long generations) {
297                return limit(() -> Limits.byFixedGeneration(generations));
298        }
299
300}