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}