1 | /* |
---|
2 | Copyright 2006 by Sean Luke and George Mason University |
---|
3 | Licensed under the Academic Free License version 3.0 |
---|
4 | See the file "LICENSE" for more information |
---|
5 | */ |
---|
6 | |
---|
7 | |
---|
8 | package ec.coevolve; |
---|
9 | import ec.*; |
---|
10 | import ec.util.*; |
---|
11 | |
---|
12 | /** |
---|
13 | * CompetitiveEvaluator.java |
---|
14 | * |
---|
15 | |
---|
16 | <p>CompetitiveEvaluator is a Evaluator which performs <i>competitive fitness evaluations</i>. |
---|
17 | Competitive fitness is where individuals' fitness is determined by testing them against |
---|
18 | other members of the same subpopulation. Competitive fitness topologies differ from |
---|
19 | co-evolution topologies in that co-evolution is a term I generally reserve for |
---|
20 | multiple sbupopulations which breed separately but compete against other subpopulations |
---|
21 | during evaluation time. Individuals are evaluated regardless of whether or not they've |
---|
22 | been evaluated in the past. |
---|
23 | |
---|
24 | <p>Your Problem is responsible for setting up the fitness appropriately. |
---|
25 | CompetitiveEvaluator expects to use Problems which adhere to the GroupedProblemForm interface, |
---|
26 | which defines a new evaluate(...) function, plus a preprocess(...) and postprocess(...) function. |
---|
27 | |
---|
28 | <p>This competitive fitness evaluator is single-threaded -- maybe we'll hack in multithreading later. |
---|
29 | And it only has two individuals competing during any fitness evaluation. The order of individuals in the |
---|
30 | subpopulation will be changed during the evaluation process. There are seven evaluation topologies |
---|
31 | presently supported: |
---|
32 | |
---|
33 | <p><dl> |
---|
34 | <dt><b>Single Elimination Tournament</b><dd> |
---|
35 | All members of the population are paired up and evaluated. In each pair, the "winner" is the individual |
---|
36 | which winds up with the superior fitness. If neither fitness is superior, then the "winner" is picked |
---|
37 | at random. Then all the winners are paired up and evaluated, and so on, just like in a single elimination |
---|
38 | tournament. It is important that the <b>population size be a <i>power of two</i></b>, else some individuals |
---|
39 | will not have the same number of "wins" as others and may lose the tournament as a result. |
---|
40 | |
---|
41 | <dt><b>Round Robin</b><dd> |
---|
42 | Every member of the population are paired up and evaluated with all other members of the population, not |
---|
43 | not including the member itself (we might add in self-play as a future later if people ask for it, it's |
---|
44 | easy to hack in). |
---|
45 | |
---|
46 | <dt><b>K-Random-Opponents-One-Way</b><dd> |
---|
47 | Each individual's fitness is calculated based on K competitions against random opponents. |
---|
48 | For details, see "A Comparison of Two Competitive Fitness Functions" by Liviu Panait and |
---|
49 | Sean Luke in the Proceedings of GECCO 2002. |
---|
50 | |
---|
51 | <dt><b>K-Random-Opponents-Two-Way</b><dd> |
---|
52 | Each individual's fitness is calculated based on K competitions against random opponents. The advantage of |
---|
53 | this method over <b>K-Random-Opponents-One-Way</b> is a reduced number of competitions (when I competes |
---|
54 | against J, both I's and J's fitnesses are updated, while in the previous method only one of the individuals |
---|
55 | has its fitness updated). |
---|
56 | For details, see "A Comparison of Two Competitive Fitness Functions" by Liviu Panait and |
---|
57 | Sean Luke in the Proceedings of GECCO 2002. |
---|
58 | </dl> |
---|
59 | |
---|
60 | <p><b>Parameters</b><br> |
---|
61 | <table> |
---|
62 | <tr><td valign=top><i>base.</i><tt>style</tt><br> |
---|
63 | <font size=-1>string with possible values: </font></td> |
---|
64 | <td valign=top>(the style of the tournament)<br> |
---|
65 | <i>single-elim-tournament</i> (a single elimination tournament)<br> |
---|
66 | <i>round-robin</i> (a round robin tournament)<br> |
---|
67 | <i>rand-1-way</i> (K-Random-Opponents, each game counts for only one of the players)<br> |
---|
68 | <i>rand-2-way</i> (K-Random-Opponents, each game counts for both players)<br> |
---|
69 | </td></tr> |
---|
70 | |
---|
71 | <tr><td valign=top><i>base.</i><tt>group-size</tt><br> |
---|
72 | <font size=-1> int</font></td> |
---|
73 | <td valign=top>(how many individuals per group, used in rand-1-way</i> and <i>rand-2-way</i> tournaments)<br> |
---|
74 | <i>group-size</i> >= 1 for <i>rand-1-way</i> or <i>rand-2-way</i><br> |
---|
75 | </td></tr> |
---|
76 | |
---|
77 | <tr><td valign=top><i>base.</i><tt>over-eval</tt><br> |
---|
78 | <font size=-1> bool = <tt>true</tt> or <tt>false</tt> (default)</font></td> |
---|
79 | <td valign=top>(if the tournament style leads to an individual playing more games than others (as can be the case for rand-2-way), |
---|
80 | should the extra games be used for his fitness evaluatiuon?)</td></tr> |
---|
81 | |
---|
82 | </table> |
---|
83 | |
---|
84 | * |
---|
85 | * @author Sean Luke & Liviu Panait |
---|
86 | * @version 1.0 |
---|
87 | */ |
---|
88 | |
---|
89 | |
---|
90 | public class CompetitiveEvaluator extends Evaluator |
---|
91 | { |
---|
92 | public static final int STYLE_SINGLE_ELIMINATION=1; |
---|
93 | public static final int STYLE_ROUND_ROBIN=2; |
---|
94 | public static final int STYLE_N_RANDOM_COMPETITORS_ONEWAY=3; |
---|
95 | public static final int STYLE_N_RANDOM_COMPETITORS_TWOWAY=4; |
---|
96 | |
---|
97 | public static final String P_COMPETE_STYLE = "style"; |
---|
98 | public int style; |
---|
99 | |
---|
100 | public static final String P_GROUP_SIZE = "group-size"; |
---|
101 | public int groupSize; |
---|
102 | |
---|
103 | public static final String P_OVER_EVAL = "over-eval"; |
---|
104 | public boolean allowOverEvaluation; |
---|
105 | |
---|
106 | public void setup( final EvolutionState state, final Parameter base ) |
---|
107 | { |
---|
108 | super.setup( state, base ); |
---|
109 | String temp; |
---|
110 | temp = state.parameters.getStringWithDefault( base.push( P_COMPETE_STYLE ), null, "" ); |
---|
111 | if( temp.equalsIgnoreCase( "single-elim-tournament" ) ) |
---|
112 | { |
---|
113 | style = STYLE_SINGLE_ELIMINATION; |
---|
114 | } |
---|
115 | else if( temp.equalsIgnoreCase( "round-robin" ) ) |
---|
116 | { |
---|
117 | style = STYLE_ROUND_ROBIN; |
---|
118 | } |
---|
119 | else if( temp.equalsIgnoreCase( "rand-1-way" ) ) |
---|
120 | { |
---|
121 | style = STYLE_N_RANDOM_COMPETITORS_ONEWAY; |
---|
122 | } |
---|
123 | else if( temp.equalsIgnoreCase( "rand-2-way" ) ) |
---|
124 | { |
---|
125 | style = STYLE_N_RANDOM_COMPETITORS_TWOWAY; |
---|
126 | } |
---|
127 | else if (temp.equalsIgnoreCase( "rand-2-ways" ) ) |
---|
128 | { |
---|
129 | state.output.fatal("'rand-2-ways' is no longer a valid style name: use 'rand-2-way'", |
---|
130 | base.push(P_COMPETE_STYLE), null); |
---|
131 | } |
---|
132 | else |
---|
133 | { |
---|
134 | state.output.fatal( "Incorrect value for parameter. Acceptable values: " + |
---|
135 | "single-elim-tournament, round-robin, rand-1-way, rand-2-way" , base.push( P_COMPETE_STYLE ) ); |
---|
136 | } |
---|
137 | |
---|
138 | if( style == STYLE_N_RANDOM_COMPETITORS_ONEWAY || style == STYLE_N_RANDOM_COMPETITORS_TWOWAY ) |
---|
139 | { |
---|
140 | groupSize = state.parameters.getInt( base.push( P_GROUP_SIZE ), null, 1 ); |
---|
141 | if( groupSize < 1 ) |
---|
142 | { |
---|
143 | state.output.fatal( "Incorrect value for parameter", base.push( P_GROUP_SIZE ) ); |
---|
144 | } |
---|
145 | } |
---|
146 | allowOverEvaluation = state.parameters.getBoolean( base.push( P_OVER_EVAL ), null, false ); |
---|
147 | } |
---|
148 | |
---|
149 | public boolean runComplete( final EvolutionState state ) |
---|
150 | { |
---|
151 | return false; |
---|
152 | } |
---|
153 | |
---|
154 | public void randomizeOrder(final EvolutionState state, final Individual[] individuals) |
---|
155 | { |
---|
156 | // copy the inds into a new array, then dump them randomly into the |
---|
157 | // subpopulation again |
---|
158 | Individual[] queue = new Individual[individuals.length]; |
---|
159 | int len = queue.length; |
---|
160 | System.arraycopy(individuals,0,queue,0,len); |
---|
161 | |
---|
162 | for(int x=len;x>0;x--) |
---|
163 | { |
---|
164 | int i = state.random[0].nextInt(x); |
---|
165 | individuals[x-1] = queue[i]; |
---|
166 | // get rid of queue[i] by swapping the highest guy there and then |
---|
167 | // decreasing the highest value :-) |
---|
168 | queue[i] = queue[x-1]; |
---|
169 | } |
---|
170 | } |
---|
171 | |
---|
172 | /** |
---|
173 | * An evaluator that performs coevolutionary evaluation. Like SimpleEvaluator, |
---|
174 | * it applies evolution pipelines, one per thread, to various subchunks of |
---|
175 | * a new population. |
---|
176 | */ |
---|
177 | public void evaluatePopulation(final EvolutionState state) |
---|
178 | { |
---|
179 | int numinds[] = new int[state.evalthreads]; |
---|
180 | int from[] = new int[state.evalthreads]; |
---|
181 | |
---|
182 | for (int y=0;y<state.evalthreads;y++) |
---|
183 | { |
---|
184 | // figure numinds |
---|
185 | if (y<state.evalthreads-1) // not last one |
---|
186 | numinds[y] = state.population.subpops[0].individuals.length/ |
---|
187 | state.evalthreads; |
---|
188 | else |
---|
189 | numinds[y] = |
---|
190 | state.population.subpops[0].individuals.length/ |
---|
191 | state.evalthreads + |
---|
192 | |
---|
193 | (state.population.subpops[0].individuals.length - |
---|
194 | (state.population.subpops[0].individuals.length / |
---|
195 | state.evalthreads) |
---|
196 | *state.evalthreads); |
---|
197 | // figure from |
---|
198 | from[y] = (state.population.subpops[0].individuals.length/ |
---|
199 | state.evalthreads) * y; |
---|
200 | } |
---|
201 | |
---|
202 | randomizeOrder( state, state.population.subpops[0].individuals ); |
---|
203 | |
---|
204 | GroupedProblemForm prob = (GroupedProblemForm)(p_problem.clone()); |
---|
205 | |
---|
206 | prob.preprocessPopulation(state,state.population, style == STYLE_SINGLE_ELIMINATION); |
---|
207 | |
---|
208 | switch(style) |
---|
209 | { |
---|
210 | case STYLE_SINGLE_ELIMINATION: |
---|
211 | evalSingleElimination( state, state.population.subpops[0].individuals, 0, prob); |
---|
212 | break; |
---|
213 | case STYLE_ROUND_ROBIN: |
---|
214 | evalRoundRobin( state, from, numinds, state.population.subpops[0].individuals, 0, prob ); |
---|
215 | break; |
---|
216 | case STYLE_N_RANDOM_COMPETITORS_ONEWAY: |
---|
217 | evalNRandomOneWay( state, from, numinds, state.population.subpops[0].individuals, 0, prob ); |
---|
218 | break; |
---|
219 | case STYLE_N_RANDOM_COMPETITORS_TWOWAY: |
---|
220 | evalNRandomTwoWay( state, from, numinds, state.population.subpops[0].individuals, 0, prob ); |
---|
221 | break; |
---|
222 | } |
---|
223 | |
---|
224 | prob.postprocessPopulation(state, state.population, style == STYLE_SINGLE_ELIMINATION); |
---|
225 | } |
---|
226 | |
---|
227 | public void evalSingleElimination( final EvolutionState state, |
---|
228 | final Individual[] individuals, |
---|
229 | final int subpop, |
---|
230 | final GroupedProblemForm prob ) |
---|
231 | { |
---|
232 | |
---|
233 | // for a single-elimination tournament, the subpop[0] size must be 2^n for |
---|
234 | // some value n. We don't check that here! Check it in setup. |
---|
235 | |
---|
236 | // create the tournament array |
---|
237 | Individual[] tourn = new Individual[individuals.length]; |
---|
238 | System.arraycopy( individuals, 0, tourn, 0, individuals.length ); |
---|
239 | int len = tourn.length; |
---|
240 | Individual[] competition = new Individual[2]; |
---|
241 | int[] subpops = new int[] { subpop, subpop }; |
---|
242 | boolean[] updates = new boolean[2]; |
---|
243 | updates[0] = updates[1] = true; |
---|
244 | |
---|
245 | // the "top half" of our array will be losers. |
---|
246 | // the bottom half will be winners. Then we cut our array in half and repeat. |
---|
247 | while( len > 1 ) |
---|
248 | { |
---|
249 | for(int x=0;x<len/2;x++) |
---|
250 | { |
---|
251 | competition[0] = tourn[x]; |
---|
252 | competition[1] = tourn[len-x-1]; |
---|
253 | |
---|
254 | prob.evaluate(state,competition,updates,true,subpops, 0); |
---|
255 | } |
---|
256 | |
---|
257 | for(int x=0;x<len/2;x++) |
---|
258 | { |
---|
259 | // if the second individual is better, than we switch them around |
---|
260 | if( tourn[len-x-1].fitness.betterThan(tourn[x].fitness) ) |
---|
261 | { |
---|
262 | Individual temp = tourn[x]; |
---|
263 | tourn[x] = tourn[len-x-1]; |
---|
264 | tourn[len-x-1] = temp; |
---|
265 | } |
---|
266 | |
---|
267 | } |
---|
268 | |
---|
269 | // last part of the tournament: deal with odd values of len! |
---|
270 | if( len%2 != 0 ) |
---|
271 | len = 1 + len/2; |
---|
272 | else |
---|
273 | len /= 2; |
---|
274 | } |
---|
275 | } |
---|
276 | |
---|
277 | |
---|
278 | public void evalRoundRobin( final EvolutionState state, |
---|
279 | int[] from, int[] numinds, |
---|
280 | final Individual[] individuals, int subpop, |
---|
281 | final GroupedProblemForm prob ) |
---|
282 | { |
---|
283 | if (state.evalthreads==1) |
---|
284 | evalRoundRobinPopChunk(state,from[0],numinds[0],0,individuals, subpop, prob); |
---|
285 | else |
---|
286 | { |
---|
287 | Thread[] t = new Thread[state.evalthreads]; |
---|
288 | |
---|
289 | // start up the threads |
---|
290 | for (int y=0;y<state.evalthreads;y++) |
---|
291 | { |
---|
292 | CompetitiveEvaluatorThread r = new RoundRobinCompetitiveEvaluatorThread(); |
---|
293 | r.threadnum = y; |
---|
294 | r.numinds = numinds[y]; |
---|
295 | r.from = from[y]; |
---|
296 | r.me = this; |
---|
297 | r.subpop = subpop; |
---|
298 | r.state = state; |
---|
299 | r.p = prob; |
---|
300 | r.inds = individuals; |
---|
301 | t[y] = new Thread(r); |
---|
302 | t[y].start(); |
---|
303 | } |
---|
304 | |
---|
305 | // gather the threads |
---|
306 | for (int y=0;y<state.evalthreads;y++) |
---|
307 | try { t[y].join(); } |
---|
308 | catch(InterruptedException e) |
---|
309 | { |
---|
310 | state.output.fatal("Whoa! The main evaluation thread got interrupted! Dying..."); |
---|
311 | } |
---|
312 | } |
---|
313 | |
---|
314 | } |
---|
315 | |
---|
316 | /** |
---|
317 | * A private helper function for evalutatePopulation which evaluates a chunk |
---|
318 | * of individuals in a subpopulation for a given thread. |
---|
319 | * |
---|
320 | * Although this method is declared public (for the benefit of a private |
---|
321 | * helper class in this file), you should not call it. |
---|
322 | * |
---|
323 | * @param state |
---|
324 | * @param numinds |
---|
325 | * @param from |
---|
326 | * @param threadnum |
---|
327 | * @param prob |
---|
328 | */ |
---|
329 | public void evalRoundRobinPopChunk(final EvolutionState state, |
---|
330 | int from, int numinds, int threadnum, |
---|
331 | final Individual[] individuals, int subpop, |
---|
332 | final GroupedProblemForm prob) |
---|
333 | { |
---|
334 | Individual[] competition = new Individual[2]; |
---|
335 | int[] subpops = new int[] { subpop, subpop }; |
---|
336 | boolean[] updates = new boolean[2]; |
---|
337 | updates[0] = updates[1] = true; |
---|
338 | int upperBound = from+numinds; |
---|
339 | |
---|
340 | // evaluate chunk of population against entire population |
---|
341 | // since an individual x will be evaluated against all |
---|
342 | // other individuals <x in other threads, only evaluate it against |
---|
343 | // individuals >x in this thread. |
---|
344 | for(int x=from;x<upperBound;x++) |
---|
345 | for(int y=x+1;y<individuals.length;y++) |
---|
346 | { |
---|
347 | competition[0] = individuals[x]; |
---|
348 | competition[1] = individuals[y]; |
---|
349 | prob.evaluate(state,competition,updates,false, subpops, 0); |
---|
350 | } |
---|
351 | } |
---|
352 | |
---|
353 | |
---|
354 | public void evalNRandomOneWay( final EvolutionState state, |
---|
355 | int[] from, int[] numinds, |
---|
356 | final Individual[] individuals, int subpop, |
---|
357 | final GroupedProblemForm prob ) |
---|
358 | { |
---|
359 | if (state.evalthreads==1) |
---|
360 | evalNRandomOneWayPopChunk(state,from[0],numinds[0],0,individuals, subpop, prob); |
---|
361 | else |
---|
362 | { |
---|
363 | Thread[] t = new Thread[state.evalthreads]; |
---|
364 | |
---|
365 | // start up the threads |
---|
366 | for (int y=0;y<state.evalthreads;y++) |
---|
367 | { |
---|
368 | CompetitiveEvaluatorThread r = new NRandomOneWayCompetitiveEvaluatorThread(); |
---|
369 | r.threadnum = y; |
---|
370 | r.numinds = numinds[y]; |
---|
371 | r.from = from[y]; |
---|
372 | r.subpop = subpop; |
---|
373 | r.me = this; |
---|
374 | r.state = state; |
---|
375 | r.p = prob; |
---|
376 | r.inds = individuals; |
---|
377 | t[y] = new Thread(r); |
---|
378 | t[y].start(); |
---|
379 | } |
---|
380 | |
---|
381 | // gather the threads |
---|
382 | for (int y=0;y<state.evalthreads;y++) |
---|
383 | try { t[y].join(); } |
---|
384 | catch(InterruptedException e) |
---|
385 | { |
---|
386 | state.output.fatal("Whoa! The main evaluation thread got interrupted! Dying..."); |
---|
387 | } |
---|
388 | } |
---|
389 | } |
---|
390 | |
---|
391 | public void evalNRandomOneWayPopChunk( final EvolutionState state, |
---|
392 | int from, int numinds, int threadnum, |
---|
393 | final Individual[] individuals, |
---|
394 | final int subpop, |
---|
395 | final GroupedProblemForm prob ) |
---|
396 | { |
---|
397 | Individual[] queue = new Individual[individuals.length]; |
---|
398 | int len = queue.length; |
---|
399 | System.arraycopy(individuals,0,queue,0,len); |
---|
400 | |
---|
401 | Individual[] competition = new Individual[2]; |
---|
402 | int subpops[] = new int[] { subpop, subpop }; |
---|
403 | boolean[] updates = new boolean[2]; |
---|
404 | updates[0] = true; |
---|
405 | updates[1] = false; |
---|
406 | int upperBound = from+numinds; |
---|
407 | |
---|
408 | for(int x=from;x<upperBound;x++) |
---|
409 | { |
---|
410 | competition[0] = individuals[x]; |
---|
411 | // fill up our tournament |
---|
412 | for(int y=0;y<groupSize;) |
---|
413 | { |
---|
414 | // swap to end and remove |
---|
415 | int index = state.random[0].nextInt(len-y); |
---|
416 | competition[1] = queue[index]; |
---|
417 | queue[index] = queue[len-y-1]; |
---|
418 | queue[len-y-1] = competition[1]; |
---|
419 | // if the opponent is not the actual individual, we can |
---|
420 | // have a competition |
---|
421 | if( competition[1] != individuals[x] ) |
---|
422 | { |
---|
423 | prob.evaluate(state,competition,updates,false,subpops, 0); |
---|
424 | y++; |
---|
425 | } |
---|
426 | } |
---|
427 | } |
---|
428 | } |
---|
429 | |
---|
430 | public void evalNRandomTwoWay( final EvolutionState state, |
---|
431 | int[] from, int[] numinds, |
---|
432 | final Individual[] individuals, int subpop, |
---|
433 | final GroupedProblemForm prob ) |
---|
434 | { |
---|
435 | if (state.evalthreads==1) |
---|
436 | evalNRandomTwoWayPopChunk(state,from[0],numinds[0],0,individuals, subpop, prob); |
---|
437 | else |
---|
438 | { |
---|
439 | Thread[] t = new Thread[state.evalthreads]; |
---|
440 | |
---|
441 | // start up the threads |
---|
442 | for (int y=0;y<state.evalthreads;y++) |
---|
443 | { |
---|
444 | CompetitiveEvaluatorThread r = new NRandomTwoWayCompetitiveEvaluatorThread(); |
---|
445 | r.threadnum = y; |
---|
446 | r.numinds = numinds[y]; |
---|
447 | r.from = from[y]; |
---|
448 | r.me = this; |
---|
449 | r.subpop = subpop; |
---|
450 | r.state = state; |
---|
451 | r.p = prob; |
---|
452 | r.inds = individuals; |
---|
453 | t[y] = new Thread(r); |
---|
454 | t[y].start(); |
---|
455 | } |
---|
456 | |
---|
457 | // gather the threads |
---|
458 | for (int y=0;y<state.evalthreads;y++) |
---|
459 | try { t[y].join(); } |
---|
460 | catch(InterruptedException e) |
---|
461 | { |
---|
462 | state.output.fatal("Whoa! The main evaluation thread got interrupted! Dying..."); |
---|
463 | } |
---|
464 | } |
---|
465 | } |
---|
466 | |
---|
467 | public void evalNRandomTwoWayPopChunk( final EvolutionState state, |
---|
468 | int from, int numinds, int threadnum, |
---|
469 | final Individual[] individuals, |
---|
470 | final int subpop, |
---|
471 | final GroupedProblemForm prob ) |
---|
472 | { |
---|
473 | |
---|
474 | // the number of games played for each player |
---|
475 | EncapsulatedIndividual[] individualsOrdered = new EncapsulatedIndividual[individuals.length]; |
---|
476 | EncapsulatedIndividual[] queue = new EncapsulatedIndividual[individuals.length]; |
---|
477 | for( int i = 0 ; i < individuals.length ; i++ ) |
---|
478 | individualsOrdered[i] = new EncapsulatedIndividual( individuals[i], 0 ); |
---|
479 | |
---|
480 | Individual[] competition = new Individual[2]; |
---|
481 | int[] subpops = new int[] { subpop, subpop }; |
---|
482 | boolean[] updates = new boolean[2]; |
---|
483 | updates[0] = true; |
---|
484 | int upperBound = from+numinds; |
---|
485 | |
---|
486 | for(int x=from;x<upperBound;x++) |
---|
487 | { |
---|
488 | System.arraycopy(individualsOrdered,0,queue,0,queue.length); |
---|
489 | competition[0] = queue[x].ind; |
---|
490 | |
---|
491 | // if the rest of individuals is not enough to fill |
---|
492 | // all games remaining for the current individual |
---|
493 | // (meaning that the current individual has left a |
---|
494 | // lot of games to play versus players with index |
---|
495 | // greater than his own), then it should play with |
---|
496 | // all. In the end, we should check that he finished |
---|
497 | // all the games he needs. If he did, everything is |
---|
498 | // ok, otherwise he should play with some other players |
---|
499 | // with index smaller than his own, but all these games |
---|
500 | // will count only for his fitness evaluation, and |
---|
501 | // not for the opponents' (unless allowOverEvaluations is set to true) |
---|
502 | |
---|
503 | // if true, it means that he has to play against all opponents with greater index |
---|
504 | if( individuals.length - x - 1 <= groupSize - queue[x].nOpponentsMet ) |
---|
505 | { |
---|
506 | for( int y = x+1 ; y < queue.length ; y++ ) |
---|
507 | { |
---|
508 | competition[1] = queue[y].ind; |
---|
509 | updates[1] = (queue[y].nOpponentsMet < groupSize) || allowOverEvaluation; |
---|
510 | prob.evaluate( state, competition, updates, false, subpops, 0 ); |
---|
511 | queue[x].nOpponentsMet++; |
---|
512 | if( updates[1] ) |
---|
513 | queue[y].nOpponentsMet++; |
---|
514 | } |
---|
515 | } |
---|
516 | else // here he has to play against a selection of the opponents with greater index |
---|
517 | { |
---|
518 | // we can use the queue structure because we'll just rearrange the indexes |
---|
519 | // but we should make sure we also rearrange the other vectors referring to the individuals |
---|
520 | |
---|
521 | for( int y = 0 ; groupSize > queue[x].nOpponentsMet ; y++ ) |
---|
522 | { |
---|
523 | // swap to the end and remove from list |
---|
524 | int index = state.random[0].nextInt( queue.length - x - 1 - y )+x+1; |
---|
525 | competition[1] = queue[index].ind; |
---|
526 | |
---|
527 | updates[1] = (queue[index].nOpponentsMet < groupSize) || allowOverEvaluation; |
---|
528 | prob.evaluate( state, competition, updates, false, subpops, 0 ); |
---|
529 | queue[x].nOpponentsMet++; |
---|
530 | if( updates[1] ) |
---|
531 | queue[index].nOpponentsMet++; |
---|
532 | |
---|
533 | // swap the players (such that a player will not be considered twice) |
---|
534 | EncapsulatedIndividual temp = queue[index]; |
---|
535 | queue[index] = queue[queue.length - y - 1]; |
---|
536 | queue[queue.length - y - 1] = temp; |
---|
537 | |
---|
538 | } |
---|
539 | |
---|
540 | } |
---|
541 | |
---|
542 | // if true, it means that the current player needs to play some games with other players with lower indexes. |
---|
543 | // this is an unfortunate situation, since all those players have already had their groupSize games for the evaluation |
---|
544 | if( queue[x].nOpponentsMet < groupSize ) |
---|
545 | { |
---|
546 | for( int y = queue[x].nOpponentsMet ; y < groupSize ; y++ ) |
---|
547 | { |
---|
548 | // select a random opponent with smaller index (don't even care for duplicates) |
---|
549 | int index; |
---|
550 | if( x > 0 ) // if x is 0, then there are no players with smaller index, therefore pick a random one |
---|
551 | index = state.random[0].nextInt( x ); |
---|
552 | else |
---|
553 | index = state.random[0].nextInt( queue.length-1 )+1; |
---|
554 | // use the opponent for the evaluation |
---|
555 | competition[1] = queue[index].ind; |
---|
556 | updates[1] = (queue[index].nOpponentsMet < groupSize) || allowOverEvaluation; |
---|
557 | prob.evaluate( state, competition, updates, false, subpops, 0 ); |
---|
558 | queue[x].nOpponentsMet++; |
---|
559 | if( updates[1] ) |
---|
560 | queue[index].nOpponentsMet++; |
---|
561 | |
---|
562 | } |
---|
563 | } |
---|
564 | |
---|
565 | } |
---|
566 | } |
---|
567 | |
---|
568 | int nextPowerOfTwo( int N ) |
---|
569 | { |
---|
570 | int i = 1; |
---|
571 | while( i < N ) |
---|
572 | i *= 2; |
---|
573 | return i; |
---|
574 | } |
---|
575 | |
---|
576 | int whereToPutInformation; |
---|
577 | void fillPositions( int[] positions, int who, int totalPerDepth, int total ) |
---|
578 | { |
---|
579 | if(totalPerDepth >= total - 1 ) |
---|
580 | { |
---|
581 | positions[whereToPutInformation] = who; |
---|
582 | whereToPutInformation++; |
---|
583 | } |
---|
584 | else |
---|
585 | { |
---|
586 | fillPositions( positions, who, totalPerDepth*2+1, total ); |
---|
587 | fillPositions( positions, totalPerDepth-who, totalPerDepth*2+1, total ); |
---|
588 | } |
---|
589 | } |
---|
590 | |
---|
591 | } |
---|
592 | |
---|
593 | // used by the K-Random-Opponents-One-Way and K-Random-Opponents-Two-Ways evaluations |
---|
594 | class EncapsulatedIndividual |
---|
595 | { |
---|
596 | public Individual ind; |
---|
597 | public int nOpponentsMet; |
---|
598 | public EncapsulatedIndividual( Individual ind_, int value_ ) |
---|
599 | { |
---|
600 | ind = ind_; |
---|
601 | nOpponentsMet = value_; |
---|
602 | } |
---|
603 | }; |
---|
604 | |
---|
605 | // used by the Single-Elimination-Tournament, (Double-Elimination-Tournament and World-Cup) evaluations |
---|
606 | class IndividualAndVictories |
---|
607 | { |
---|
608 | public Individual ind; |
---|
609 | public int victories; |
---|
610 | public IndividualAndVictories( Individual ind_, int value_ ) |
---|
611 | { |
---|
612 | ind = ind_; |
---|
613 | victories = value_; |
---|
614 | } |
---|
615 | }; |
---|
616 | |
---|
617 | class IndComparator implements SortComparator |
---|
618 | { |
---|
619 | public boolean lt(Object a, Object b) |
---|
620 | { return ((Individual)a).fitness.betterThan(((Individual)b).fitness); } |
---|
621 | public boolean gt(Object a, Object b) |
---|
622 | { return ((Individual)b).fitness.betterThan(((Individual)a).fitness); } |
---|
623 | } |
---|
624 | |
---|
625 | abstract class CompetitiveEvaluatorThread implements Runnable |
---|
626 | { |
---|
627 | public int numinds; |
---|
628 | public int from; |
---|
629 | public CompetitiveEvaluator me; |
---|
630 | public EvolutionState state; |
---|
631 | public int threadnum; |
---|
632 | public GroupedProblemForm p; |
---|
633 | public int subpop; |
---|
634 | public Individual[] inds; |
---|
635 | } |
---|
636 | |
---|
637 | class RoundRobinCompetitiveEvaluatorThread extends CompetitiveEvaluatorThread |
---|
638 | { |
---|
639 | public synchronized void run() |
---|
640 | { me.evalRoundRobinPopChunk(state,from,numinds,threadnum,inds, subpop, p); } |
---|
641 | } |
---|
642 | |
---|
643 | class NRandomOneWayCompetitiveEvaluatorThread extends CompetitiveEvaluatorThread |
---|
644 | { |
---|
645 | public synchronized void run() |
---|
646 | { me.evalNRandomOneWayPopChunk(state,from,numinds,threadnum,inds, subpop, p); } |
---|
647 | } |
---|
648 | class NRandomTwoWayCompetitiveEvaluatorThread extends CompetitiveEvaluatorThread |
---|
649 | { |
---|
650 | public synchronized void run() |
---|
651 | { me.evalNRandomTwoWayPopChunk(state,from,numinds,threadnum,inds, subpop, p); } |
---|
652 | } |
---|