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 | }
|
---|