1 | package ec.vector; |
---|
2 | |
---|
3 | import ec.*; |
---|
4 | import ec.util.*; |
---|
5 | |
---|
6 | /* |
---|
7 | * FloatVectorSpecies.java |
---|
8 | * |
---|
9 | * Created: Tue Feb 20 13:26:00 2001 |
---|
10 | * By: Sean Luke |
---|
11 | */ |
---|
12 | |
---|
13 | /** |
---|
14 | * FloatVectorSpecies is a subclass of VectorSpecies with special |
---|
15 | * constraints for floating-point vectors, namely FloatVectorIndividual and |
---|
16 | * DoubleVectorIndividual. |
---|
17 | * |
---|
18 | * <p>FloatVectorSpecies can specify min/max numeric constraints on gene values |
---|
19 | * in three different ways. |
---|
20 | * |
---|
21 | * <ol> |
---|
22 | * <li> You may provide a default min and max value. |
---|
23 | * This is done by specifying: |
---|
24 | * <p><i>base</i>.<tt>min-gene</tt> |
---|
25 | * <br><i>base</i>.<tt>max-gene</tt> |
---|
26 | * <p><i>Note:</i> you <b>must</b> provide these values even if you don't use them, |
---|
27 | * as they're used as defaults by #2 and #3 below. |
---|
28 | *<p> |
---|
29 | * <li> You may provide min and max values for genes in segments (regions) along |
---|
30 | * the genome. This is done by specifying: |
---|
31 | * <p><i>base</i>.<tt>num-segments</tt> |
---|
32 | * The segments may be defined by either start or end indices of genes. |
---|
33 | * This is controlled by specifying the value of: |
---|
34 | * <p><i>base</i>.<tt>segment-type</tt> |
---|
35 | * which can assume the value of start or end, with start being the default. |
---|
36 | * The indices are defined using Java array style, i.e. the first gene has the index of 0, |
---|
37 | * and the last gene has the index of genome-size - 1. |
---|
38 | * <p>Using this method, each segment is specified by<i>j</i>... |
---|
39 | * <p><i>base</i>.<tt>segment.</tt><i>j</i><tt>.start</tt> |
---|
40 | * <br><i>base</i>.<tt>segment.</tt><i>j</i><tt>.min-gene</tt> |
---|
41 | * <br><i>base</i>.<tt>segment.</tt><i>j</i><tt>.max-gene</tt> |
---|
42 | * if segment-type value was chosen as start or by: |
---|
43 | * <p><i>base</i>.<tt>segment.</tt><i>j</i><tt>.end</tt> |
---|
44 | * <br><i>base</i>.<tt>segment.</tt><i>j</i><tt>.min-gene</tt> |
---|
45 | * <br><i>base</i>.<tt>segment.</tt><i>j</i><tt>.max-gene</tt> |
---|
46 | * if segment-type value is equal to end. |
---|
47 | *<p> |
---|
48 | * <li> You may provide min and max values for each separate gene. |
---|
49 | * This is done by specifying (for each gene location <i>i</i> you wish to specify) |
---|
50 | * <p><i>base</i>.<tt>min-gene</tt>.<i>i</i> |
---|
51 | * <br><i>basn</i>.<tt>max-gene</tt>.<i>i</i> |
---|
52 | * </ol> |
---|
53 | * |
---|
54 | * <p>Any settings for #3 override #2, and both override #1. |
---|
55 | * |
---|
56 | * <p> |
---|
57 | * FloatVectorSpecies provides support for three ways of mutating a gene: |
---|
58 | * <ul> |
---|
59 | * <li>replacing the gene's value with a value uniformly-drawn from the gene's |
---|
60 | * range (the default behavior, legacy from the previous versions).</li> |
---|
61 | * <li>perturbing the gene's value with gaussian noise; if the gene-by-gene range |
---|
62 | * is used, than the standard deviation is scaled to reflect each gene's range. |
---|
63 | * If the gaussian mutation's standard deviation is too large for the range, |
---|
64 | * than there's a large probability the mutated value will land outside range. |
---|
65 | * We will try again a number of times (100) before giving up and using the |
---|
66 | * previous mutation method.</li> |
---|
67 | * <li>perturbing the gene's value with noise chosen from a <i>polynomial distribution</i>, |
---|
68 | * similar to the gaussian distribution. The polynomial distribution was popularized |
---|
69 | * by Kalyanmoy Deb and is found in many of his publications (see http://www.iitk.ac.in/kangal/deb.shtml). |
---|
70 | * The polynomial distribution has two options. First, there is the <i>index</i>. This |
---|
71 | * variable defines the shape of the distribution and is in some sense the equivalent of the |
---|
72 | * standard deviation in the gaussian distribution. The index is an integer. If it is zero, |
---|
73 | * the polynomial distribution is simply the uniform distribution from [1,-1]. If it is 1, the |
---|
74 | * polynomial distribution is basically a triangular distribution from [1,-1] peaking at 0. If |
---|
75 | * it is 2, the polynomial distribution follows a squared function, again peaking at 0. Larger |
---|
76 | * values result in even more peaking and narrowness. The default values used in nearly all of |
---|
77 | * the NSGA-II and Deb work is 20. Second, there is whether or not the value is intended for |
---|
78 | * <i>bounded</i> genes. The default polynomial distribution is used when we assume the gene can |
---|
79 | * take on literally any value, even beyond the min and max values. For genes which are restricted |
---|
80 | * to be between min and max, there is an alternative version of the polynomial distribution, used by |
---|
81 | * Deb's team but not discussed much in the literature, desiged for that situation. We assume boundedness |
---|
82 | * by default, and have found it to be somewhat better for NSGA-II and SPEA2 problems. For a description |
---|
83 | * of this alternative version, see "A Niched-Penalty Approach for Constraint Handling in Genetic Algorithms" |
---|
84 | * by Kalyanmoy Deb and Samir Agrawal. Deb's default implementation bounds the result to min or max; |
---|
85 | * instead ECJ's implementation of the polynomial distribution retries until it finds a legal value. This |
---|
86 | * will be just fine for ranges like [0,1], but for smaller ranges you may be waiting a long time. |
---|
87 | * </ul> |
---|
88 | * |
---|
89 | * |
---|
90 | * <p> |
---|
91 | * <b>Parameters</b><br> |
---|
92 | * <table> |
---|
93 | * <tr> |
---|
94 | * <td valign=top><i>base</i>.<tt>min-gene</tt><br> |
---|
95 | * <font size=-1>double (default=0.0)</font></td> |
---|
96 | * <td valign=top>(the minimum gene value)</td> |
---|
97 | * </tr> |
---|
98 | * |
---|
99 | * <tr> |
---|
100 | * <td valign=top><i>base</i>.<tt>max-gene</tt><br> |
---|
101 | * <font size=-1>double >= <i>base</i>.min-gene</font></td> |
---|
102 | * <td valign=top>(the maximum gene value)</td> |
---|
103 | * </tr> |
---|
104 | * |
---|
105 | * <tr> |
---|
106 | * <td valign=top><i>base</i>.<tt>min-gene</tt>.<i>i</i><br> |
---|
107 | * <font size=-1>double (default=<i>base</i>.<tt>min-gene</tt>)</font></td> |
---|
108 | * <td valign=top>(the minimum gene value for gene <i>i</i>)</td> |
---|
109 | * </tr> |
---|
110 | * |
---|
111 | * <tr> |
---|
112 | * <td valign=top><i>base</i>.<tt>max-gene</tt>.<i>i</i><br> |
---|
113 | * <font size=-1>double >= <i>base</i>.min-gene.<i>i</i> (default=<i>base</i>.<tt>max-gene</tt>)</font></td> |
---|
114 | * <td valign=top>(the maximum gene value for gene <i>i</i>)</td> |
---|
115 | * </tr> |
---|
116 | * |
---|
117 | * <tr><td valign=top><i>base.</i>.<tt>num-segments</tt><br> |
---|
118 | * <font size=-1>int >= 1 (default=no segments used)</font></td> |
---|
119 | * <td valign=top>(the number of gene segments defined)</td> |
---|
120 | * </tr> |
---|
121 | * |
---|
122 | * <tr><td valign=top><i>base.</i>.<tt>segment-type</tt><br> |
---|
123 | * <font size=-1>start (default) or end</font></td> |
---|
124 | * <td valign=top>(defines the way in which segments are defined: either by providing start indices (segment-type=start) or by providing end indices (segment-type=end)</td> |
---|
125 | * </tr> |
---|
126 | * |
---|
127 | * <tr><td valign=top><i>base.</i>.<tt>segment</tt>.<i>j</i>.<tt>start</tt><br> |
---|
128 | * <font size=-1>0 <= int < genome length</font></td> |
---|
129 | * <td valign=top>(the start index of gene segment <i>j</i> -- the end of a segment is before the start of the next segment)</td> |
---|
130 | * <td valign=top>(used when the value of segment-type parameter is equal to start)</td> |
---|
131 | * </tr> |
---|
132 | * |
---|
133 | * <tr><td valign=top><i>base.</i>.<tt>segment</tt>.<i>j</i>.<tt>end</tt><br> |
---|
134 | * <font size=-1>0 <= int < genome length</font></td> |
---|
135 | * <td valign=top>(the end of gene segment <i>j</i> -- the start of a segment is after the end of the previous segment)</td> |
---|
136 | * <td valign=top>(used when the value of segment-type parameter is equal to end)</td> |
---|
137 | * </tr> |
---|
138 | * |
---|
139 | * <tr><td valign=top><i>base.</i>.<tt>segment</tt>.<i>j</i>.<tt>min-gene</tt><br> |
---|
140 | * <font size=-1>double (default=0.0)</font></td> |
---|
141 | * <td valign=top>(the minimum gene value for segment <i>j</i>)</td> |
---|
142 | * </tr> |
---|
143 | * |
---|
144 | * <tr><td valign=top><i>base.</i>.<tt>segment</tt>.<i>j</i>.<tt>max-gene</tt><br> |
---|
145 | * <font size=-1>double >= <i>base.</i>.<tt>segment</tt>.<i>j</i>.<tt>min-gene</tt></td> |
---|
146 | * <td valign=top>(the maximum gene value for segment <i>j</i>)</td> |
---|
147 | * </tr> |
---|
148 | * |
---|
149 | * <tr> |
---|
150 | * <td valign=top><i>base</i>.<tt>mutation-type</tt><br> |
---|
151 | * <font size=-1><tt>reset</tt>, <tt>gauss</tt>, or <tt>polynomial</tt> (default=<tt>reset</tt>)</font></td> |
---|
152 | * <td valign=top>(the mutation type)</td> |
---|
153 | * </tr> |
---|
154 | * |
---|
155 | * <tr> |
---|
156 | * <td valign=top><i>base</i>.<tt>mutation-stdev</tt><br> |
---|
157 | * <font size=-1>double ≥ 0</font></td> |
---|
158 | * <td valign=top>(the standard deviation or the gauss perturbation)</td> |
---|
159 | * </tr> |
---|
160 | * |
---|
161 | * <tr> |
---|
162 | * <td valign=top><i>base</i>.<tt>out-of-bounds-retries</tt><br> |
---|
163 | * <font size=-1>int ≥ 0 (default=100)</font></td> |
---|
164 | * <td valign=top>(number of times the gaussian mutation got the gene out of range |
---|
165 | * before we give up and reset the gene's value; 0 means "never give up")</td> |
---|
166 | * </tr> |
---|
167 | * |
---|
168 | * <tr> |
---|
169 | * <td valign=top><i>base</i>.<tt>distribution-index</tt><br> |
---|
170 | * <font size=-1>int ≥ 0</font></td> |
---|
171 | * <td valign=top>(the mutation distribution index for the polynomial mutation distribution)</td> |
---|
172 | * </tr> |
---|
173 | * |
---|
174 | * <tr> |
---|
175 | * <td valign=top><i>base</i>.<tt>alternative-polynomial-version</tt><br> |
---|
176 | * <font size=-1>boolean (default=true)</font></td> |
---|
177 | * <td valign=top>(whether to use the "bounded" variation of the polynomial mutation or the standard ("unbounded") version)</td> |
---|
178 | * </tr> |
---|
179 | * |
---|
180 | * <tr> |
---|
181 | * <td valign=top><i>base</i>.<tt>mutation-bounded</tt><br> |
---|
182 | * <font size=-1>boolean (default=true)</font></td> |
---|
183 | * <td valign=top>(whether mutation is restricted to only being within the min/max gene values. Does not apply to SimulatedBinaryCrossover (which is always bounded))</td> |
---|
184 | * </tr> |
---|
185 | * |
---|
186 | * </table> |
---|
187 | * @author Sean Luke, Gabriel Balan, Rafal Kicinger |
---|
188 | * @version 2.0 |
---|
189 | */ |
---|
190 | public class FloatVectorSpecies extends VectorSpecies |
---|
191 | { |
---|
192 | public final static String P_MINGENE = "min-gene"; |
---|
193 | |
---|
194 | public final static String P_MAXGENE = "max-gene"; |
---|
195 | |
---|
196 | public final static String P_MUTATIONTYPE = "mutation-type"; |
---|
197 | |
---|
198 | public final static String P_STDEV = "mutation-stdev"; |
---|
199 | |
---|
200 | public final static String P_MUTATION_DISTRIBUTION_INDEX = "mutation-distribution-index"; |
---|
201 | |
---|
202 | public final static String P_POLYNOMIAL_ALTERNATIVE = "alternative-polynomial-version"; |
---|
203 | |
---|
204 | public final static String V_RESET_MUTATION = "reset"; |
---|
205 | |
---|
206 | public final static String V_GAUSS_MUTATION = "gauss"; |
---|
207 | |
---|
208 | public final static String V_POLYNOMIAL_MUTATION = "polynomial"; |
---|
209 | |
---|
210 | public final static String P_OUTOFBOUNDS_RETRIES = "out-of-bounds-retries"; |
---|
211 | |
---|
212 | public final static String P_NUM_SEGMENTS = "num-segments"; |
---|
213 | |
---|
214 | public final static String P_SEGMENT_TYPE = "segment-type"; |
---|
215 | |
---|
216 | public final static String P_SEGMENT_START = "start"; |
---|
217 | |
---|
218 | public final static String P_SEGMENT_END = "end"; |
---|
219 | |
---|
220 | public final static String P_SEGMENT = "segment"; |
---|
221 | |
---|
222 | public final static String P_MUTATION_BOUNDED = "mutation-bounded"; |
---|
223 | |
---|
224 | public final static int C_RESET_MUTATION = 0; |
---|
225 | |
---|
226 | public final static int C_GAUSS_MUTATION = 1; |
---|
227 | |
---|
228 | public final static int C_POLYNOMIAL_MUTATION = 2; |
---|
229 | |
---|
230 | public double[] minGenes; |
---|
231 | public double[] maxGenes; |
---|
232 | |
---|
233 | /** What kind of mutation do we have? */ |
---|
234 | public int mutationType; |
---|
235 | |
---|
236 | public double gaussMutationStdev; |
---|
237 | public boolean mutationIsBounded; |
---|
238 | |
---|
239 | public int outOfBoundsRetries=100; |
---|
240 | |
---|
241 | public int mutationDistributionIndex; |
---|
242 | public boolean polynomialIsAlternative; |
---|
243 | |
---|
244 | static final double SIMULATED_BINARY_CROSSOVER_EPS = 1.0e-14; |
---|
245 | |
---|
246 | private boolean outOfBoundsRetriesWarningPrinted = false; |
---|
247 | public void outOfRangeRetryLimitReached(EvolutionState state) |
---|
248 | { |
---|
249 | if(!outOfBoundsRetriesWarningPrinted) |
---|
250 | { |
---|
251 | outOfBoundsRetriesWarningPrinted=true; |
---|
252 | state.output.warning( |
---|
253 | "The limit of 'out-of-range' retries for gaussian mutation was reached."); |
---|
254 | } |
---|
255 | } |
---|
256 | |
---|
257 | public double maxGene(int gene) |
---|
258 | { |
---|
259 | double[] m = maxGenes; |
---|
260 | if (m.length <= gene) |
---|
261 | { |
---|
262 | if (!dynamicInitialSize && !warned) warnAboutGene(gene); |
---|
263 | gene = m.length - 1; |
---|
264 | } |
---|
265 | return m[gene]; |
---|
266 | } |
---|
267 | |
---|
268 | public double minGene(int gene) |
---|
269 | { |
---|
270 | double[] m = minGenes; |
---|
271 | if (m.length <= gene) |
---|
272 | { |
---|
273 | if (!dynamicInitialSize && !warned) warnAboutGene(gene); |
---|
274 | gene = m.length - 1; |
---|
275 | } |
---|
276 | return m[gene]; |
---|
277 | } |
---|
278 | |
---|
279 | public boolean inNumericalTypeRange(double geneVal) |
---|
280 | { |
---|
281 | if (i_prototype instanceof FloatVectorIndividual) |
---|
282 | return (geneVal <= Float.MAX_VALUE && geneVal >= -Float.MAX_VALUE); |
---|
283 | else if (i_prototype instanceof DoubleVectorIndividual) |
---|
284 | return true; // geneVal is valid for all double |
---|
285 | else |
---|
286 | return false; // dunno what the individual is... |
---|
287 | } |
---|
288 | |
---|
289 | public void setup(final EvolutionState state, final Parameter base) |
---|
290 | { |
---|
291 | super.setup(state, base); |
---|
292 | |
---|
293 | Parameter def = defaultBase(); |
---|
294 | |
---|
295 | // create the arrays |
---|
296 | minGenes = new double[genomeSize]; |
---|
297 | maxGenes = new double[genomeSize]; |
---|
298 | |
---|
299 | |
---|
300 | |
---|
301 | // LOADING GLOBAL MIN/MAX GENES |
---|
302 | double minGene = state.parameters.getDoubleWithDefault(base.push(P_MINGENE), def.push(P_MINGENE), 0); |
---|
303 | double maxGene = state.parameters.getDouble(base.push(P_MAXGENE), def.push(P_MAXGENE), minGene); |
---|
304 | if (maxGene < minGene) |
---|
305 | state.output.fatal("FloatVectorSpecies must have a default min-gene which is <= the default max-gene", |
---|
306 | base.push(P_MAXGENE), def.push(P_MAXGENE)); |
---|
307 | |
---|
308 | for (int x = 0; x < genomeSize; x++) |
---|
309 | { |
---|
310 | minGenes[x] = minGene; |
---|
311 | maxGenes[x] = maxGene; |
---|
312 | } |
---|
313 | |
---|
314 | |
---|
315 | // LOADING SEGMENTS |
---|
316 | |
---|
317 | |
---|
318 | //Set number of segments to 0 by default |
---|
319 | int numSegments = 0; |
---|
320 | // Now check to see if segments of genes (genes having the same min and |
---|
321 | // max values) exist |
---|
322 | if (state.parameters.exists(base.push(P_NUM_SEGMENTS), def.push(P_NUM_SEGMENTS))) |
---|
323 | { |
---|
324 | if (dynamicInitialSize) |
---|
325 | state.output.warnOnce("Using dynamic initial sizing, but per-segment min/max gene declarations. This is probably wrong. You probably want to use global min/max declarations.", |
---|
326 | base.push(P_NUM_SEGMENTS), def.push(P_NUM_SEGMENTS)); |
---|
327 | |
---|
328 | numSegments = state.parameters.getIntWithDefault(base.push(P_NUM_SEGMENTS), |
---|
329 | def.push(P_NUM_SEGMENTS), 0); |
---|
330 | |
---|
331 | if(numSegments == 0) |
---|
332 | state.output.warning( |
---|
333 | "The number of genome segments has been defined to be equal to 0.\n" |
---|
334 | + "Hence, no genome segments will be defined.", |
---|
335 | base.push(P_NUM_SEGMENTS), |
---|
336 | def.push(P_NUM_SEGMENTS)); |
---|
337 | else if(numSegments < 0) |
---|
338 | state.output.fatal( |
---|
339 | "Invalid number of genome segments: " + numSegments |
---|
340 | + "\nIt must be a nonnegative value.", |
---|
341 | base.push(P_NUM_SEGMENTS), |
---|
342 | def.push(P_NUM_SEGMENTS)); |
---|
343 | |
---|
344 | //read the type of segment definition using the default start value |
---|
345 | String segmentType = state.parameters.getStringWithDefault(base.push(P_SEGMENT_TYPE), |
---|
346 | def.push(P_SEGMENT_TYPE), P_SEGMENT_START); |
---|
347 | |
---|
348 | if(segmentType.equalsIgnoreCase(P_SEGMENT_START)) |
---|
349 | initializeGenomeSegmentsByStartIndices(state, base, def, numSegments, minGene, maxGene); |
---|
350 | else if(segmentType.equalsIgnoreCase(P_SEGMENT_END)) |
---|
351 | initializeGenomeSegmentsByEndIndices(state, base, def, numSegments, minGene, maxGene); |
---|
352 | else |
---|
353 | state.output.fatal( |
---|
354 | "Invalid specification of genome segment type: " + segmentType |
---|
355 | + "\nThe " + P_SEGMENT_TYPE + " parameter must have the value of " + P_SEGMENT_START + " or " + P_SEGMENT_END, |
---|
356 | base.push(P_SEGMENT_TYPE), |
---|
357 | def.push(P_SEGMENT_TYPE)); |
---|
358 | |
---|
359 | |
---|
360 | } |
---|
361 | |
---|
362 | |
---|
363 | |
---|
364 | // LOADING PER-GENE VALUES |
---|
365 | |
---|
366 | boolean foundStuff = false; |
---|
367 | boolean warnedMin = false; |
---|
368 | boolean warnedMax = false; |
---|
369 | for (int x = 0; x < genomeSize; x++) |
---|
370 | { |
---|
371 | if (!state.parameters.exists(base.push(P_MINGENE).push("" + x), def.push(P_MINGENE).push("" + x))) |
---|
372 | { |
---|
373 | if (foundStuff && !warnedMin) |
---|
374 | { |
---|
375 | state.output.warning( |
---|
376 | "FloatVectorSpecies has missing min-gene values for some genes.\n" |
---|
377 | + "The first one is gene #" + x + ".", |
---|
378 | base.push(P_MINGENE).push("" + x), def.push(P_MINGENE).push("" + x)); |
---|
379 | warnedMin = true; |
---|
380 | } |
---|
381 | } |
---|
382 | else |
---|
383 | { |
---|
384 | if (dynamicInitialSize) |
---|
385 | state.output.warnOnce("Using dynamic initial sizing, but per-gene min/max gene declarations. This is probably wrong. You probably want to use global min/max declarations.", |
---|
386 | base.push(P_MINGENE).push(""+x),base.push(P_MINGENE).push(""+x)); |
---|
387 | |
---|
388 | minGenes[x] = state.parameters.getDoubleWithDefault(base.push(P_MINGENE).push("" + x), |
---|
389 | def.push(P_MINGENE).push("" + x), minGene); |
---|
390 | foundStuff = true; |
---|
391 | } |
---|
392 | |
---|
393 | if (!state.parameters.exists(base.push(P_MAXGENE).push("" + x), def.push(P_MAXGENE).push("" + x))) |
---|
394 | { |
---|
395 | if (foundStuff && !warnedMax) |
---|
396 | { |
---|
397 | state.output.warning( |
---|
398 | "FloatVectorSpecies has missing max-gene values for some genes.\n" |
---|
399 | + "The first one is gene #" + x + ".", |
---|
400 | base.push(P_MAXGENE).push("" + x), def.push(P_MAXGENE).push("" + x)); |
---|
401 | warnedMax = true; |
---|
402 | } |
---|
403 | } |
---|
404 | else |
---|
405 | { |
---|
406 | if (dynamicInitialSize) |
---|
407 | state.output.warnOnce("Using dynamic initial sizing, but per-gene min/max gene declarations. This is probably wrong. You probably want to use global min/max declarations.", |
---|
408 | base.push(P_MINGENE).push(""+x),base.push(P_MINGENE).push(""+x)); |
---|
409 | |
---|
410 | maxGenes[x] = state.parameters.getDoubleWithDefault(base.push(P_MAXGENE).push("" + x), |
---|
411 | def.push(P_MAXGENE).push("" + x), maxGene); |
---|
412 | foundStuff = true; |
---|
413 | } |
---|
414 | } |
---|
415 | |
---|
416 | |
---|
417 | |
---|
418 | |
---|
419 | |
---|
420 | |
---|
421 | // VERIFY |
---|
422 | for(int x=0 ; x < genomeSize; x++) |
---|
423 | { |
---|
424 | if (maxGenes[x] != maxGenes[x]) // uh oh, NaN |
---|
425 | state.output.fatal("FloatVectorSpecies found that max-gene[" + x + "] is NaN"); |
---|
426 | |
---|
427 | if (minGenes[x] != minGenes[x]) // uh oh, NaN |
---|
428 | state.output.fatal("FloatVectorSpecies found that min-gene[" + x + "] is NaN"); |
---|
429 | |
---|
430 | if (maxGenes[x] < minGenes[x]) |
---|
431 | state.output.fatal("FloatVectorSpecies must have a min-gene[" + x + "] which is <= the max-gene[" + x + "]"); |
---|
432 | |
---|
433 | // check to see if these longs are within the data type of the particular individual |
---|
434 | if (!inNumericalTypeRange(minGenes[x])) |
---|
435 | state.output.fatal("This FloatvectorSpecies has a prototype of the kind: " |
---|
436 | + i_prototype.getClass().getName() |
---|
437 | + ", but doesn't have a min-gene[" |
---|
438 | + x |
---|
439 | + "] value within the range of this prototype's genome's data types"); |
---|
440 | if (!inNumericalTypeRange(maxGenes[x])) |
---|
441 | state.output.fatal("This FloatvectorSpecies has a prototype of the kind: " |
---|
442 | + i_prototype.getClass().getName() |
---|
443 | + ", but doesn't have a max-gene[" |
---|
444 | + x |
---|
445 | + "] value within the range of this prototype's genome's data types"); |
---|
446 | } |
---|
447 | |
---|
448 | |
---|
449 | |
---|
450 | |
---|
451 | |
---|
452 | /// MUTATION |
---|
453 | |
---|
454 | |
---|
455 | mutationIsBounded = state.parameters.getBoolean(base.push(P_MUTATION_BOUNDED), def.push(P_MUTATION_BOUNDED), true); |
---|
456 | String mtype = state.parameters.getStringWithDefault(base.push(P_MUTATIONTYPE), def.push(P_MUTATIONTYPE), null); |
---|
457 | mutationType = C_RESET_MUTATION; |
---|
458 | if (mtype == null) |
---|
459 | state.output.warning("No mutation type given for FloatVectorSpecies, assuming 'reset' mutation", |
---|
460 | base.push(P_MUTATIONTYPE), def.push(P_MUTATIONTYPE)); |
---|
461 | else if (mtype.equalsIgnoreCase(V_RESET_MUTATION)) |
---|
462 | mutationType = C_RESET_MUTATION; // redundant |
---|
463 | else if (mtype.equalsIgnoreCase(V_POLYNOMIAL_MUTATION)) |
---|
464 | mutationType = C_POLYNOMIAL_MUTATION; // redundant |
---|
465 | else if (mtype.equalsIgnoreCase(V_GAUSS_MUTATION)) |
---|
466 | mutationType = C_GAUSS_MUTATION; |
---|
467 | else |
---|
468 | state.output.fatal("FloatVectorSpecies given a bad mutation type: " |
---|
469 | + mtype, base.push(P_MUTATIONTYPE), def.push(P_MUTATIONTYPE)); |
---|
470 | |
---|
471 | if (mutationType == C_POLYNOMIAL_MUTATION) |
---|
472 | { |
---|
473 | mutationDistributionIndex = state.parameters.getInt(base.push(P_MUTATION_DISTRIBUTION_INDEX), def.push(P_MUTATION_DISTRIBUTION_INDEX), 0); |
---|
474 | if (mutationDistributionIndex < 0) |
---|
475 | state.output.fatal("If FloatVectorSpecies is going to use polynomial mutation, the distribution index must be defined and >= 0.", |
---|
476 | base.push(P_MUTATION_DISTRIBUTION_INDEX), def.push(P_MUTATION_DISTRIBUTION_INDEX)); |
---|
477 | polynomialIsAlternative = state.parameters.getBoolean(base.push(P_POLYNOMIAL_ALTERNATIVE), def.push(P_POLYNOMIAL_ALTERNATIVE), true); |
---|
478 | |
---|
479 | outOfBoundsRetries = state.parameters.getIntWithDefault(base.push(P_OUTOFBOUNDS_RETRIES), def.push(P_OUTOFBOUNDS_RETRIES), outOfBoundsRetries); |
---|
480 | if(outOfBoundsRetries<0) |
---|
481 | { |
---|
482 | state.output.fatal( |
---|
483 | "If it's going to use polynomial mutation, FloatvectorSpecies must have a positive number of out-of-bounds retries or 0 (for don't give up). " + |
---|
484 | "This is even the case if doing so-called \"bounded\" polynomial mutation, which auto-bounds anyway, or if the mutation is unbounded. " + |
---|
485 | "In either case, just provide an arbitrary value, which will be ignored.", |
---|
486 | base.push(P_OUTOFBOUNDS_RETRIES), def.push(P_OUTOFBOUNDS_RETRIES)); |
---|
487 | } |
---|
488 | } |
---|
489 | |
---|
490 | if (mutationType == C_GAUSS_MUTATION) |
---|
491 | { |
---|
492 | gaussMutationStdev = state.parameters.getDouble(base.push(P_STDEV),def.push(P_STDEV), 0); |
---|
493 | if (gaussMutationStdev <= 0) |
---|
494 | state.output.fatal("If it's going to use gaussian mutation, FloatvectorSpecies must have a strictly positive standard deviation", |
---|
495 | base.push(P_STDEV), def.push(P_STDEV)); |
---|
496 | |
---|
497 | outOfBoundsRetries = state.parameters.getIntWithDefault(base.push(P_OUTOFBOUNDS_RETRIES), def.push(P_OUTOFBOUNDS_RETRIES), outOfBoundsRetries); |
---|
498 | if(outOfBoundsRetries<0) |
---|
499 | { |
---|
500 | state.output.fatal( |
---|
501 | "If it's going to use gaussian mutation, FloatvectorSpecies must have a positive number of out-of-bounds retries or 0 (for don't give up). " + |
---|
502 | "This is even the case if the mutation is unbounded. In that case, just provide an arbitrary value, which will be ignored.", |
---|
503 | base.push(P_OUTOFBOUNDS_RETRIES), def.push(P_OUTOFBOUNDS_RETRIES)); |
---|
504 | } |
---|
505 | } |
---|
506 | /* |
---|
507 | //Debugging |
---|
508 | for(int i = 0; i < minGenes.length; i++) |
---|
509 | System.out.println("Min: " + minGenes[i] + ", Max: " + maxGenes[i]); |
---|
510 | */ |
---|
511 | } |
---|
512 | |
---|
513 | |
---|
514 | private void initializeGenomeSegmentsByStartIndices(final EvolutionState state, |
---|
515 | final Parameter base, |
---|
516 | final Parameter def, |
---|
517 | int numSegments, |
---|
518 | double minGene, double maxGene) |
---|
519 | { |
---|
520 | boolean warnedMin = false; |
---|
521 | boolean warnedMax = false; |
---|
522 | double currentSegmentMinGeneValue = Double.MAX_VALUE; |
---|
523 | double currentSegmentMaxGeneValue = Double.MIN_VALUE; |
---|
524 | |
---|
525 | //loop in reverse order |
---|
526 | int previousSegmentEnd = genomeSize; |
---|
527 | int currentSegmentEnd = 0; |
---|
528 | |
---|
529 | for (int i = numSegments - 1; i >= 0; i--) |
---|
530 | { |
---|
531 | //check if the segment data exist |
---|
532 | if (state.parameters.exists(base.push(P_SEGMENT).push(""+i).push(P_SEGMENT_START), |
---|
533 | def.push(P_SEGMENT).push(""+i).push(P_SEGMENT_START))) |
---|
534 | { |
---|
535 | //Read the index of the end gene specifying current segment |
---|
536 | currentSegmentEnd = state.parameters.getInt(base.push(P_SEGMENT).push(""+i).push(P_SEGMENT_START), |
---|
537 | def.push(P_SEGMENT).push(""+i).push(P_SEGMENT_START)); |
---|
538 | |
---|
539 | } |
---|
540 | else |
---|
541 | { |
---|
542 | state.output.fatal("Genome segment " + i + " has not been defined!" + |
---|
543 | "\nYou must specify start indices for " + numSegments + " segment(s)", |
---|
544 | base.push(P_SEGMENT).push(""+i).push(P_SEGMENT_START), |
---|
545 | base.push(P_SEGMENT).push(""+i).push(P_SEGMENT_START)); |
---|
546 | } |
---|
547 | |
---|
548 | //check if the start index is valid |
---|
549 | if(currentSegmentEnd >= previousSegmentEnd || currentSegmentEnd < 0) |
---|
550 | state.output.fatal( |
---|
551 | "Invalid start index value for segment " + i + ": " + currentSegmentEnd |
---|
552 | + "\nThe value must be smaller than " + previousSegmentEnd + |
---|
553 | " and greater than or equal to " + 0); |
---|
554 | |
---|
555 | //check if the index of the first segment is equal to 0 |
---|
556 | if(i == 0 && currentSegmentEnd != 0) |
---|
557 | state.output.fatal( |
---|
558 | "Invalid start index value for the first segment " + i + ": " + currentSegmentEnd |
---|
559 | + "\nThe value must be equal to " + 0); |
---|
560 | |
---|
561 | |
---|
562 | //get min and max values of genes in this segment |
---|
563 | if (!state.parameters.exists(base.push(P_SEGMENT).push(""+i).push(P_MINGENE), |
---|
564 | base.push(P_SEGMENT).push(""+i).push(P_MINGENE))) |
---|
565 | { |
---|
566 | if (!warnedMin) |
---|
567 | { |
---|
568 | state.output.warning( |
---|
569 | "IntegerVectorSpecies has missing min-gene values for some segments.\n" |
---|
570 | + "The first segment is #" + i + ".", |
---|
571 | base.push(P_SEGMENT).push(""+i), |
---|
572 | base.push(P_SEGMENT).push(""+i)); |
---|
573 | warnedMin = true; |
---|
574 | } |
---|
575 | |
---|
576 | //the min-gene value has not been defined for this segment so assume the global min value |
---|
577 | currentSegmentMinGeneValue = minGene; |
---|
578 | } |
---|
579 | else //get the min value for this segment |
---|
580 | { |
---|
581 | currentSegmentMinGeneValue = state.parameters.getDoubleWithDefault( |
---|
582 | base.push(P_SEGMENT).push(""+i).push(P_MINGENE), |
---|
583 | base.push(P_SEGMENT).push(""+i).push(P_MINGENE), |
---|
584 | minGene); |
---|
585 | |
---|
586 | //check if the value is in range |
---|
587 | if (!inNumericalTypeRange(currentSegmentMinGeneValue)) |
---|
588 | state.output |
---|
589 | .error( |
---|
590 | "This IntegerVectorSpecies has a prototype of the kind: " |
---|
591 | + i_prototype.getClass() |
---|
592 | .getName() |
---|
593 | + ", but doesn't have a min-gene " |
---|
594 | + " value for segment " + i |
---|
595 | + " within the range of this prototype's genome's data types", |
---|
596 | base.push(P_SEGMENT).push(""+i).push(P_MINGENE), |
---|
597 | base.push(P_SEGMENT).push(""+i).push(P_MINGENE)); |
---|
598 | |
---|
599 | } |
---|
600 | |
---|
601 | if (!state.parameters.exists(base.push(P_SEGMENT).push(""+i).push(P_MAXGENE), |
---|
602 | base.push(P_SEGMENT).push(""+i).push(P_MAXGENE))) |
---|
603 | { |
---|
604 | if (!warnedMax) |
---|
605 | { |
---|
606 | state.output.warning( |
---|
607 | "IntegerVectorSpecies has missing max-gene values for some segments.\n" |
---|
608 | + "The first segment is #" + i + ".", |
---|
609 | base.push(P_SEGMENT).push(""+i), |
---|
610 | base.push(P_SEGMENT).push(""+i)); |
---|
611 | warnedMax = true; |
---|
612 | } |
---|
613 | |
---|
614 | //the max-gen value has not been defined for this segment so assume the global max value |
---|
615 | currentSegmentMaxGeneValue = maxGene; |
---|
616 | |
---|
617 | } |
---|
618 | else //get the max value for this segment |
---|
619 | { |
---|
620 | currentSegmentMaxGeneValue = state.parameters.getDoubleWithDefault( |
---|
621 | base.push(P_SEGMENT).push(""+i).push(P_MAXGENE), |
---|
622 | base.push(P_SEGMENT).push(""+i).push(P_MAXGENE), |
---|
623 | maxGene); |
---|
624 | |
---|
625 | //check if the value is in range |
---|
626 | if (!inNumericalTypeRange(currentSegmentMaxGeneValue)) |
---|
627 | state.output |
---|
628 | .fatal( |
---|
629 | "This IntegerVectorSpecies has a prototype of the kind: " |
---|
630 | + i_prototype.getClass() |
---|
631 | .getName() |
---|
632 | + ", but doesn't have a max-gene " |
---|
633 | + " value for segment " + i |
---|
634 | + " within the range of this prototype's genome's data types", |
---|
635 | base.push(P_SEGMENT).push(""+i).push(P_MAXGENE), |
---|
636 | base.push(P_SEGMENT).push(""+i).push(P_MAXGENE)); |
---|
637 | } |
---|
638 | |
---|
639 | //check is min is smaller than or equal to max |
---|
640 | if (currentSegmentMaxGeneValue < currentSegmentMinGeneValue) |
---|
641 | state.output.fatal( |
---|
642 | "IntegerVectorSpecies must have a min-gene value for segment " |
---|
643 | + i + " which is <= the max-gene value", |
---|
644 | base.push(P_SEGMENT).push(""+i).push(P_MAXGENE), |
---|
645 | base.push(P_SEGMENT).push(""+i).push(P_MAXGENE)); |
---|
646 | |
---|
647 | |
---|
648 | //and assign min and max values for all genes in this segment |
---|
649 | for(int j = previousSegmentEnd-1; j >= currentSegmentEnd; j--) |
---|
650 | { |
---|
651 | minGenes[j] = currentSegmentMinGeneValue; |
---|
652 | maxGenes[j] = currentSegmentMaxGeneValue; |
---|
653 | } |
---|
654 | |
---|
655 | previousSegmentEnd = currentSegmentEnd; |
---|
656 | |
---|
657 | } |
---|
658 | |
---|
659 | } |
---|
660 | |
---|
661 | private void initializeGenomeSegmentsByEndIndices(final EvolutionState state, |
---|
662 | final Parameter base, |
---|
663 | final Parameter def, |
---|
664 | int numSegments, |
---|
665 | double minGene, double maxGene) |
---|
666 | { |
---|
667 | boolean warnedMin = false; |
---|
668 | boolean warnedMax = false; |
---|
669 | double currentSegmentMinGeneValue = Double.MAX_VALUE; |
---|
670 | double currentSegmentMaxGeneValue = Double.MIN_VALUE; |
---|
671 | |
---|
672 | int previousSegmentEnd = -1; |
---|
673 | int currentSegmentEnd = 0; |
---|
674 | // iterate over segments and set genes values for each segment |
---|
675 | for (int i = 0; i < numSegments; i++) |
---|
676 | { |
---|
677 | //check if the segment data exist |
---|
678 | if (state.parameters.exists(base.push(P_SEGMENT).push(""+i).push(P_SEGMENT_END), def.push(P_SEGMENT).push(""+i).push(P_SEGMENT_END))) |
---|
679 | { |
---|
680 | //Read the index of the end gene specifying current segment |
---|
681 | currentSegmentEnd = state.parameters.getInt(base.push(P_SEGMENT).push(""+i).push(P_SEGMENT_END), |
---|
682 | def.push(P_SEGMENT).push(""+i).push(P_SEGMENT_END)); |
---|
683 | |
---|
684 | } |
---|
685 | else |
---|
686 | { |
---|
687 | state.output.fatal("Genome segment " + i + " has not been defined!" + |
---|
688 | "\nYou must specify end indices for " + numSegments + " segment(s)", |
---|
689 | base.push(P_SEGMENT).push(""+i).push(P_SEGMENT_END), |
---|
690 | base.push(P_SEGMENT).push(""+i).push(P_SEGMENT_END)); |
---|
691 | } |
---|
692 | |
---|
693 | //check if the end index is valid |
---|
694 | if(currentSegmentEnd <= previousSegmentEnd || currentSegmentEnd >= genomeSize) |
---|
695 | state.output.fatal( |
---|
696 | "Invalid end index value for segment " + i + ": " + currentSegmentEnd |
---|
697 | + "\nThe value must be greater than " + previousSegmentEnd + |
---|
698 | " and smaller than " + genomeSize); |
---|
699 | |
---|
700 | //check if the index of the final segment is equal to the genomeSize |
---|
701 | if(i == numSegments - 1 && currentSegmentEnd != (genomeSize-1)) |
---|
702 | state.output.fatal( |
---|
703 | "Invalid end index value for the last segment " + i + ": " + currentSegmentEnd |
---|
704 | + "\nThe value must be equal to the index of the last gene in the genome: " + (genomeSize-1)); |
---|
705 | |
---|
706 | |
---|
707 | //get min and max values of genes in this segment |
---|
708 | if (!state.parameters.exists(base.push(P_SEGMENT).push(""+i).push(P_MINGENE), |
---|
709 | base.push(P_SEGMENT).push(""+i).push(P_MINGENE))) |
---|
710 | { |
---|
711 | if (!warnedMin) |
---|
712 | { |
---|
713 | state.output.warning( |
---|
714 | "IntegerVectorSpecies has missing min-gene values for some segments.\n" |
---|
715 | + "The first segment is #" + i + ".", |
---|
716 | base.push(P_SEGMENT).push(""+i), |
---|
717 | base.push(P_SEGMENT).push(""+i)); |
---|
718 | warnedMin = true; |
---|
719 | } |
---|
720 | |
---|
721 | //the min-gene value has not been defined for this segment so assume the global min value |
---|
722 | currentSegmentMinGeneValue = minGene; |
---|
723 | } |
---|
724 | else //get the min value for this segment |
---|
725 | { |
---|
726 | currentSegmentMinGeneValue = state.parameters.getDoubleWithDefault( |
---|
727 | base.push(P_SEGMENT).push(""+i).push(P_MINGENE), |
---|
728 | base.push(P_SEGMENT).push(""+i).push(P_MINGENE), |
---|
729 | minGene); |
---|
730 | |
---|
731 | //check if the value is in range |
---|
732 | if (!inNumericalTypeRange(currentSegmentMinGeneValue)) |
---|
733 | state.output |
---|
734 | .error( |
---|
735 | "This IntegerVectorSpecies has a prototype of the kind: " |
---|
736 | + i_prototype.getClass() |
---|
737 | .getName() |
---|
738 | + ", but doesn't have a min-gene " |
---|
739 | + " value for segment " + i |
---|
740 | + " within the range of this prototype's genome's data types", |
---|
741 | base.push(P_SEGMENT).push(""+i).push(P_MINGENE), |
---|
742 | base.push(P_SEGMENT).push(""+i).push(P_MINGENE)); |
---|
743 | |
---|
744 | } |
---|
745 | |
---|
746 | if (!state.parameters.exists(base.push(P_SEGMENT).push(""+i).push(P_MAXGENE), |
---|
747 | base.push(P_SEGMENT).push(""+i).push(P_MAXGENE))) |
---|
748 | { |
---|
749 | if (!warnedMax) |
---|
750 | { |
---|
751 | state.output.warning( |
---|
752 | "IntegerVectorSpecies has missing max-gene values for some segments.\n" |
---|
753 | + "The first segment is #" + i + ".", |
---|
754 | base.push(P_SEGMENT).push(""+i), |
---|
755 | base.push(P_SEGMENT).push(""+i)); |
---|
756 | warnedMax = true; |
---|
757 | } |
---|
758 | |
---|
759 | //the max-gen value has not been defined for this segment so assume the global max value |
---|
760 | currentSegmentMaxGeneValue = maxGene; |
---|
761 | |
---|
762 | } |
---|
763 | else //get the max value for this segment |
---|
764 | { |
---|
765 | currentSegmentMaxGeneValue = state.parameters.getDoubleWithDefault( |
---|
766 | base.push(P_SEGMENT).push(""+i).push(P_MAXGENE), |
---|
767 | base.push(P_SEGMENT).push(""+i).push(P_MAXGENE), |
---|
768 | maxGene); |
---|
769 | |
---|
770 | //check if the value is in range |
---|
771 | if (!inNumericalTypeRange(currentSegmentMaxGeneValue)) |
---|
772 | state.output |
---|
773 | .fatal( |
---|
774 | "This IntegerVectorSpecies has a prototype of the kind: " |
---|
775 | + i_prototype.getClass() |
---|
776 | .getName() |
---|
777 | + ", but doesn't have a max-gene " |
---|
778 | + " value for segment " + i |
---|
779 | + " within the range of this prototype's genome's data types", |
---|
780 | base.push(P_SEGMENT).push(""+i).push(P_MAXGENE), |
---|
781 | base.push(P_SEGMENT).push(""+i).push(P_MAXGENE)); |
---|
782 | } |
---|
783 | |
---|
784 | //check is min is smaller than or equal to max |
---|
785 | if (currentSegmentMaxGeneValue < currentSegmentMinGeneValue) |
---|
786 | state.output.fatal( |
---|
787 | "IntegerVectorSpecies must have a min-gene value for segment " |
---|
788 | + i + " which is <= the max-gene value", |
---|
789 | base.push(P_SEGMENT).push(""+i).push(P_MAXGENE), |
---|
790 | base.push(P_SEGMENT).push(""+i).push(P_MAXGENE)); |
---|
791 | |
---|
792 | |
---|
793 | //and assign min and max values for all genes in this segment |
---|
794 | for(int j = previousSegmentEnd+1; j <= currentSegmentEnd; j++) |
---|
795 | { |
---|
796 | minGenes[j] = currentSegmentMinGeneValue; |
---|
797 | maxGenes[j] = currentSegmentMaxGeneValue; |
---|
798 | } |
---|
799 | |
---|
800 | previousSegmentEnd = currentSegmentEnd; |
---|
801 | |
---|
802 | } |
---|
803 | } |
---|
804 | } |
---|