1 package net.bmahe.genetics4j.samples;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.util.BitSet;
6 import java.util.List;
7
8 import org.apache.commons.cli.CommandLine;
9 import org.apache.commons.cli.CommandLineParser;
10 import org.apache.commons.cli.DefaultParser;
11 import org.apache.commons.cli.HelpFormatter;
12 import org.apache.commons.cli.Options;
13 import org.apache.commons.cli.ParseException;
14 import org.apache.commons.io.FileUtils;
15 import org.apache.commons.lang3.Validate;
16 import org.apache.logging.log4j.LogManager;
17 import org.apache.logging.log4j.Logger;
18
19 import net.bmahe.genetics4j.core.EASystem;
20 import net.bmahe.genetics4j.core.EASystemFactory;
21 import net.bmahe.genetics4j.core.Genotype;
22 import net.bmahe.genetics4j.core.chromosomes.BitChromosome;
23 import net.bmahe.genetics4j.core.evolutionlisteners.EvolutionListeners;
24 import net.bmahe.genetics4j.core.postevaluationprocess.FitnessSharing;
25 import net.bmahe.genetics4j.core.spec.EAConfiguration;
26 import net.bmahe.genetics4j.core.spec.EAConfiguration.Builder;
27 import net.bmahe.genetics4j.core.spec.EAExecutionContext;
28 import net.bmahe.genetics4j.core.spec.EAExecutionContexts;
29 import net.bmahe.genetics4j.core.spec.EvolutionResult;
30 import net.bmahe.genetics4j.core.spec.chromosome.BitChromosomeSpec;
31 import net.bmahe.genetics4j.core.spec.combination.MultiPointCrossover;
32 import net.bmahe.genetics4j.core.spec.mutation.RandomMutation;
33 import net.bmahe.genetics4j.core.spec.selection.Tournament;
34 import net.bmahe.genetics4j.core.termination.Terminations;
35 import net.bmahe.genetics4j.core.util.BitChromosomeUtils;
36 import net.bmahe.genetics4j.extras.evolutionlisteners.CSVEvolutionListener;
37 import net.bmahe.genetics4j.extras.evolutionlisteners.ColumnExtractor;
38
39 public class FitnessSharingExample {
40
41 final static public Logger logger = LogManager.getLogger(FitnessSharingExample.class);
42
43 final static public String PARAM_DEST_CSV_WITHOUT_SHARING = "w";
44 final static public String LONG_PARAM_DEST_CSV_WITHOUT_SHARING = "without-sharing-dest";
45
46 final static public String PARAM_DEST_CSV_WITH_SHARING = "s";
47 final static public String LONG_PARAM_DEST_CSV_WITH_SHARING = "with-sharing-dest";
48
49 final static public String PARAM_POPULATION_SIZE = "p";
50 final static public String LONG_PARAM_POPULATION_SIZE = "population-size";
51
52 final static public String DEFAULT_DEST_CSV_WITHOUT_SHARING = "withoutFitnessSharing.csv";
53 final static public String DEFAULT_DEST_CSV_WITH_SHARING = "withFitnessSharing.csv";
54 final static public int DEFAULT_POPULATION_SIZE = 50;
55
56 public static void cliError(final Options options, final String errorMessage) {
57 final HelpFormatter formatter = new HelpFormatter();
58 logger.error(errorMessage);
59 formatter.printHelp(FitnessSharingExample.class.getSimpleName(), options);
60 System.exit(-1);
61 }
62
63 public static int toPhenotype(final Genotype genotype) {
64 Validate.notNull(genotype);
65
66 final BitChromosome bitChromosome = genotype.getChromosome(0, BitChromosome.class);
67 final BitSet individualBitSet = bitChromosome.getBitSet();
68
69 final long[] longArray = individualBitSet.toLongArray();
70
71 return longArray.length > 0 ? (int) longArray[0] : 0;
72 }
73
74 public static void main(String[] args) throws IOException {
75
76
77
78
79
80 final CommandLineParser parser = new DefaultParser();
81
82 final Options options = new Options();
83 options.addOption(PARAM_DEST_CSV_WITHOUT_SHARING,
84 LONG_PARAM_DEST_CSV_WITHOUT_SHARING,
85 true,
86 "destination csv file for the case without fitness sharing");
87
88 options.addOption(PARAM_DEST_CSV_WITH_SHARING,
89 LONG_PARAM_DEST_CSV_WITH_SHARING,
90 true,
91 "destination csv file for the case with fitness sharing");
92
93 options.addOption(PARAM_POPULATION_SIZE, LONG_PARAM_POPULATION_SIZE, true, "Population size");
94
95 String csvFilenameWithoutSharing = DEFAULT_DEST_CSV_WITHOUT_SHARING;
96 String csvFilenameWithSharing = DEFAULT_DEST_CSV_WITH_SHARING;
97 int populationSize = DEFAULT_POPULATION_SIZE;
98 try {
99 final CommandLine line = parser.parse(options, args);
100
101 if (line.hasOption(PARAM_DEST_CSV_WITHOUT_SHARING)) {
102 csvFilenameWithoutSharing = line.getOptionValue(PARAM_DEST_CSV_WITHOUT_SHARING);
103 }
104
105 if (line.hasOption(PARAM_DEST_CSV_WITH_SHARING)) {
106 csvFilenameWithSharing = line.getOptionValue(PARAM_DEST_CSV_WITH_SHARING);
107 }
108
109 if (line.hasOption(PARAM_POPULATION_SIZE)) {
110 populationSize = Integer.parseInt(line.getOptionValue(PARAM_POPULATION_SIZE));
111 }
112
113 } catch (ParseException exp) {
114 cliError(options, "Unexpected exception:" + exp.getMessage());
115 }
116
117 logger.info("Population size: {}", populationSize);
118
119 logger.info("Evolution without fitness sharing. CSV output located at {}", csvFilenameWithoutSharing);
120 FileUtils.forceMkdirParent(new File(csvFilenameWithoutSharing));
121
122
123 final Builder<Double> eaConfigurationBuilder = new EAConfiguration.Builder<>();
124 eaConfigurationBuilder.chromosomeSpecs(BitChromosomeSpec.of(7))
125 .parentSelectionPolicy(Tournament.of(2))
126 .combinationPolicy(MultiPointCrossover.of(2))
127 .mutationPolicies(RandomMutation.of(0.05))
128 .fitness((genotype) -> {
129 final int x = toPhenotype(genotype);
130 return x < 0 || x > 100 ? 0.0 : Math.abs(30 * Math.sin(x / 10));
131 })
132 .termination(Terminations.ofMaxGeneration(5));
133 final EAConfiguration<Double> eaConfiguration = eaConfigurationBuilder.build();
134
135
136
137 final var csvEvolutionListener = CSVEvolutionListener.<Double, Void>of(csvFilenameWithoutSharing,
138 List.of(ColumnExtractor.of("generation", es -> es.generation()),
139 ColumnExtractor.of("fitness", es -> es.fitness()),
140 ColumnExtractor.of("x", es -> toPhenotype(es.individual()))));
141
142 final var logTop5EvolutionListener = EvolutionListeners
143 .<Double>ofLogTopN(logger, 5, genotype -> Integer.toString(toPhenotype(genotype)));
144
145 final EAExecutionContext<Double> eaExecutionContext = EAExecutionContexts.<Double>forScalarFitness()
146 .populationSize(populationSize)
147 .addEvolutionListeners(logTop5EvolutionListener, csvEvolutionListener)
148 .build();
149
150
151
152 final EASystem<Double> eaSystem = EASystemFactory.from(eaConfiguration, eaExecutionContext);
153
154 final EvolutionResult<Double> evolutionResult = eaSystem.evolve();
155 logger.info("Best genotype: {}", evolutionResult.bestGenotype());
156 logger.info(" with fitness: {}", evolutionResult.bestFitness());
157 logger.info(" at generation: {}", evolutionResult.generation());
158
159
160
161
162 logger.info("Evolution with fitness sharing. CSV output located at {}", csvFilenameWithSharing);
163 FileUtils.forceMkdirParent(new File(csvFilenameWithSharing));
164
165
166 var eaConfigurationWithFitnessSharing = new EAConfiguration.Builder<Double>().from(eaConfiguration)
167 .postEvaluationProcessor(FitnessSharing.ofStandard((i1, i2) -> {
168
169 final BitChromosome bitChromosome1 = i1.getChromosome(0, BitChromosome.class);
170 final BitChromosome bitChromosome2 = i2.getChromosome(0, BitChromosome.class);
171
172 return (double) BitChromosomeUtils.hammingDistance(bitChromosome1, bitChromosome2);
173 }, 5.0))
174 .build();
175
176
177
178 final var csvEvolutionListenerWithFitnessSharing = new CSVEvolutionListener.Builder<Double, Void>()
179 .from(csvEvolutionListener)
180 .filename(csvFilenameWithSharing)
181 .build();
182
183 final var eaExecutionContextWithFitnessSharing = EAExecutionContext.<Double>builder()
184 .from(eaExecutionContext)
185 .evolutionListeners(List.of(logTop5EvolutionListener, csvEvolutionListenerWithFitnessSharing))
186 .build();
187
188
189
190 final EASystem<Double> eaSystemWithFitnessSharing = EASystemFactory.from(eaConfigurationWithFitnessSharing,
191 eaExecutionContextWithFitnessSharing);
192
193 final EvolutionResult<Double> evolutionResultWithFitnessSharing = eaSystemWithFitnessSharing.evolve();
194 logger.info("Best genotype: {}", evolutionResultWithFitnessSharing.bestGenotype());
195 logger.info(" with fitness: {}", evolutionResultWithFitnessSharing.bestFitness());
196 logger.info(" at generation: {}", evolutionResultWithFitnessSharing.generation());
197
198 }
199 }