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 import java.util.Objects;
8
9 import org.apache.commons.cli.CommandLine;
10 import org.apache.commons.cli.CommandLineParser;
11 import org.apache.commons.cli.DefaultParser;
12 import org.apache.commons.cli.HelpFormatter;
13 import org.apache.commons.cli.Options;
14 import org.apache.commons.cli.ParseException;
15 import org.apache.commons.io.FileUtils;
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 Objects.requireNonNull(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(
84 PARAM_DEST_CSV_WITHOUT_SHARING,
85 LONG_PARAM_DEST_CSV_WITHOUT_SHARING,
86 true,
87 "destination csv file for the case without fitness sharing");
88
89 options.addOption(
90 PARAM_DEST_CSV_WITH_SHARING,
91 LONG_PARAM_DEST_CSV_WITH_SHARING,
92 true,
93 "destination csv file for the case with fitness sharing");
94
95 options.addOption(PARAM_POPULATION_SIZE, LONG_PARAM_POPULATION_SIZE, true, "Population size");
96
97 String csvFilenameWithoutSharing = DEFAULT_DEST_CSV_WITHOUT_SHARING;
98 String csvFilenameWithSharing = DEFAULT_DEST_CSV_WITH_SHARING;
99 int populationSize = DEFAULT_POPULATION_SIZE;
100 try {
101 final CommandLine line = parser.parse(options, args);
102
103 if (line.hasOption(PARAM_DEST_CSV_WITHOUT_SHARING)) {
104 csvFilenameWithoutSharing = line.getOptionValue(PARAM_DEST_CSV_WITHOUT_SHARING);
105 }
106
107 if (line.hasOption(PARAM_DEST_CSV_WITH_SHARING)) {
108 csvFilenameWithSharing = line.getOptionValue(PARAM_DEST_CSV_WITH_SHARING);
109 }
110
111 if (line.hasOption(PARAM_POPULATION_SIZE)) {
112 populationSize = Integer.parseInt(line.getOptionValue(PARAM_POPULATION_SIZE));
113 }
114
115 } catch (ParseException exp) {
116 cliError(options, "Unexpected exception:" + exp.getMessage());
117 }
118
119 logger.info("Population size: {}", populationSize);
120
121 logger.info("Evolution without fitness sharing. CSV output located at {}", csvFilenameWithoutSharing);
122 FileUtils.forceMkdirParent(new File(csvFilenameWithoutSharing));
123
124
125 final Builder<Double> eaConfigurationBuilder = new EAConfiguration.Builder<>();
126 eaConfigurationBuilder.chromosomeSpecs(BitChromosomeSpec.of(7))
127 .parentSelectionPolicy(Tournament.of(2))
128 .combinationPolicy(MultiPointCrossover.of(2))
129 .mutationPolicies(RandomMutation.of(0.05))
130 .fitness((genotype) -> {
131 final int x = toPhenotype(genotype);
132 return x < 0 || x > 100 ? 0.0 : Math.abs(30 * Math.sin(x / 10));
133 })
134 .termination(Terminations.ofMaxGeneration(5));
135 final EAConfiguration<Double> eaConfiguration = eaConfigurationBuilder.build();
136
137
138
139 final var csvEvolutionListener = CSVEvolutionListener.<Double, Void>of(
140 csvFilenameWithoutSharing,
141 List.of(
142 ColumnExtractor.of("generation", es -> es.generation()),
143 ColumnExtractor.of("fitness", es -> es.fitness()),
144 ColumnExtractor.of("x", es -> toPhenotype(es.individual()))));
145
146 final var logTop5EvolutionListener = EvolutionListeners
147 .<Double>ofLogTopN(logger, 5, genotype -> Integer.toString(toPhenotype(genotype)));
148
149 final EAExecutionContext<Double> eaExecutionContext = EAExecutionContexts.<Double>forScalarFitness()
150 .populationSize(populationSize)
151 .addEvolutionListeners(logTop5EvolutionListener, csvEvolutionListener)
152 .build();
153
154
155
156 final EASystem<Double> eaSystem = EASystemFactory.from(eaConfiguration, eaExecutionContext);
157
158 final EvolutionResult<Double> evolutionResult = eaSystem.evolve();
159 logger.info("Best genotype: {}", evolutionResult.bestGenotype());
160 logger.info(" with fitness: {}", evolutionResult.bestFitness());
161 logger.info(" at generation: {}", evolutionResult.generation());
162
163
164
165
166 logger.info("Evolution with fitness sharing. CSV output located at {}", csvFilenameWithSharing);
167 FileUtils.forceMkdirParent(new File(csvFilenameWithSharing));
168
169
170 var eaConfigurationWithFitnessSharing = new EAConfiguration.Builder<Double>().from(eaConfiguration)
171 .postEvaluationProcessor(FitnessSharing.ofStandard((i1, i2) -> {
172
173 final BitChromosome bitChromosome1 = i1.getChromosome(0, BitChromosome.class);
174 final BitChromosome bitChromosome2 = i2.getChromosome(0, BitChromosome.class);
175
176 return (double) BitChromosomeUtils.hammingDistance(bitChromosome1, bitChromosome2);
177 }, 5.0))
178 .build();
179
180
181
182 final var csvEvolutionListenerWithFitnessSharing = new CSVEvolutionListener.Builder<Double, Void>()
183 .from(csvEvolutionListener)
184 .filename(csvFilenameWithSharing)
185 .build();
186
187 final var eaExecutionContextWithFitnessSharing = EAExecutionContext.<Double>builder()
188 .from(eaExecutionContext)
189 .evolutionListeners(List.of(logTop5EvolutionListener, csvEvolutionListenerWithFitnessSharing))
190 .build();
191
192
193
194 final EASystem<Double> eaSystemWithFitnessSharing = EASystemFactory
195 .from(eaConfigurationWithFitnessSharing, eaExecutionContextWithFitnessSharing);
196
197 final EvolutionResult<Double> evolutionResultWithFitnessSharing = eaSystemWithFitnessSharing.evolve();
198 logger.info("Best genotype: {}", evolutionResultWithFitnessSharing.bestGenotype());
199 logger.info(" with fitness: {}", evolutionResultWithFitnessSharing.bestFitness());
200 logger.info(" at generation: {}", evolutionResultWithFitnessSharing.generation());
201
202 }
203 }