001/*
002 * Java Genetic Algorithm Library (jenetics-8.1.0).
003 * Copyright (c) 2007-2024 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         * {@snippet lang="java":
089         * final EvolutionStream<G, C> stream = streamable
090         *     .stream(() -> EvolutionStart.of(ISeq.empty(), 1));
091         * }
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         * {@snippet lang="java":
123         * private static final Problem<Double, DoubleGene, Double>
124         * PROBLEM = Problem.of(
125         *     x -> cos(0.5 + sin(x))*cos(x),
126         *     Codecs.ofScalar(DoubleRange.of(0.0, 2.0*PI))
127         * );
128         *
129         * private static final Engine<DoubleGene, Double>
130         * ENGINE = Engine.builder(PROBLEM)
131         *     .optimize(Optimize.MINIMUM)
132         *     .offspringSelector(new RouletteWheelSelector<>())
133         *     .build();
134         *
135         * public static void main(final String[] args) throws IOException {
136         *     // Result of the first evolution run.
137         *     final EvolutionResult<DoubleGene, Double> rescue = ENGINE.stream()
138         *         .limit(Limits.bySteadyFitness(10))
139         *         .collect(EvolutionResult.toBestEvolutionResult());
140         *
141         *     // Save the result of the first run into a file.
142         *     final Path path = Paths.get("result.bin");
143         *     IO.object.write(rescue, path);
144         *
145         *     // Load the previous result and continue evolution.
146         *     @SuppressWarnings("unchecked")
147         *     final EvolutionResult<DoubleGene, Double> result = ENGINE
148         *         .stream((EvolutionResult<DoubleGene, Double>)IO.object.read(path))
149         *         .limit(Limits.bySteadyFitness(20))
150         *         .collect(EvolutionResult.toBestEvolutionResult());
151         *
152         *     System.out.println(result.bestPhenotype());
153         * }
154         * }
155         *
156         * The example above shows how to save an {@link EvolutionResult} from a
157         * first run, save it to disk and continue the evolution.
158         *
159         * @param result the previously evolved {@code EvolutionResult}
160         * @return a new evolution stream, which continues a previous one
161         * @throws NullPointerException if the given evolution {@code result} is
162         *         {@code null}
163         */
164        default EvolutionStream<G, C>
165        stream(final EvolutionResult<G, C> result) {
166                return stream(EvolutionStart.of(
167                        result.population(),
168                        result.generation()
169                ));
170        }
171
172        /**
173         * Create a new, possibly <em>infinite</em>, evolution stream with the given
174         * initial population. If an empty {@code Population} is given, the engine's
175         * genotype factory is used for creating the population. The given population
176         * might be the result of another engine, and this method allows to start the
177         * evolution with the outcome of a different engine. The fitness function
178         * is replaced by the one defined for this engine.
179         *
180         * @param population the initial individuals used for the evolution stream.
181         *        Missing individuals are created and individuals not needed are
182         *        skipped.
183         * @param generation the generation the stream starts from; must be greater
184         *        than zero.
185         * @return a new evolution stream.
186         * @throws java.lang.NullPointerException if the given {@code population} is
187         *         {@code null}.
188         * @throws IllegalArgumentException if the given {@code generation} is
189         *         smaller then one
190         */
191        default EvolutionStream<G, C> stream(
192                final ISeq<Phenotype<G, C>> population,
193                final long generation
194        ) {
195                return stream(EvolutionStart.of(population, generation));
196        }
197
198        /**
199         * Create a new, possibly <em>infinite</em>, evolution stream with the given
200         * initial population. If an empty {@code Population} is given, the engine's
201         * genotype factory is used for creating the population. The given population
202         * might be the result of another engine, and this method allows to start the
203         * evolution with the outcome of a different engine. The fitness function
204         * is replaced by the one defined for this engine.
205         *
206         * @param population the initial individuals used for the evolution stream.
207         *        Missing individuals are created and individuals not needed are
208         *        skipped.
209         * @return a new evolution stream.
210         * @throws java.lang.NullPointerException if the given {@code population} is
211         *         {@code null}.
212         */
213        default EvolutionStream<G, C> stream(final ISeq<Phenotype<G, C>> population) {
214                return stream(EvolutionStart.of(population, 1));
215        }
216
217        /**
218         * Create a new, possibly <em>infinite</em>, evolution stream with the given
219         * initial individuals. If an empty {@code Iterable} is given, the engine's
220         * genotype factory is used for creating the population.
221         *
222         * @param genotypes the initial individuals used for the evolution stream.
223         *        Missing individuals are created and individuals not needed are
224         *        skipped.
225         * @param generation the generation the stream starts from; must be greater
226         *        than zero.
227         * @return a new evolution stream.
228         * @throws java.lang.NullPointerException if the given {@code genotypes} is
229         *         {@code null}.
230         * @throws IllegalArgumentException if the given {@code generation} is
231         *         smaller then one
232         */
233        default EvolutionStream<G, C> stream(
234                final Iterable<Genotype<G>> genotypes,
235                final long generation
236        ) {
237                return stream(EvolutionInit.of(ISeq.of(genotypes), generation));
238        }
239
240        /**
241         * Create a new, possibly <em>infinite</em>, evolution stream with the given
242         * initial individuals. If an empty {@code Iterable} is given, the engine's
243         * genotype factory is used for creating the population.
244         *
245         * @param genotypes the initial individuals used for the evolution stream.
246         *        Missing individuals are created and individuals not needed are
247         *        skipped.
248         * @return a new evolution stream.
249         * @throws java.lang.NullPointerException if the given {@code genotypes} is
250         *         {@code null}.
251         */
252        default EvolutionStream<G, C>
253        stream(final Iterable<Genotype<G>> genotypes) {
254                return stream(genotypes, 1);
255        }
256
257        /**
258         * Return a new {@code EvolutionStreamable} instance where all created
259         * {@code EvolutionStream}s are limited by the given predicate. Since some
260         * predicates have to maintain internal state, a predicate {@code Supplier}
261         * must be given instead a plain limiting predicate.
262         *
263         * @param proceed the limiting predicate supplier.
264         * @return a new evolution-streamable object
265         * @throws NullPointerException if the give {@code predicate} is {@code null}
266         */
267        default EvolutionStreamable<G, C>
268        limit(final Supplier<? extends Predicate<? super EvolutionResult<G, C>>> proceed) {
269                requireNonNull(proceed);
270
271                return new EvolutionStreamable<>() {
272                        @Override
273                        public EvolutionStream<G, C>
274                        stream(final Supplier<EvolutionStart<G, C>> start) {
275                                return EvolutionStreamable.this.stream(start).limit(proceed.get());
276                        }
277
278                        @Override
279                        public EvolutionStream<G, C> stream(final EvolutionInit<G> init) {
280                                return EvolutionStreamable.this.stream(init).limit(proceed.get());
281                        }
282                };
283        }
284
285        /**
286         * Return a new {@code EvolutionStreamable} instance where all created
287         * {@code EvolutionStream}s are limited to the given number of generations.
288         *
289         * @param generations the number of generations after the created evolution
290         *        streams are truncated
291         * @return a new evolution-streamable object
292         * @throws IllegalArgumentException if the given {@code generations} is
293         *         smaller than zero.
294         */
295        default EvolutionStreamable<G, C> limit(final long generations) {
296                return limit(() -> Limits.byFixedGeneration(generations));
297        }
298
299}