[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 |
|
---|
| 9 | package ec;
|
---|
| 10 | import java.util.*;
|
---|
| 11 | import java.io.*;
|
---|
| 12 | import ec.util.*;
|
---|
| 13 |
|
---|
| 14 | /*
|
---|
| 15 | * Subpopulation.java
|
---|
| 16 | *
|
---|
| 17 | * Created: Tue Aug 10 20:34:14 1999
|
---|
| 18 | * By: Sean Luke
|
---|
| 19 | */
|
---|
| 20 |
|
---|
| 21 | /**
|
---|
| 22 | * Subpopulation is a group which is basically an array of Individuals.
|
---|
| 23 | * There is always one or more Subpopulations in the Population. Each
|
---|
| 24 | * Subpopulation has a Species, which governs the formation of the Individuals
|
---|
| 25 | * in that Subpopulation. Subpopulations also contain a Fitness prototype
|
---|
| 26 | * which is cloned to form Fitness objects for individuals in the subpopulation.
|
---|
| 27 | *
|
---|
| 28 | * <p>An initial subpopulation is populated with new random individuals
|
---|
| 29 | * using the populate(...) method. This method typically populates
|
---|
| 30 | * by filling the array with individuals created using the Subpopulations'
|
---|
| 31 | * species' emptyClone() method, though you might override this to create
|
---|
| 32 | * them with other means, by loading from text files for example.
|
---|
| 33 | *
|
---|
| 34 | * <p>In a multithreaded area of a run, Subpopulations should be considered
|
---|
| 35 | * immutable. That is, once they are created, they should not be modified,
|
---|
| 36 | * nor anything they contain. This protocol helps ensure read-safety under
|
---|
| 37 | * multithreading race conditions.
|
---|
| 38 | *
|
---|
| 39 |
|
---|
| 40 | <p><b>Parameters</b><br>
|
---|
| 41 | <table>
|
---|
| 42 | <tr><td valign=top><i>base</i>.<tt>size</tt><br>
|
---|
| 43 | <font size=-1>int >= 1</font></td>
|
---|
| 44 | <td valign=top>(total number of individuals in the subpopulation)</td></tr>
|
---|
| 45 |
|
---|
| 46 | <tr><td valign=top><i>base</i>.<tt>species</tt><br>
|
---|
| 47 | <font size=-1>classname, inherits and != ec.Species</font></td>
|
---|
| 48 | <td valign=top>(the class of the subpopulations' Species)</td></tr>
|
---|
| 49 |
|
---|
| 50 | <tr><td valign=top><i>base</i>.<tt>fitness</tt><br>
|
---|
| 51 | <font size=-1>classname, inherits and != ec.Fitness</font></td>
|
---|
| 52 | <td valign=top>(the class for the prototypical Fitness for individuals in this subpopulation)</td></tr>
|
---|
| 53 |
|
---|
| 54 | <tr><td valign=top><i>base</i>.<tt>file</tt><br>
|
---|
| 55 | <font size=-1>String</font></td>
|
---|
| 56 | <td valign=top>(pathname of file from which the population is to be loaded. If not defined, or empty, then the population will be initialized at random in the standard manner)</td></tr>
|
---|
| 57 |
|
---|
| 58 | <tr><td valign=top><i>base</i>.<tt>duplicate-retries</tt><br>
|
---|
| 59 | <font size=-1>int >= 0</font></td>
|
---|
| 60 | <td valign=top>(during initialization, when we produce an individual which already exists in the subpopulation, the number of times we try to replace it with something unique. Ignored if we're loading from a file.)</td></tr>
|
---|
| 61 | </table>
|
---|
| 62 |
|
---|
| 63 | <p><b>Default Base</b><br>
|
---|
| 64 | ec.subpop
|
---|
| 65 |
|
---|
| 66 | <p><b>Parameter bases</b><br>
|
---|
| 67 | <table>
|
---|
| 68 | <tr><td valign=top><i>base</i>.<tt>species</tt></td>
|
---|
| 69 | <td>species (the subpopulations' species)</td></tr>
|
---|
| 70 |
|
---|
| 71 | </table>
|
---|
| 72 |
|
---|
| 73 |
|
---|
| 74 | * @author Sean Luke
|
---|
| 75 | * @version 1.0
|
---|
| 76 | */
|
---|
| 77 |
|
---|
| 78 |
|
---|
| 79 | public class Subpopulation implements Group
|
---|
| 80 | {
|
---|
| 81 | /** A new subpopulation should be loaded from this file if it is non-null;
|
---|
| 82 | otherwise they should be created at random. */
|
---|
| 83 | public File loadInds;
|
---|
| 84 |
|
---|
| 85 | /** The species for individuals in this subpopulation. */
|
---|
| 86 | public Species species;
|
---|
| 87 |
|
---|
| 88 | /** The subpopulation's individuals. */
|
---|
| 89 | public Individual[] individuals;
|
---|
| 90 |
|
---|
| 91 | /** Do we allow duplicates? */
|
---|
| 92 | public int numDuplicateRetries;
|
---|
| 93 |
|
---|
| 94 | public static final String P_SUBPOPULATION = "subpop";
|
---|
| 95 | public static final String P_FILE = "file";
|
---|
| 96 | public static final String P_SUBPOPSIZE = "size"; // parameter for number of subpops or pops
|
---|
| 97 | public static final String P_SPECIES = "species";
|
---|
| 98 | public static final String P_RETRIES = "duplicate-retries";
|
---|
| 99 |
|
---|
| 100 | public static final String NUM_INDIVIDUALS_PREAMBLE = "Number of Individuals: ";
|
---|
| 101 | public static final String INDIVIDUAL_INDEX_PREAMBLE = "Individual Number: ";
|
---|
| 102 |
|
---|
| 103 | public Parameter defaultBase()
|
---|
| 104 | {
|
---|
| 105 | return ECDefaults.base().push(P_SUBPOPULATION);
|
---|
| 106 | }
|
---|
| 107 |
|
---|
| 108 | /** Returns an instance of Subpopulation just like it had been before it was
|
---|
| 109 | populated with individuals. You may need to override this if you override
|
---|
| 110 | Subpopulation. <b>IMPORTANT NOTE</b>: if the size of the array in
|
---|
| 111 | Subpopulation has been changed, then the clone will take on the new array
|
---|
| 112 | size. This helps some evolution strategies.
|
---|
| 113 | @see Group#emptyClone()
|
---|
| 114 | */
|
---|
| 115 |
|
---|
| 116 | public Group emptyClone()
|
---|
| 117 | {
|
---|
| 118 | try
|
---|
| 119 | {
|
---|
| 120 | Subpopulation p = (Subpopulation)clone();
|
---|
| 121 | p.species = species; // don't throw it away...maybe this is a bad idea...
|
---|
| 122 | p.individuals = new Individual[individuals.length]; // empty
|
---|
| 123 | return p;
|
---|
| 124 | }
|
---|
| 125 | catch (CloneNotSupportedException e) { throw new InternalError(); } // never happens
|
---|
| 126 | }
|
---|
| 127 |
|
---|
| 128 | public void setup(final EvolutionState state, final Parameter base)
|
---|
| 129 | {
|
---|
| 130 | Parameter def = defaultBase();
|
---|
| 131 |
|
---|
| 132 | int size;
|
---|
| 133 |
|
---|
| 134 | // do we load from a file?
|
---|
| 135 | loadInds = state.parameters.getFile(
|
---|
| 136 | base.push(P_FILE),null);
|
---|
| 137 |
|
---|
| 138 | // what species do we use?
|
---|
| 139 |
|
---|
| 140 | species = (Species) state.parameters.getInstanceForParameter(
|
---|
| 141 | base.push(P_SPECIES),def.push(P_SPECIES),
|
---|
| 142 | Species.class);
|
---|
| 143 | species.setup(state,base.push(P_SPECIES));
|
---|
| 144 |
|
---|
| 145 | // how big should our subpopulation be?
|
---|
| 146 |
|
---|
| 147 | size = state.parameters.getInt(
|
---|
| 148 | base.push(P_SUBPOPSIZE),def.push(P_SUBPOPSIZE),1);
|
---|
| 149 | if (size<=0)
|
---|
| 150 | state.output.fatal(
|
---|
| 151 | "Subpopulation size must be an integer >= 1.\n",
|
---|
| 152 | base.push(P_SUBPOPSIZE),def.push(P_SUBPOPSIZE));
|
---|
| 153 |
|
---|
| 154 | // How often do we retry if we find a duplicate?
|
---|
| 155 | numDuplicateRetries = state.parameters.getInt(
|
---|
| 156 | base.push(P_RETRIES),def.push(P_RETRIES),0);
|
---|
| 157 | if (numDuplicateRetries < 0) state.output.fatal(
|
---|
| 158 | "The number of retries for duplicates must be an integer >= 0.\n",
|
---|
| 159 | base.push(P_RETRIES),def.push(P_RETRIES));
|
---|
| 160 |
|
---|
| 161 | individuals = new Individual[size];
|
---|
| 162 | }
|
---|
| 163 |
|
---|
| 164 |
|
---|
| 165 |
|
---|
| 166 | public void populate(EvolutionState state, int thread)
|
---|
| 167 | {
|
---|
| 168 | // should we load individuals from a file? -- duplicates are permitted
|
---|
| 169 | if (loadInds!=null)
|
---|
| 170 | {
|
---|
| 171 | try { readSubpopulation(state, new LineNumberReader(new FileReader(loadInds))); }
|
---|
| 172 | catch (IOException e) { state.output.fatal("An IOException occurred when trying to read from the file " + loadInds + ". The IOException was: \n" + e); }
|
---|
| 173 | }
|
---|
| 174 | else
|
---|
| 175 | {
|
---|
| 176 | Hashtable h = null;
|
---|
| 177 | if (numDuplicateRetries >= 1)
|
---|
| 178 | h = new Hashtable(individuals.length / 2); // seems reasonable
|
---|
| 179 |
|
---|
| 180 | for(int x=0;x<individuals.length;x++)
|
---|
| 181 | {
|
---|
| 182 | for(int tries=0;
|
---|
| 183 | tries <= /* Yes, I see that*/ numDuplicateRetries;
|
---|
| 184 | tries++)
|
---|
| 185 | {
|
---|
| 186 | individuals[x] = species.newIndividual(state, thread);
|
---|
| 187 |
|
---|
| 188 | if (numDuplicateRetries >= 1)
|
---|
| 189 | {
|
---|
| 190 | // check for duplicates
|
---|
| 191 | Object o = h.get(individuals[x]);
|
---|
| 192 | if (o == null) // found nothing, we're safe
|
---|
| 193 | // hash it and go
|
---|
| 194 | {
|
---|
| 195 | h.put(individuals[x],individuals[x]);
|
---|
| 196 | break;
|
---|
| 197 | }
|
---|
| 198 | }
|
---|
| 199 | } // oh well, we tried to cut down the duplicates
|
---|
| 200 | }
|
---|
| 201 | }
|
---|
| 202 | }
|
---|
| 203 |
|
---|
| 204 | /** Prints an entire subpopulation in a form readable by humans.
|
---|
| 205 | @deprecated Verbosity no longer has meaning
|
---|
| 206 | */
|
---|
| 207 | public final void printSubpopulationForHumans(final EvolutionState state,
|
---|
| 208 | final int log,
|
---|
| 209 | final int verbosity)
|
---|
| 210 | {
|
---|
| 211 | printSubpopulationForHumans(state, log);
|
---|
| 212 | }
|
---|
| 213 |
|
---|
| 214 | /** Prints an entire subpopulation in a form readable by humans but also parseable by the computer using readSubpopulation(EvolutionState, LineNumberReader).
|
---|
| 215 | @deprecated Verbosity no longer has meaning
|
---|
| 216 | */
|
---|
| 217 | public final void printSubpopulation(final EvolutionState state,
|
---|
| 218 | final int log,
|
---|
| 219 | final int verbosity)
|
---|
| 220 | {
|
---|
| 221 | printSubpopulation(state, log);
|
---|
| 222 | }
|
---|
| 223 |
|
---|
| 224 | /** Prints an entire subpopulation in a form readable by humans, with a verbosity of Output.V_NO_GENERAL. */
|
---|
| 225 | public void printSubpopulationForHumans(final EvolutionState state,
|
---|
| 226 | final int log)
|
---|
| 227 | {
|
---|
| 228 | state.output.println(NUM_INDIVIDUALS_PREAMBLE + individuals.length, log);
|
---|
| 229 | for(int i = 0 ; i < individuals.length; i++)
|
---|
| 230 | {
|
---|
| 231 | state.output.println(INDIVIDUAL_INDEX_PREAMBLE + Code.encode(i), log);
|
---|
| 232 | individuals[i].printIndividualForHumans(state, log);
|
---|
| 233 | }
|
---|
| 234 | }
|
---|
| 235 |
|
---|
| 236 | /** Prints an entire subpopulation in a form readable by humans but also parseable by the computer using readSubpopulation(EvolutionState, LineNumberReader) with a verbosity of Output.V_NO_GENERAL. */
|
---|
| 237 | public void printSubpopulation(final EvolutionState state,
|
---|
| 238 | final int log)
|
---|
| 239 | {
|
---|
| 240 | state.output.println(NUM_INDIVIDUALS_PREAMBLE + Code.encode(individuals.length), log);
|
---|
| 241 | for(int i = 0 ; i < individuals.length; i++)
|
---|
| 242 | {
|
---|
| 243 | state.output.println(INDIVIDUAL_INDEX_PREAMBLE + Code.encode(i), log);
|
---|
| 244 | individuals[i].printIndividual(state, log);
|
---|
| 245 | }
|
---|
| 246 | }
|
---|
| 247 |
|
---|
| 248 | /** Prints an entire subpopulation in a form readable by humans but also parseable by the computer using readSubpopulation(EvolutionState, LineNumberReader). */
|
---|
| 249 | public void printSubpopulation(final EvolutionState state,
|
---|
| 250 | final PrintWriter writer)
|
---|
| 251 | {
|
---|
| 252 | writer.println(NUM_INDIVIDUALS_PREAMBLE + Code.encode(individuals.length));
|
---|
| 253 | for(int i = 0 ; i < individuals.length; i++)
|
---|
| 254 | {
|
---|
| 255 | writer.println(INDIVIDUAL_INDEX_PREAMBLE + Code.encode(i));
|
---|
| 256 | individuals[i].printIndividual(state, writer);
|
---|
| 257 | }
|
---|
| 258 | }
|
---|
| 259 |
|
---|
| 260 | /** Reads a subpopulation from the format generated by printSubpopulation(....). If the number of individuals is not identical, the individuals array will
|
---|
| 261 | be deleted and replaced with a new array, and a warning will be generated as individuals will have to be created using newIndividual(...) rather
|
---|
| 262 | than readIndividual(...). */
|
---|
| 263 | public void readSubpopulation(final EvolutionState state,
|
---|
| 264 | final LineNumberReader reader) throws IOException
|
---|
| 265 | {
|
---|
| 266 | // read in number of individuals and check to see if this appears to be a valid subpopulation
|
---|
| 267 | int numIndividuals = Code.readIntegerWithPreamble(NUM_INDIVIDUALS_PREAMBLE, state, reader);
|
---|
| 268 |
|
---|
| 269 | // read in individuals
|
---|
| 270 | if (numIndividuals != individuals.length)
|
---|
| 271 | {
|
---|
| 272 | state.output.warnOnce("On reading subpopulation from text stream, the subpopulation size didn't match.\n" +
|
---|
| 273 | "Had to resize and use newIndividual() instead of readIndividual().");
|
---|
| 274 | individuals = new Individual[numIndividuals];
|
---|
| 275 | for(int i = 0 ; i < individuals.length; i++)
|
---|
| 276 | {
|
---|
| 277 | int j = Code.readIntegerWithPreamble(INDIVIDUAL_INDEX_PREAMBLE, state, reader);
|
---|
| 278 | // sanity check
|
---|
| 279 | if (j!=i) state.output.warnOnce("On reading subpopulation from text stream, some individual indexes in the subpopulation did not match.");
|
---|
| 280 | individuals[i] = species.newIndividual(state, reader);
|
---|
| 281 | }
|
---|
| 282 | }
|
---|
| 283 | else for(int i = 0 ; i < individuals.length; i++)
|
---|
| 284 | {
|
---|
| 285 | int j = Code.readIntegerWithPreamble(INDIVIDUAL_INDEX_PREAMBLE, state, reader);
|
---|
| 286 | // sanity check
|
---|
| 287 | if (j!=i) state.output.warnOnce("On reading subpopulation from text stream, some individual indexes in the subpopulation did not match.");
|
---|
| 288 | if (individuals[i] != null)
|
---|
| 289 | individuals[i].readIndividual(state, reader);
|
---|
| 290 | else
|
---|
| 291 | {
|
---|
| 292 | state.output.warnOnce("On reading subpopulation from text stream, some of the preexisting subpopulation's slots were null.\n" +
|
---|
| 293 | "Had to use newIndividual() instead of readIndividual(). If you're starting an evolutionary run by reading an\n" +
|
---|
| 294 | "existing population from a file, this is expected -- ignore this message.");
|
---|
| 295 | individuals[i] = species.newIndividual(state, reader);
|
---|
| 296 | }
|
---|
| 297 | }
|
---|
| 298 | }
|
---|
| 299 |
|
---|
| 300 | /** Writes a subpopulation in binary form, in a format readable by readSubpopulation(EvolutionState, DataInput). */
|
---|
| 301 | public void writeSubpopulation(final EvolutionState state,
|
---|
| 302 | final DataOutput dataOutput) throws IOException
|
---|
| 303 | {
|
---|
| 304 | dataOutput.writeInt(individuals.length);
|
---|
| 305 | for(int i = 0 ; i < individuals.length; i++)
|
---|
| 306 | individuals[i].writeIndividual(state, dataOutput);
|
---|
| 307 | }
|
---|
| 308 |
|
---|
| 309 | /** Reads a subpopulation in binary form, from the format generated by writeSubpopulation(...). If the number of individuals is not identical, the individuals array will
|
---|
| 310 | be deleted and replaced with a new array, and a warning will be generated as individuals will have to be created using newIndividual(...) rather
|
---|
| 311 | than readIndividual(...) */
|
---|
| 312 | public void readSubpopulation(final EvolutionState state,
|
---|
| 313 | final DataInput dataInput) throws IOException
|
---|
| 314 | {
|
---|
| 315 | int numIndividuals = dataInput.readInt();
|
---|
| 316 | if (numIndividuals != individuals.length)
|
---|
| 317 | {
|
---|
| 318 | state.output.warnOnce("On reading subpopulation from binary stream, the subpopulation size was incorrect.\n" +
|
---|
| 319 | "Had to resize and use newIndividual() instead of readIndividual().");
|
---|
| 320 | individuals = new Individual[numIndividuals];
|
---|
| 321 | for(int i = 0 ; i < individuals.length; i++)
|
---|
| 322 | individuals[i] = species.newIndividual(state, dataInput);
|
---|
| 323 | }
|
---|
| 324 | else for(int i = 0 ; i < individuals.length; i++)
|
---|
| 325 | individuals[i].readIndividual(state, dataInput);
|
---|
| 326 | }
|
---|
| 327 | }
|
---|