[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 | |
---|
| 8 | package ec.gp; |
---|
| 9 | import ec.*; |
---|
| 10 | import ec.util.*; |
---|
| 11 | import java.io.*; |
---|
| 12 | |
---|
| 13 | /* |
---|
| 14 | * GPIndividual.java |
---|
| 15 | * |
---|
| 16 | * Created: Fri Aug 27 17:07:45 1999 |
---|
| 17 | * By: Sean Luke |
---|
| 18 | */ |
---|
| 19 | |
---|
| 20 | /** |
---|
| 21 | * GPIndividual is an Individual used for GP evolution runs. |
---|
| 22 | * GPIndividuals contain, at the very least, a nonempty array of GPTrees. |
---|
| 23 | * You can use GPIndividual directly, or subclass it to extend it as |
---|
| 24 | * you see fit. |
---|
| 25 | |
---|
| 26 | * <P>GPIndividuals have two clone methods: clone() and lightClone(). clone() is |
---|
| 27 | * a deep clone method as usual. lightClone() is a light clone which does not copy |
---|
| 28 | * the trees. |
---|
| 29 | * |
---|
| 30 | * <p>In addition to serialization for checkpointing, Individuals may read and write themselves to streams in three ways. |
---|
| 31 | * |
---|
| 32 | * <ul> |
---|
| 33 | * <li><b>writeIndividual(...,DataOutput)/readIndividual(...,DataInput)</b> This method |
---|
| 34 | * transmits or receives an individual in binary. It is the most efficient approach to sending |
---|
| 35 | * individuals over networks, etc. These methods write the evaluated flag and the fitness, then |
---|
| 36 | * call <b>readGenotype/writeGenotype</b>, which you must implement to write those parts of your |
---|
| 37 | * Individual special to your functions-- the default versions of readGenotype/writeGenotype throw errors. |
---|
| 38 | * You don't need to implement them if you don't plan on using read/writeIndividual. |
---|
| 39 | * |
---|
| 40 | * <li><b>printIndividual(...,PrintWriter)/readIndividual(...,LineNumberReader)</b> This |
---|
| 41 | * approach transmits or receives an indivdual in text encoded such that the individual is largely readable |
---|
| 42 | * by humans but can be read back in 100% by ECJ as well. Because GPIndividuals are often very large, |
---|
| 43 | * <b>GPIndividual has overridden these methods -- they work differently than in Individual (the superclass).</b> In specific: |
---|
| 44 | * <b>readIndividual</b> by default reads in the fitness and the evaluation flag, then calls <b>parseGenotype</b> |
---|
| 45 | * to read in the trees (via GPTree.readTree(...)). |
---|
| 46 | * However <b>printIndividual</b> by default prints the fitness and evaluation flag, and prints all the trees |
---|
| 47 | * by calling GPTree.printTree(...). It does not call <b>genotypeToString</b> at all. This |
---|
| 48 | * is because it's very wasteful to build up a large string holding the printed form of the GPIndividual |
---|
| 49 | * just to pump it out a stream once. |
---|
| 50 | * |
---|
| 51 | * <li><b>printIndividualForHumans(...,PrintWriter)</b> This |
---|
| 52 | * approach prints an individual in a fashion intended for human consumption only. Because GPIndividuals are often very large, |
---|
| 53 | * <b>GPIndividual has overridden this methods -- it works differently than in Individual (the superclass).</b> In specific: |
---|
| 54 | * <b>printIndividual</b> by default prints the fitness and evaluation flag, and prints all the trees |
---|
| 55 | * by calling GPTree.printTreeForHumans(...). It does not call <b>genotypeToStringForHumans</b> at all. This |
---|
| 56 | * is because it's very wasteful to build up a large string holding the printed form of the GPIndividual |
---|
| 57 | * just to pump it out a stream once. |
---|
| 58 | * |
---|
| 59 | * <p>In general, the various readers and writers do three things: they tell the Fitness to read/write itself, |
---|
| 60 | * they read/write the evaluated flag, and they read/write the GPTree array (by having each GPTree read/write |
---|
| 61 | * itself). If you add instance variables to GPIndividual, you'll need to read/write those variables as well. |
---|
| 62 | |
---|
| 63 | |
---|
| 64 | <p><b>Parameters</b><br> |
---|
| 65 | <table> |
---|
| 66 | <tr><td valign=top><i>base</i>.<tt>numtrees</tt><br> |
---|
| 67 | <font size=-1>int >= 1</font></td> |
---|
| 68 | <td valign=top>(number of trees in the GPIndividual)</td></tr> |
---|
| 69 | |
---|
| 70 | <tr><td valign=top><i>base</i>.<tt>tree.</tt><i>n</i><br> |
---|
| 71 | <font size=-1>classname, inherits or = ec.gp.GPTree</font></td> |
---|
| 72 | <td valign=top>(class of tree <i>n</i> in the individual)</td></tr> |
---|
| 73 | </table> |
---|
| 74 | |
---|
| 75 | <p><b>Default Base</b><br> |
---|
| 76 | gp.individual |
---|
| 77 | |
---|
| 78 | <p><b>Parameter bases</b><br> |
---|
| 79 | <table> |
---|
| 80 | <tr><td valign=top><i>base</i>.<tt>tree.</tt><i>n</i></td> |
---|
| 81 | <td>tree <i>n</i> in the individual</td></tr> |
---|
| 82 | </table> |
---|
| 83 | |
---|
| 84 | * |
---|
| 85 | * @author Sean Luke |
---|
| 86 | * @version 1.0 |
---|
| 87 | */ |
---|
| 88 | |
---|
| 89 | public class GPIndividual extends Individual |
---|
| 90 | { |
---|
| 91 | public static final String P_NUMTREES = "numtrees"; |
---|
| 92 | public static final String P_TREE = "tree"; |
---|
| 93 | |
---|
| 94 | public GPTree[] trees; |
---|
| 95 | |
---|
| 96 | public Parameter defaultBase() |
---|
| 97 | { |
---|
| 98 | return GPDefaults.base().push(P_INDIVIDUAL); |
---|
| 99 | } |
---|
| 100 | |
---|
| 101 | public boolean equals(Object ind) |
---|
| 102 | { |
---|
| 103 | if (!(this.getClass().equals(ind.getClass()))) return false; // GPIndividuals are special. |
---|
| 104 | GPIndividual i = (GPIndividual)ind; |
---|
| 105 | if (trees.length != i.trees.length) return false; |
---|
| 106 | // this default version works fine for most GPIndividuals. |
---|
| 107 | for(int x=0;x<trees.length;x++) |
---|
| 108 | if (!(trees[x].treeEquals(i.trees[x]))) return false; |
---|
| 109 | return true; |
---|
| 110 | } |
---|
| 111 | |
---|
| 112 | public int hashCode() |
---|
| 113 | { |
---|
| 114 | // stolen from GPNode. It's a decent algorithm. |
---|
| 115 | int hash = this.getClass().hashCode(); |
---|
| 116 | |
---|
| 117 | for(int x=0;x<trees.length;x++) |
---|
| 118 | hash = |
---|
| 119 | // Rotate hash and XOR |
---|
| 120 | (hash << 1 | hash >>> 31 ) ^ |
---|
| 121 | trees[x].treeHashCode(); |
---|
| 122 | return hash; |
---|
| 123 | } |
---|
| 124 | |
---|
| 125 | /** Sets up a prototypical GPIndividual with those features which it |
---|
| 126 | shares with other GPIndividuals in its species, and nothing more. */ |
---|
| 127 | |
---|
| 128 | public void setup(final EvolutionState state, final Parameter base) |
---|
| 129 | { |
---|
| 130 | super.setup(state,base); // actually unnecessary (Individual.setup() is empty) |
---|
| 131 | |
---|
| 132 | Parameter def = defaultBase(); |
---|
| 133 | |
---|
| 134 | // set my evaluation to false |
---|
| 135 | evaluated = false; |
---|
| 136 | |
---|
| 137 | // how many trees? |
---|
| 138 | int t = state.parameters.getInt(base.push(P_NUMTREES),def.push(P_NUMTREES),1); // at least 1 tree for GP! |
---|
| 139 | if (t <= 0) |
---|
| 140 | state.output.fatal("A GPIndividual must have at least one tree.", |
---|
| 141 | base.push(P_NUMTREES),def.push(P_NUMTREES)); |
---|
| 142 | |
---|
| 143 | // load the trees |
---|
| 144 | trees = new GPTree[t]; |
---|
| 145 | |
---|
| 146 | for (int x=0;x<t;x++) |
---|
| 147 | { |
---|
| 148 | Parameter p = base.push(P_TREE).push(""+x); |
---|
| 149 | trees[x] = (GPTree)(state.parameters.getInstanceForParameterEq( |
---|
| 150 | p,def.push(P_TREE).push(""+x),GPTree.class)); |
---|
| 151 | trees[x].owner = this; |
---|
| 152 | trees[x].setup(state,p); |
---|
| 153 | } |
---|
| 154 | |
---|
| 155 | // now that our function sets are all associated with trees, |
---|
| 156 | // give the nodes a chance to determine whether or not this is |
---|
| 157 | // going to work for them (especially the ADFs). |
---|
| 158 | GPInitializer initializer = ((GPInitializer)state.initializer); |
---|
| 159 | for (int x=0;x<t;x++) |
---|
| 160 | { |
---|
| 161 | for(int w = 0;w < trees[x].constraints(initializer).functionset.nodes.length;w++) |
---|
| 162 | { |
---|
| 163 | GPNode[] gpfi = trees[x].constraints(initializer).functionset.nodes[w]; |
---|
| 164 | for (int y = 0;y<gpfi.length;y++) |
---|
| 165 | gpfi[y].checkConstraints(state,x,this,base); |
---|
| 166 | } |
---|
| 167 | } |
---|
| 168 | // because I promised with checkConstraints(...) |
---|
| 169 | state.output.exitIfErrors(); |
---|
| 170 | } |
---|
| 171 | |
---|
| 172 | |
---|
| 173 | /** Verification of validity of the GPIndividual -- strictly for debugging purposes only */ |
---|
| 174 | public final void verify(EvolutionState state) |
---|
| 175 | { |
---|
| 176 | if (!(state.initializer instanceof GPInitializer)) |
---|
| 177 | { state.output.error("Initializer is not a GPInitializer"); return; } |
---|
| 178 | |
---|
| 179 | GPInitializer initializer = (GPInitializer)(state.initializer); |
---|
| 180 | |
---|
| 181 | if (trees==null) |
---|
| 182 | { state.output.error("Null trees in GPIndividual."); return; } |
---|
| 183 | for(int x=0;x<trees.length;x++) if (trees[x]==null) |
---|
| 184 | { state.output.error("Null tree (#"+x+") in GPIndividual."); return; } |
---|
| 185 | for(int x=0;x<trees.length;x++) |
---|
| 186 | trees[x].verify(state); |
---|
| 187 | state.output.exitIfErrors(); |
---|
| 188 | } |
---|
| 189 | |
---|
| 190 | /** Prints just the trees of the GPIndividual. Broken out like this to be used by GEIndividual to avoid |
---|
| 191 | re-printing the fitness and evaluated premables. */ |
---|
| 192 | public void printTrees(final EvolutionState state, final int log) |
---|
| 193 | { |
---|
| 194 | for(int x=0;x<trees.length;x++) |
---|
| 195 | { |
---|
| 196 | state.output.println("Tree " + x + ":",log); |
---|
| 197 | trees[x].printTreeForHumans(state,log); |
---|
| 198 | } |
---|
| 199 | } |
---|
| 200 | |
---|
| 201 | public void printIndividualForHumans(final EvolutionState state, final int log) |
---|
| 202 | { |
---|
| 203 | state.output.println(EVALUATED_PREAMBLE + (evaluated ? "true" : "false"), log); |
---|
| 204 | fitness.printFitnessForHumans(state,log); |
---|
| 205 | printTrees(state,log); |
---|
| 206 | } |
---|
| 207 | |
---|
| 208 | public void printIndividual(final EvolutionState state, final int log) |
---|
| 209 | { |
---|
| 210 | state.output.println(EVALUATED_PREAMBLE + Code.encode(evaluated), log); |
---|
| 211 | fitness.printFitness(state,log); |
---|
| 212 | for(int x=0;x<trees.length;x++) |
---|
| 213 | { |
---|
| 214 | state.output.println("Tree " + x + ":",log); |
---|
| 215 | trees[x].printTree(state,log); |
---|
| 216 | } |
---|
| 217 | } |
---|
| 218 | |
---|
| 219 | public void printIndividual(final EvolutionState state, |
---|
| 220 | final PrintWriter writer) |
---|
| 221 | { |
---|
| 222 | writer.println(EVALUATED_PREAMBLE + Code.encode(evaluated)); |
---|
| 223 | fitness.printFitness(state,writer); |
---|
| 224 | for(int x=0;x<trees.length;x++) |
---|
| 225 | { |
---|
| 226 | writer.println("Tree " + x + ":"); |
---|
| 227 | trees[x].printTree(state,writer); |
---|
| 228 | } |
---|
| 229 | } |
---|
| 230 | |
---|
| 231 | /** Overridden for the GPIndividual genotype. */ |
---|
| 232 | public void writeGenotype(final EvolutionState state, |
---|
| 233 | final DataOutput dataOutput) throws IOException |
---|
| 234 | { |
---|
| 235 | dataOutput.writeInt(trees.length); |
---|
| 236 | for(int x=0;x<trees.length;x++) |
---|
| 237 | trees[x].writeTree(state,dataOutput); |
---|
| 238 | } |
---|
| 239 | |
---|
| 240 | /** Overridden for the GPIndividual genotype. */ |
---|
| 241 | public void readGenotype(final EvolutionState state, |
---|
| 242 | final DataInput dataInput) throws IOException |
---|
| 243 | { |
---|
| 244 | int treelength = dataInput.readInt(); |
---|
| 245 | if (trees == null || treelength != trees.length) // wrong size! |
---|
| 246 | state.output.fatal("Number of trees differ in GPIndividual when reading from readGenotype(EvolutionState, DataInput)."); |
---|
| 247 | for(int x=0;x<trees.length;x++) |
---|
| 248 | trees[x].readTree(state,dataInput); |
---|
| 249 | } |
---|
| 250 | |
---|
| 251 | public void parseGenotype(final EvolutionState state, |
---|
| 252 | final LineNumberReader reader) throws IOException |
---|
| 253 | { |
---|
| 254 | // Read my trees |
---|
| 255 | for(int x=0;x<trees.length;x++) |
---|
| 256 | { |
---|
| 257 | reader.readLine(); // throw it away -- it's the tree indicator |
---|
| 258 | trees[x].readTree(state,reader); |
---|
| 259 | } |
---|
| 260 | } |
---|
| 261 | |
---|
| 262 | /** Deep-clones the GPIndividual. Note that you should not deep-clone the prototypical GPIndividual |
---|
| 263 | stored in GPSpecies: they contain blank GPTrees with null roots, and this method, |
---|
| 264 | which calls GPTree.clone(), will produce a NullPointerException as a result. Instead, you probably |
---|
| 265 | want to use GPSpecies.newIndividual(...) if you're thinking of playing with the prototypical |
---|
| 266 | GPIndividual. */ |
---|
| 267 | |
---|
| 268 | public Object clone() |
---|
| 269 | { |
---|
| 270 | // a deep clone |
---|
| 271 | |
---|
| 272 | GPIndividual myobj = (GPIndividual)(super.clone()); |
---|
| 273 | |
---|
| 274 | // copy the tree array |
---|
| 275 | myobj.trees = new GPTree[trees.length]; |
---|
| 276 | for(int x=0;x<trees.length;x++) |
---|
| 277 | { |
---|
| 278 | myobj.trees[x] = (GPTree)(trees[x].clone()); // force a deep clone |
---|
| 279 | myobj.trees[x].owner = myobj; // reset owner away from me |
---|
| 280 | } |
---|
| 281 | return myobj; |
---|
| 282 | } |
---|
| 283 | |
---|
| 284 | /** Like clone(), but doesn't force the GPTrees to deep-clone themselves. */ |
---|
| 285 | public GPIndividual lightClone() |
---|
| 286 | { |
---|
| 287 | // a light clone |
---|
| 288 | GPIndividual myobj = (GPIndividual)(super.clone()); |
---|
| 289 | |
---|
| 290 | // copy the tree array |
---|
| 291 | myobj.trees = new GPTree[trees.length]; |
---|
| 292 | for(int x=0;x<trees.length;x++) |
---|
| 293 | { |
---|
| 294 | myobj.trees[x] = (GPTree)(trees[x].lightClone()); // note light-cloned! |
---|
| 295 | myobj.trees[x].owner = myobj; // reset owner away from me |
---|
| 296 | } |
---|
| 297 | return myobj; |
---|
| 298 | } |
---|
| 299 | |
---|
| 300 | /** Returns the "size" of the individual, namely, the number of nodes |
---|
| 301 | in all of its subtrees. */ |
---|
| 302 | public long size() |
---|
| 303 | { |
---|
| 304 | long size = 0; |
---|
| 305 | for(int x=0;x<trees.length;x++) |
---|
| 306 | size += trees[x].child.numNodes(GPNode.NODESEARCH_ALL); |
---|
| 307 | return size; |
---|
| 308 | } |
---|
| 309 | |
---|
| 310 | } |
---|