001/* 002 * Java Genetic Algorithm Library (jenetics-8.0.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 * 171 * {@snippet lang="java": 172 * public static void main(final String[] args) { 173 * final Problem<double[], DoubleGene, Double> problem = Problem.of( 174 * v -> Math.sin(v[0])*Math.cos(v[1]), 175 * Codecs.ofVector(DoubleRange.of(0, 2*Math.PI), 2) 176 * ); 177 * 178 * // Engine builder template. 179 * final Engine.Builder<DoubleGene, Double> builder = Engine 180 * .builder(problem) 181 * .minimizing(); 182 * 183 * // Evolution used for low fitness variance. 184 * final Evolution<DoubleGene, Double> lowVar = builder.copy() 185 * .alterers(new Mutator<>(0.5)) 186 * .selector(new MonteCarloSelector<>()) 187 * .build(); 188 * 189 * // Evolution used for high fitness variance. 190 * final Evolution<DoubleGene, Double> highVar = builder.copy() 191 * .alterers( 192 * new Mutator<>(0.05), 193 * new MeanAlterer<>()) 194 * .selector(new RouletteWheelSelector<>()) 195 * .build(); 196 * 197 * final EvolutionStream<DoubleGene, Double> stream = 198 * EvolutionStream.ofAdjustableEvolution( 199 * EvolutionStart::empty, 200 * er -> var(er) < 0.2 ? lowVar : highVar 201 * ); 202 * 203 * final Genotype<DoubleGene> result = stream 204 * .limit(Limits.bySteadyFitness(50)) 205 * .collect(EvolutionResult.toBestGenotype()); 206 * 207 * System.out.println(result + ": " + 208 * problem.fitness().apply(problem.codec().decode(result))); 209 * } 210 * 211 * private static double var(final EvolutionStart<DoubleGene, Double> result) { 212 * return result != null 213 * ? result.getPopulation().stream() 214 * .map(Phenotype::fitness) 215 * .collect(DoubleMoments.toDoubleMoments()) 216 * .variance() 217 * : 0.0; 218 * } 219 * } 220 * 221 * @see #ofEvolution(Supplier, Evolution) 222 * 223 * @param start the evolution start object 224 * @param evolution the adaptable evolution function 225 * @param <G> the gene type 226 * @param <C> the fitness type 227 * @return a new {@code EvolutionStream} with the given {@code start} and 228 * {@code evolution} function 229 * @throws java.lang.NullPointerException if one of the arguments is 230 * {@code null} 231 */ 232 static <G extends Gene<?, G>, C extends Comparable<? super C>> 233 EvolutionStream<G, C> ofAdjustableEvolution( 234 final Supplier<EvolutionStart<G, C>> start, 235 final Function< 236 ? super EvolutionStart<G, C>, 237 ? extends Evolution<G, C>> evolution 238 ) { 239 return EvolutionStreamImpl.of(start, evolution); 240 } 241 242}