View Javadoc
1   package net.bmahe.genetics4j.core.spec;
2   
3   import java.util.Collection;
4   import java.util.Collections;
5   import java.util.Comparator;
6   import java.util.List;
7   import java.util.Optional;
8   import java.util.function.Function;
9   import java.util.function.Supplier;
10  
11  import org.apache.commons.lang3.Validate;
12  import org.immutables.value.Value;
13  
14  import net.bmahe.genetics4j.core.Genotype;
15  import net.bmahe.genetics4j.core.Population;
16  import net.bmahe.genetics4j.core.combination.AllCasesGenotypeCombinator;
17  import net.bmahe.genetics4j.core.combination.GenotypeCombinator;
18  import net.bmahe.genetics4j.core.spec.chromosome.ChromosomeSpec;
19  import net.bmahe.genetics4j.core.spec.combination.CombinationPolicy;
20  import net.bmahe.genetics4j.core.spec.mutation.MutationPolicy;
21  import net.bmahe.genetics4j.core.spec.replacement.Elitism;
22  import net.bmahe.genetics4j.core.spec.replacement.ReplacementStrategy;
23  import net.bmahe.genetics4j.core.spec.selection.SelectionPolicy;
24  import net.bmahe.genetics4j.core.spec.selection.Tournament;
25  import net.bmahe.genetics4j.core.termination.Termination;
26  
27  /**
28   * Evolutionary Algorithm Configuration.
29   * <p>
30   * This describe the set of strategies to use. They describe the genotype, the
31   * different policies for selection, combination as well as mutation, and other
32   * relevant parameters
33   * <p>
34   * Fitness computation is delegated to subclasses to better match the various
35   * ways in which they can be computed
36   * 
37   * @param <T> Type of the fitness measurement
38   */
39  public abstract class AbstractEAConfiguration<T extends Comparable<T>> {
40  	/**
41  	 * Default offspring ratio
42  	 */
43  	public static final double DEFAULT_OFFSPRING_RATIO = 1.0;
44  
45  	/**
46  	 * Default optimization strategy
47  	 */
48  	public static final Optimization DEFAULT_OPTIMIZATION = Optimization.MAXIMIZE;
49  
50  	/**
51  	 * Genotype of the population
52  	 * 
53  	 * @return
54  	 */
55  	public abstract List<ChromosomeSpec> chromosomeSpecs();
56  
57  	/**
58  	 * Defines the policy to select the parents. The selected parents will be used
59  	 * for generating the new offsprings
60  	 * 
61  	 * @return
62  	 */
63  	public abstract SelectionPolicy parentSelectionPolicy();
64  
65  	/**
66  	 * Defines the policy to generate new offsprings from two parents
67  	 * 
68  	 * @return
69  	 */
70  	public abstract CombinationPolicy combinationPolicy();
71  
72  	/**
73  	 * Defines what mutations to be performed on the offsprings
74  	 * 
75  	 * @return
76  	 */
77  	public abstract List<MutationPolicy> mutationPolicies();
78  
79  	/**
80  	 * Defines the replacement strategy
81  	 * <p>
82  	 * The replacement strategy is what will determine the next population based on
83  	 * the generated and mutated offsprings along with the current population
84  	 * <p>
85  	 * If not specified, the default replacement strategy will be to use Elitism
86  	 * with tournament selection of 3 individuals for both offsprings and survivors.
87  	 * The default offspring ratio is {@link Elitism#DEFAULT_OFFSPRING_RATIO}
88  	 * 
89  	 * @return
90  	 */
91  	@Value.Default
92  	public ReplacementStrategy replacementStrategy() {
93  		final var replacementStrategyBuilder = Elitism.builder();
94  
95  		replacementStrategyBuilder.offspringRatio(Elitism.DEFAULT_OFFSPRING_RATIO)
96  				.offspringSelectionPolicy(Tournament.of(3))
97  				.survivorSelectionPolicy(Tournament.of(3));
98  
99  		return replacementStrategyBuilder.build();
100 	}
101 
102 	/**
103 	 * Post-processing of a population after it got evaluated
104 	 * <p>
105 	 * This gives the opportunity to filter out, repair or rescore individuals
106 	 * 
107 	 * @return Population to be used by the remaining evolution process
108 	 */
109 	public abstract Optional<Function<Population<T>, Population<T>>> postEvaluationProcessor();
110 
111 	/**
112 	 * Defines termination condition
113 	 * 
114 	 * @return
115 	 */
116 	public abstract Termination<T> termination();
117 
118 	/**
119 	 * Defines how to generate individuals
120 	 * <p>
121 	 * If not specified, the system will rely on the chromosome factories
122 	 * 
123 	 * @return
124 	 */
125 	public abstract Optional<Supplier<Genotype>> genotypeGenerator();
126 
127 	/**
128 	 * Seed the initial population with specific individuals
129 	 * 
130 	 * @return
131 	 */
132 	@Value.Default
133 	public Collection<Genotype> seedPopulation() {
134 		return Collections.emptyList();
135 	}
136 
137 	/**
138 	 * Defines how to combine the offspring chromosomes generated
139 	 * <p>
140 	 * Combination of individuals is done on a per chromosome basis. This means some
141 	 * parents may generate a different number of children for each chromosome. This
142 	 * method will therefore define how to take all these generated chromosomes and
143 	 * combine them into offspring individuals
144 	 * <p>
145 	 * The current default implementation is to generate as many individual as there
146 	 * are combinations of generated chromosomes
147 	 * 
148 	 * @return
149 	 */
150 	@Value.Default
151 	public GenotypeCombinator genotypeCombinator() {
152 		return new AllCasesGenotypeCombinator();
153 	}
154 
155 	/**
156 	 * Defines how many children will be generated at each iteration. Value must be
157 	 * between 0 and 1 (inclusive) and represents a fraction of the population size
158 	 * 
159 	 * @return
160 	 */
161 	@Value.Default
162 	public double offspringGeneratedRatio() {
163 		return DEFAULT_OFFSPRING_RATIO;
164 	}
165 
166 	/**
167 	 * Defines the optimization goal, whether we want to maximize the fitness or
168 	 * minimize it
169 	 * 
170 	 * @return
171 	 */
172 	@Value.Default
173 	public Optimization optimization() {
174 		return DEFAULT_OPTIMIZATION;
175 	}
176 
177 	/**
178 	 * Validates the configuration
179 	 */
180 	@Value.Check
181 	protected void check() {
182 		Validate.isTrue(chromosomeSpecs().size() > 0, "No chromosomes were specified");
183 		Validate.inclusiveBetween(0.0d, 1.0d, offspringGeneratedRatio());
184 	}
185 
186 	/**
187 	 * Returns a specific chromosome spec from the genotype definition
188 	 * 
189 	 * @param index
190 	 * @return
191 	 */
192 	public ChromosomeSpec getChromosomeSpec(final int index) {
193 		Validate.isTrue(index >= 0);
194 		Validate.isTrue(index < chromosomeSpecs().size());
195 
196 		return chromosomeSpecs().get(index);
197 	}
198 
199 	/**
200 	 * Returns the currently number of chromosomes defined in the genotype
201 	 * 
202 	 * @return
203 	 */
204 	public int numChromosomes() {
205 		return chromosomeSpecs().size();
206 	}
207 
208 	/**
209 	 * Return a comparator based on the optimization method and natural order
210 	 * 
211 	 * @return
212 	 */
213 	public Comparator<T> fitnessComparator() {
214 
215 		return switch (optimization()) {
216 			case MAXIMIZE -> Comparator.naturalOrder();
217 			case MINIMIZE -> Comparator.reverseOrder();
218 		};
219 	}
220 }