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 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 another 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 another 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 have 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}