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