[6152] | 1 | /* |
---|
| 2 | Copyright 2006 by Sean Luke |
---|
| 3 | Licensed under the Academic Free License version 3.0 |
---|
| 4 | See the file "LICENSE" for more information |
---|
| 5 | */ |
---|
| 6 | |
---|
| 7 | package ec.multiobjective; |
---|
| 8 | |
---|
| 9 | import java.io.*; |
---|
| 10 | import ec.util.DecodeReturn; |
---|
| 11 | import ec.util.Parameter; |
---|
| 12 | import ec.util.Code; |
---|
| 13 | import ec.Fitness; |
---|
| 14 | import ec.EvolutionState; |
---|
| 15 | import java.util.*; |
---|
| 16 | import ec.*; |
---|
| 17 | |
---|
| 18 | /* |
---|
| 19 | * MultiObjectiveFitness.java |
---|
| 20 | * |
---|
| 21 | * Created: Tue Aug 10 20:27:38 1999 |
---|
| 22 | * By: Sean Luke |
---|
| 23 | */ |
---|
| 24 | |
---|
| 25 | /** |
---|
| 26 | * MultiObjectiveFitness is a subclass of Fitness which implements basic |
---|
| 27 | * multi-objective mechanisms suitable for being used with a variety of |
---|
| 28 | * multi-objective selection mechanisms, including ones using pareto-optimality. |
---|
| 29 | * |
---|
| 30 | * <p> |
---|
| 31 | * The object contains two items: an array of floating point values representing |
---|
| 32 | * the various multiple fitnesses, and a flag (maximize) indicating whether |
---|
| 33 | * higher is considered better. By default, isIdealFitness() always returns |
---|
| 34 | * false; you might want to override that, though it'd be unusual -- what is the |
---|
| 35 | * ideal fitness from the perspective of a pareto front? |
---|
| 36 | * |
---|
| 37 | * <p> |
---|
| 38 | * The object also contains maximum and minimum fitness values suggested for the |
---|
| 39 | * problem, on a per-objective basis. By default the maximum values are all 1.0 |
---|
| 40 | * and the minimum values are all 0.0, but you can change these. Note that |
---|
| 41 | * maximum does not mean "best" unless maximize is true. |
---|
| 42 | * |
---|
| 43 | * <p>The class also contains utility methods or computing pareto dominance, |
---|
| 44 | * Pareto Fronts and Pareto Front Ranks, and distance in multiobjective space. |
---|
| 45 | * The default comparison operators use Pareto Dominance, though this is often |
---|
| 46 | * overridden by subclasses. |
---|
| 47 | * |
---|
| 48 | * <p>The fitness() method returns the maximum of the fitness values, which is |
---|
| 49 | * clearly nonsensical: you should not be using this method. |
---|
| 50 | * |
---|
| 51 | * <p>Subclasses of this class may add certain auxiliary fitness measures which |
---|
| 52 | * are printed out by MultiObjectiveStatistics along with the multiple objectives. |
---|
| 53 | * To have these values printed out, override the getAuxiliaryFitnessNames() |
---|
| 54 | * and getAuxiliaryFitnessValues() methods. |
---|
| 55 | * |
---|
| 56 | * <p> |
---|
| 57 | * <b>Parameters</b><br> |
---|
| 58 | * <table> |
---|
| 59 | * <tr> |
---|
| 60 | * <td valign=top><i>base</i>.<tt>num-objectives</tt><br> |
---|
| 61 | * (else)<tt>multi.num-objectives</tt><br> |
---|
| 62 | * <font size=-1>int >= 1</font></td> |
---|
| 63 | * <td valign=top>(the number of fitnesses in the objectives array)</td> |
---|
| 64 | * </tr> |
---|
| 65 | * |
---|
| 66 | * <tr> |
---|
| 67 | * <td valign=top><i>base</i>.<tt>maximize</tt><br> |
---|
| 68 | * <font size=-1> bool = <tt>true</tt> (default) or <tt>false</tt></font></td> |
---|
| 69 | * <td valign=top>(are higher values considered "better"?) |
---|
| 70 | * </table> |
---|
| 71 | * |
---|
| 72 | * <tr> |
---|
| 73 | * <td valign=top><i>base</i>.<tt>max</tt><br> |
---|
| 74 | * <font size=-1> float (<tt>1.0</tt> default)</font></td> |
---|
| 75 | * <td valign=top>(maximum fitness value for all objectives)</table> |
---|
| 76 | * |
---|
| 77 | * <tr> |
---|
| 78 | * <td valign=top><i>base</i>.<tt>max</tt>.<i>i</i><br> |
---|
| 79 | * <font size=-1> float (<tt>1.0</tt> default)</font></td> |
---|
| 80 | * <td valign=top>(maximum fitness value for objective <i>i</i>. Overrides the |
---|
| 81 | * all-objective maximum fitness.)</table> |
---|
| 82 | * |
---|
| 83 | * <tr> |
---|
| 84 | * <td valign=top><i>base</i>.<tt>min</tt><br> |
---|
| 85 | * <font size=-1> float (<tt>0.0</tt> (default)</font></td> |
---|
| 86 | * <td valign=top>(minimum fitness value for all objectives)</table> |
---|
| 87 | * |
---|
| 88 | * <tr> |
---|
| 89 | * <td valign=top><i>base</i>.<tt>min</tt>.<i>i</i><br> |
---|
| 90 | * <font size=-1> float = <tt>0.0</tt> (default)</font></td> |
---|
| 91 | * <td valign=top>(minimum fitness value for objective <i>i</i>. Overrides the |
---|
| 92 | * all-objective minimum fitness.)</table> |
---|
| 93 | * |
---|
| 94 | * <p> |
---|
| 95 | * <b>Default Base</b><br> |
---|
| 96 | * multi.fitness |
---|
| 97 | * |
---|
| 98 | * @author Sean Luke |
---|
| 99 | * @version 1.1 |
---|
| 100 | */ |
---|
| 101 | |
---|
| 102 | public class MultiObjectiveFitness extends Fitness |
---|
| 103 | { |
---|
| 104 | public static final String MULTI_FITNESS_POSTAMBLE = "["; |
---|
| 105 | public static final String FITNESS_POSTAMBLE = "]"; |
---|
| 106 | |
---|
| 107 | /** parameter for size of objectives */ |
---|
| 108 | public static final String P_NUMOBJECTIVES = "num-objectives"; |
---|
| 109 | |
---|
| 110 | /** parameter for max fitness values */ |
---|
| 111 | public static final String P_MAXOBJECTIVES = "max"; |
---|
| 112 | |
---|
| 113 | /** parameter for min fitness values */ |
---|
| 114 | public static final String P_MINOBJECTIVES = "min"; |
---|
| 115 | |
---|
| 116 | /** Is higher better? */ |
---|
| 117 | public static final String P_MAXIMIZE = "maximize"; |
---|
| 118 | |
---|
| 119 | /** Desired maximum fitness values. By default these are 1.0. Shared. */ |
---|
| 120 | public float[] maxObjective; |
---|
| 121 | |
---|
| 122 | /** Desired minimum fitness values. By default these are 0.0. Shared. */ |
---|
| 123 | public float[] minObjective; |
---|
| 124 | |
---|
| 125 | /** The various fitnesses. */ |
---|
| 126 | protected float[] objectives; // values range from 0 (worst) to 1 INCLUSIVE |
---|
| 127 | protected boolean maximize = true; |
---|
| 128 | |
---|
| 129 | /** Returns auxilliary fitness value names to be printed by the statistics object. |
---|
| 130 | By default, an empty array is returned, but various algorithms may override this to provide additional columns. |
---|
| 131 | */ |
---|
| 132 | public String[] getAuxilliaryFitnessNames() { return new String[] { }; } |
---|
| 133 | |
---|
| 134 | /** Returns auxilliary fitness values to be printed by the statistics object. |
---|
| 135 | By default, an empty array is returned, but various algorithms may override this to provide additional columns. |
---|
| 136 | */ |
---|
| 137 | public double[] getAuxilliaryFitnessValues() { return new double[] { }; } |
---|
| 138 | |
---|
| 139 | public boolean isMaximizing() |
---|
| 140 | { |
---|
| 141 | return maximize; |
---|
| 142 | } |
---|
| 143 | |
---|
| 144 | |
---|
| 145 | public int getNumObjectives() { return objectives.length; } |
---|
| 146 | |
---|
| 147 | /** |
---|
| 148 | * Returns the objectives as an array. Note that this is the *actual array*. |
---|
| 149 | * Though you could set values in this array, you should NOT do this -- |
---|
| 150 | * rather, set them using setObjectives(). |
---|
| 151 | */ |
---|
| 152 | public float[] getObjectives() |
---|
| 153 | { |
---|
| 154 | return objectives; |
---|
| 155 | } |
---|
| 156 | |
---|
| 157 | public float getObjective(int i) |
---|
| 158 | { |
---|
| 159 | return objectives[i]; |
---|
| 160 | } |
---|
| 161 | |
---|
| 162 | public void setObjectives(final EvolutionState state, float[] newObjectives) |
---|
| 163 | { |
---|
| 164 | if (newObjectives == null) |
---|
| 165 | { |
---|
| 166 | state.output.fatal("Null objective array provided to MultiObjectiveFitness."); |
---|
| 167 | } |
---|
| 168 | if (newObjectives.length != objectives.length) |
---|
| 169 | { |
---|
| 170 | state.output.fatal("New objective array length does not match current length."); |
---|
| 171 | } |
---|
| 172 | for (int i = 0; i < newObjectives.length; i++) |
---|
| 173 | { |
---|
| 174 | float _f = newObjectives[i]; |
---|
| 175 | if (_f == Float.POSITIVE_INFINITY || _f == Float.NEGATIVE_INFINITY || Float.isNaN(_f)) |
---|
| 176 | { |
---|
| 177 | state.output.warning("Bad objective #" + i + ": " + _f + ", setting to worst value for that objective."); |
---|
| 178 | if (maximize) |
---|
| 179 | newObjectives[i] = minObjective[i]; |
---|
| 180 | else |
---|
| 181 | newObjectives[i] = maxObjective[i]; |
---|
| 182 | } |
---|
| 183 | } |
---|
| 184 | objectives = newObjectives; |
---|
| 185 | } |
---|
| 186 | |
---|
| 187 | public Parameter defaultBase() |
---|
| 188 | { |
---|
| 189 | return MultiObjectiveDefaults.base().push(P_FITNESS); |
---|
| 190 | } |
---|
| 191 | |
---|
| 192 | public Object clone() |
---|
| 193 | { |
---|
| 194 | MultiObjectiveFitness f = (MultiObjectiveFitness) (super.clone()); |
---|
| 195 | f.objectives = (float[]) (objectives.clone()); // cloning an array |
---|
| 196 | |
---|
| 197 | // note that we do NOT clone max and min fitness -- they're shared |
---|
| 198 | return f; |
---|
| 199 | } |
---|
| 200 | |
---|
| 201 | /** |
---|
| 202 | * Returns the Max() of objectives, which adheres to Fitness.java's protocol |
---|
| 203 | * for this method. Though you should not rely on a selection or statistics |
---|
| 204 | * method which requires this. |
---|
| 205 | */ |
---|
| 206 | public float fitness() |
---|
| 207 | { |
---|
| 208 | float fit = objectives[0]; |
---|
| 209 | for (int x = 1; x < objectives.length; x++) |
---|
| 210 | if (fit < objectives[x]) |
---|
| 211 | fit = objectives[x]; |
---|
| 212 | return fit; |
---|
| 213 | } |
---|
| 214 | |
---|
| 215 | /** |
---|
| 216 | * Sets up. This must be called at least once in the prototype before |
---|
| 217 | * instantiating any fitnesses that will actually be used in evolution. |
---|
| 218 | */ |
---|
| 219 | |
---|
| 220 | public void setup(EvolutionState state, Parameter base) |
---|
| 221 | { |
---|
| 222 | super.setup(state, base); // unnecessary really |
---|
| 223 | |
---|
| 224 | Parameter def = defaultBase(); |
---|
| 225 | int numFitnesses; |
---|
| 226 | |
---|
| 227 | numFitnesses = state.parameters.getInt(base.push(P_NUMOBJECTIVES), def.push(P_NUMOBJECTIVES), 0); |
---|
| 228 | if (numFitnesses <= 0) |
---|
| 229 | state.output.fatal("The number of objectives must be an integer >= 1.", base.push(P_NUMOBJECTIVES), def.push(P_NUMOBJECTIVES)); |
---|
| 230 | |
---|
| 231 | maximize = state.parameters.getBoolean(base.push(P_MAXIMIZE), def.push(P_MAXIMIZE), true); |
---|
| 232 | |
---|
| 233 | objectives = new float[numFitnesses]; |
---|
| 234 | maxObjective = new float[numFitnesses]; |
---|
| 235 | minObjective = new float[numFitnesses]; |
---|
| 236 | |
---|
| 237 | for (int i = 0; i < numFitnesses; i++) |
---|
| 238 | { |
---|
| 239 | // load default globals |
---|
| 240 | minObjective[i] = state.parameters.getFloatWithDefault(base.push(P_MINOBJECTIVES), def.push(P_MINOBJECTIVES), 0.0f); |
---|
| 241 | maxObjective[i] = state.parameters.getFloatWithDefault(base.push(P_MAXOBJECTIVES), def.push(P_MAXOBJECTIVES), 1.0f); |
---|
| 242 | |
---|
| 243 | // load specifics if any |
---|
| 244 | minObjective[i] = state.parameters.getFloatWithDefault(base.push(P_MINOBJECTIVES).push("" + i), def.push(P_MINOBJECTIVES).push("" + i), minObjective[i]); |
---|
| 245 | maxObjective[i] = state.parameters.getFloatWithDefault(base.push(P_MAXOBJECTIVES).push("" + i), def.push(P_MAXOBJECTIVES).push("" + i), maxObjective[i]); |
---|
| 246 | |
---|
| 247 | // test for validity |
---|
| 248 | if (minObjective[i] >= maxObjective[i]) |
---|
| 249 | state.output.error("For objective " + i + "the min fitness must be strictly less than the max fitness."); |
---|
| 250 | } |
---|
| 251 | state.output.exitIfErrors(); |
---|
| 252 | } |
---|
| 253 | |
---|
| 254 | /** |
---|
| 255 | * Returns true if this fitness is the "ideal" fitness. Default always |
---|
| 256 | * returns false. You may want to override this. |
---|
| 257 | */ |
---|
| 258 | public boolean isIdealFitness() |
---|
| 259 | { |
---|
| 260 | return false; |
---|
| 261 | } |
---|
| 262 | |
---|
| 263 | /** |
---|
| 264 | * Returns true if I'm equivalent in fitness (neither better nor worse) to |
---|
| 265 | * _fitness. The rule I'm using is this: If one of us is better in one or |
---|
| 266 | * more criteria, and we are equal in the others, then equivalentTo is |
---|
| 267 | * false. If each of us is better in one or more criteria each, or we are |
---|
| 268 | * equal in all criteria, then equivalentTo is true. Multiobjective optimization algorithms may |
---|
| 269 | * choose to override this to do something else. |
---|
| 270 | */ |
---|
| 271 | |
---|
| 272 | public boolean equivalentTo(Fitness _fitness) |
---|
| 273 | { |
---|
| 274 | MultiObjectiveFitness other = (MultiObjectiveFitness) _fitness; |
---|
| 275 | boolean abeatsb = false; |
---|
| 276 | boolean bbeatsa = false; |
---|
| 277 | |
---|
| 278 | if (maximize != other.maximize) |
---|
| 279 | throw new RuntimeException( |
---|
| 280 | "Attempt made to compare two multiobjective fitnesses; but one expects higher values to be better and the other expectes lower values to be better."); |
---|
| 281 | if (objectives.length != other.objectives.length) |
---|
| 282 | throw new RuntimeException("Attempt made to compare two multiobjective fitnesses; but they have different numbers of objectives."); |
---|
| 283 | if (maximize) |
---|
| 284 | { |
---|
| 285 | for (int x = 0; x < objectives.length; x++) |
---|
| 286 | { |
---|
| 287 | if (objectives[x] > other.objectives[x]) |
---|
| 288 | abeatsb = true; |
---|
| 289 | if (objectives[x] < other.objectives[x]) |
---|
| 290 | bbeatsa = true; |
---|
| 291 | if (abeatsb && bbeatsa) |
---|
| 292 | return true; |
---|
| 293 | } |
---|
| 294 | } |
---|
| 295 | else |
---|
| 296 | // lower is better |
---|
| 297 | { |
---|
| 298 | for (int x = 0; x < objectives.length; x++) |
---|
| 299 | { |
---|
| 300 | if (objectives[x] < other.objectives[x]) |
---|
| 301 | abeatsb = true; |
---|
| 302 | if (objectives[x] > other.objectives[x]) |
---|
| 303 | bbeatsa = true; |
---|
| 304 | if (abeatsb && bbeatsa) |
---|
| 305 | return true; |
---|
| 306 | } |
---|
| 307 | } |
---|
| 308 | if (abeatsb || bbeatsa) |
---|
| 309 | return false; |
---|
| 310 | return true; |
---|
| 311 | } |
---|
| 312 | |
---|
| 313 | /** |
---|
| 314 | * Returns true if I'm better than _fitness. The DEFAULT rule I'm using is this: if |
---|
| 315 | * I am better in one or more criteria, and we are equal in the others, then |
---|
| 316 | * betterThan is true, else it is false. Multiobjective optimization algorithms may |
---|
| 317 | * choose to override this to do something else. |
---|
| 318 | */ |
---|
| 319 | |
---|
| 320 | public boolean betterThan(Fitness fitness) |
---|
| 321 | { |
---|
| 322 | return paretoDominates((MultiObjectiveFitness)fitness); |
---|
| 323 | } |
---|
| 324 | |
---|
| 325 | /** |
---|
| 326 | * Returns true if I'm better than _fitness. The rule I'm using is this: if |
---|
| 327 | * I am better in one or more criteria, and we are equal in the others, then |
---|
| 328 | * betterThan is true, else it is false. |
---|
| 329 | */ |
---|
| 330 | |
---|
| 331 | public boolean paretoDominates(MultiObjectiveFitness other) |
---|
| 332 | { |
---|
| 333 | boolean abeatsb = false; |
---|
| 334 | if (maximize != other.maximize) |
---|
| 335 | throw new RuntimeException( |
---|
| 336 | "Attempt made to compare two multiobjective fitnesses; but one expects higher values to be better and the other expectes lower values to be better."); |
---|
| 337 | if (objectives.length != other.objectives.length) |
---|
| 338 | throw new RuntimeException("Attempt made to compare two multiobjective fitnesses; but they have different numbers of objectives."); |
---|
| 339 | if (maximize) |
---|
| 340 | { |
---|
| 341 | for (int x = 0; x < objectives.length; x++) |
---|
| 342 | { |
---|
| 343 | if (objectives[x] > other.objectives[x]) |
---|
| 344 | abeatsb = true; |
---|
| 345 | else if (objectives[x] < other.objectives[x]) |
---|
| 346 | return false; |
---|
| 347 | } |
---|
| 348 | } |
---|
| 349 | else |
---|
| 350 | { |
---|
| 351 | for (int x = 0; x < objectives.length; x++) |
---|
| 352 | { |
---|
| 353 | if (objectives[x] < other.objectives[x]) |
---|
| 354 | abeatsb = true; |
---|
| 355 | else if (objectives[x] > other.objectives[x]) |
---|
| 356 | return false; |
---|
| 357 | } |
---|
| 358 | } |
---|
| 359 | return abeatsb; |
---|
| 360 | } |
---|
| 361 | |
---|
| 362 | // Remove an individual from the ArrayList, shifting the topmost |
---|
| 363 | // individual in his place |
---|
| 364 | static void yank(int val, ArrayList list) |
---|
| 365 | { |
---|
| 366 | int size = list.size(); |
---|
| 367 | list.set(val, list.get(size - 1)); |
---|
| 368 | list.remove(size - 1); |
---|
| 369 | } |
---|
| 370 | |
---|
| 371 | /** |
---|
| 372 | * Divides an array of Individuals into the Pareto front and the "nonFront" (everyone else). |
---|
| 373 | * The Pareto front is returned. You may provide ArrayLists for the front and a nonFront. |
---|
| 374 | * If you provide null for the front, an ArrayList will be created for you. If you provide |
---|
| 375 | * null for the nonFront, non-front individuals will not be added to it. This algorithm is |
---|
| 376 | * O(n^2). |
---|
| 377 | */ |
---|
| 378 | public static ArrayList partitionIntoParetoFront(Individual[] inds, ArrayList front, ArrayList nonFront) |
---|
| 379 | { |
---|
| 380 | if (front == null) |
---|
| 381 | front = new ArrayList(); |
---|
| 382 | |
---|
| 383 | // put the first guy in the front |
---|
| 384 | front.add(inds[0]); |
---|
| 385 | |
---|
| 386 | // iterate over all the remaining individuals |
---|
| 387 | for (int i = 1; i < inds.length; i++) |
---|
| 388 | { |
---|
| 389 | Individual ind = (Individual) (inds[i]); |
---|
| 390 | |
---|
| 391 | boolean noOneWasBetter = true; |
---|
| 392 | int frontSize = front.size(); |
---|
| 393 | |
---|
| 394 | // iterate over the entire front |
---|
| 395 | for (int j = 0; j < frontSize; j++) |
---|
| 396 | { |
---|
| 397 | Individual frontmember = (Individual) (front.get(j)); |
---|
| 398 | |
---|
| 399 | // if the front member is better than the individual, dump the individual and go to the next one |
---|
| 400 | if (((MultiObjectiveFitness) (frontmember.fitness)).paretoDominates((MultiObjectiveFitness) (ind.fitness))) |
---|
| 401 | { |
---|
| 402 | if (nonFront != null) nonFront.add(ind); |
---|
| 403 | noOneWasBetter = false; |
---|
| 404 | break; // failed. He's not in the front |
---|
| 405 | } |
---|
| 406 | // if the individual was better than the front member, dump the front member. But look over the |
---|
| 407 | // other front members (don't break) because others might be dominated by the individual as well. |
---|
| 408 | else if (((MultiObjectiveFitness) (ind.fitness)).paretoDominates((MultiObjectiveFitness) (frontmember.fitness))) |
---|
| 409 | { |
---|
| 410 | yank(j, front); |
---|
| 411 | // a front member is dominated by the new individual. Replace him |
---|
| 412 | frontSize--; // member got removed |
---|
| 413 | j--; // because there's another guy we now need to consider in his place |
---|
| 414 | if (nonFront != null) nonFront.add(frontmember); |
---|
| 415 | } |
---|
| 416 | } |
---|
| 417 | if (noOneWasBetter) |
---|
| 418 | front.add(ind); |
---|
| 419 | } |
---|
| 420 | return front; |
---|
| 421 | } |
---|
| 422 | |
---|
| 423 | |
---|
| 424 | /** Divides inds into pareto front ranks (each an ArrayList), and returns them, in order, |
---|
| 425 | stored in an ArrayList. */ |
---|
| 426 | public static ArrayList partitionIntoRanks(Individual[] inds) |
---|
| 427 | { |
---|
| 428 | Individual[] dummy = new Individual[0]; |
---|
| 429 | ArrayList frontsByRank = new ArrayList(); |
---|
| 430 | |
---|
| 431 | while(inds.length > 0) |
---|
| 432 | { |
---|
| 433 | ArrayList front = new ArrayList(); |
---|
| 434 | ArrayList nonFront = new ArrayList(); |
---|
| 435 | MultiObjectiveFitness.partitionIntoParetoFront(inds, front, nonFront); |
---|
| 436 | |
---|
| 437 | // build inds out of remainder |
---|
| 438 | inds = (Individual[]) nonFront.toArray(dummy); |
---|
| 439 | frontsByRank.add(front); |
---|
| 440 | } |
---|
| 441 | return frontsByRank; |
---|
| 442 | } |
---|
| 443 | |
---|
| 444 | |
---|
| 445 | /** |
---|
| 446 | * Returns the sum of the squared difference between two Fitnesses in Objective space. |
---|
| 447 | */ |
---|
| 448 | public double sumSquaredObjectiveDistance(MultiObjectiveFitness other) |
---|
| 449 | { |
---|
| 450 | double s = 0; |
---|
| 451 | for (int i = 0; i < objectives.length; i++) |
---|
| 452 | { |
---|
| 453 | double a = (objectives[i] - other.objectives[i]); |
---|
| 454 | s += a * a; |
---|
| 455 | } |
---|
| 456 | return s; |
---|
| 457 | } |
---|
| 458 | |
---|
| 459 | |
---|
| 460 | /** |
---|
| 461 | * Returns the Manhattan difference between two Fitnesses in Objective space. |
---|
| 462 | */ |
---|
| 463 | public double manhattanObjectiveDistance(MultiObjectiveFitness other) |
---|
| 464 | { |
---|
| 465 | double s = 0; |
---|
| 466 | for (int i = 0; i < objectives.length; i++) |
---|
| 467 | { |
---|
| 468 | s += Math.abs(objectives[i] - other.objectives[i]); |
---|
| 469 | } |
---|
| 470 | return s; |
---|
| 471 | } |
---|
| 472 | |
---|
| 473 | |
---|
| 474 | public String fitnessToString() |
---|
| 475 | { |
---|
| 476 | String s = FITNESS_PREAMBLE + MULTI_FITNESS_POSTAMBLE; |
---|
| 477 | for (int x = 0; x < objectives.length; x++) |
---|
| 478 | { |
---|
| 479 | if (x > 0) |
---|
| 480 | s = s + " "; |
---|
| 481 | s = s + Code.encode(objectives[x]); |
---|
| 482 | } |
---|
| 483 | s = s + " "; |
---|
| 484 | s = s + Code.encode(maximize); |
---|
| 485 | return s + FITNESS_POSTAMBLE; |
---|
| 486 | } |
---|
| 487 | |
---|
| 488 | |
---|
| 489 | public String fitnessToStringForHumans() |
---|
| 490 | { |
---|
| 491 | String s = FITNESS_PREAMBLE + MULTI_FITNESS_POSTAMBLE; |
---|
| 492 | for (int x = 0; x < objectives.length; x++) |
---|
| 493 | { |
---|
| 494 | if (x > 0) |
---|
| 495 | s = s + " "; |
---|
| 496 | s = s + objectives[x]; |
---|
| 497 | } |
---|
| 498 | s = s + " "; |
---|
| 499 | s = s + (maximize ? "max" : "min"); |
---|
| 500 | return s + FITNESS_POSTAMBLE; |
---|
| 501 | } |
---|
| 502 | |
---|
| 503 | public void readFitness(final EvolutionState state, final LineNumberReader reader) throws IOException |
---|
| 504 | { |
---|
| 505 | DecodeReturn d = Code.checkPreamble(FITNESS_PREAMBLE + MULTI_FITNESS_POSTAMBLE, state, reader); |
---|
| 506 | for (int x = 0; x < objectives.length; x++) |
---|
| 507 | { |
---|
| 508 | Code.decode(d); |
---|
| 509 | if (d.type != DecodeReturn.T_FLOAT) |
---|
| 510 | state.output.fatal("Reading Line " + d.lineNumber + ": " + "Bad Fitness (objectives value #" + x + ")."); |
---|
| 511 | objectives[x] = (float) d.d; |
---|
| 512 | } |
---|
| 513 | Code.decode(d); |
---|
| 514 | if (d.type != DecodeReturn.T_BOOLEAN) |
---|
| 515 | state.output.fatal("Reading Line " + d.lineNumber + ": " + "Information missing about whether higher is better"); |
---|
| 516 | maximize = (boolean) (d.l != 0); |
---|
| 517 | } |
---|
| 518 | |
---|
| 519 | public void writeFitness(final EvolutionState state, final DataOutput dataOutput) throws IOException |
---|
| 520 | { |
---|
| 521 | dataOutput.writeInt(objectives.length); |
---|
| 522 | for (int x = 0; x < objectives.length; x++) |
---|
| 523 | dataOutput.writeFloat(objectives[x]); |
---|
| 524 | dataOutput.writeBoolean(maximize); |
---|
| 525 | } |
---|
| 526 | |
---|
| 527 | public void readFitness(final EvolutionState state, final DataInput dataInput) throws IOException |
---|
| 528 | { |
---|
| 529 | int len = dataInput.readInt(); |
---|
| 530 | if (objectives == null || objectives.length != len) |
---|
| 531 | objectives = new float[len]; |
---|
| 532 | for (int x = 0; x < objectives.length; x++) |
---|
| 533 | objectives[x] = dataInput.readFloat(); |
---|
| 534 | maximize = dataInput.readBoolean(); |
---|
| 535 | } |
---|
| 536 | } |
---|