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