source: java/ecj/cecj/eval/TournamentCoevolutionaryEvaluator.java @ 28

Last change on this file since 28 was 28, checked in by mszubert, 15 years ago

cecj - coEvolutionary Computation in Java with additional games package

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 6.6 KB
Line 
1package cecj.eval;
2
3import cecj.interaction.InteractionResult;
4import cecj.problems.SymmetricCompetitionProblem;
5import ec.EvolutionState;
6import ec.Individual;
7import ec.simple.SimpleFitness;
8import ec.util.Parameter;
9
10/**
11 * Single elimination tournament competitive evaluator. It is different from the other
12 * coevolutionary evaluators because interactions between individuals must be simulated in strict
13 * order. It depends on the outcome of previous interaction if the individual can compete further.
14 *
15 * Assumes that individuals use <code>SimpleFitness</code>. The fitness assigned by this method is
16 * equal to the height of the tournament subtree that particular individual has traversed - the
17 * number of games won. If a series of tournaments is organized (i.e. <code>repeats</code> parameter
18 * is greater than 1), the fitness is summed over all the tournaments.
19 *
20 * This evaluator can be used if problem being solved implements
21 * <code>SymmetricCompetitionProblem</code> interface.
22 *
23 * It cannot employ any other mechanisms like archiving or fitness sharing because the interactions
24 * scheme is very different and hard to generalize.
25 *
26 * @author Marcin Szubert
27 *
28 */
29public class TournamentCoevolutionaryEvaluator extends CoevolutionaryEvaluator {
30
31        private static final String P_REPEATS = "repeats";
32
33        /**
34         * Specifies how many times the tournament should be repeated during single evaluation process.
35         * More repeats can reduce the noise of this evaluation scheme.
36         */
37        private int tournamentRepeats;
38
39        private SymmetricCompetitionProblem problem;
40
41        /**
42         * Represents competing individuals.
43         */
44        private Individual[] competitors;
45
46        /**
47         * Number of competitors - size of the particular subpopulation.
48         */
49        private int numCompetitors;
50
51        /**
52         * Points gathered during the course of competition.
53         */
54        private int[] points;
55
56        /**
57         * An array used as a tournament tree representation. It stores indices of competing
58         * individuals. Neighbouring indices copmete with each other in certain round.
59         */
60        private int[] competition;
61
62        /**
63         * Stores active competitors ready to be divided into pairs.
64         */
65        private int[] activeCompetitors;
66
67        /**
68         * Indicates if particular competitor is still in game.
69         */
70        private boolean[] active;
71
72        @Override
73        public void setup(final EvolutionState state, final Parameter base) {
74                super.setup(state, base);
75
76                if (!(p_problem instanceof SymmetricCompetitionProblem)) {
77                        state.output.fatal("Tournament evaluator can be used only with symmetric problems");
78                } else {
79                        problem = (SymmetricCompetitionProblem) p_problem;
80                }
81
82                Parameter repeatsParameter = base.push(P_REPEATS);
83                tournamentRepeats = state.parameters.getIntWithDefault(repeatsParameter, null, 1);
84                if (tournamentRepeats <= 0) {
85                        state.output.fatal("Tournament repeats parameter can not be negative.",
86                                repeatsParameter);
87                }
88        }
89
90        @Override
91        public void evaluatePopulation(EvolutionState state) {
92                for (int subpop = 0; subpop < numSubpopulations; subpop++) {
93                        prepareTournament(state, subpop);
94                        for (int r = 0; r < tournamentRepeats; r++) {
95                                makeTournament(state);
96                        }
97                        assignFitness(state);
98                }
99        }
100
101        /**
102         * Initializes structures used in the tournament series.
103         *
104         * @param state
105         * @param subpop
106         */
107        private void prepareTournament(EvolutionState state, int subpop) {
108                competitors = state.population.subpops[subpop].individuals;
109                numCompetitors = competitors.length;
110
111                points = new int[numCompetitors];
112                active = new boolean[numCompetitors];
113                competition = new int[numCompetitors];
114                activeCompetitors = new int[numCompetitors];
115        }
116
117        /**
118         * Plays a single tournament between earlier selected competitors from particular subpopulation.
119         * Each tournament consists of a sequence of rounds. In each round number of active competitors
120         * is reduced by half according to the results of their games (approximately - if at the start
121         * of the round number of players is odd, one player is given a "bye" and advances to the next
122         * round directly). At the beginning of each round there is a drawing which assigns competitors
123         * in pairs.
124         *
125         * @param state
126         */
127        private void makeTournament(EvolutionState state) {
128                int numActiveCompetitors;
129                for (int c = 0; c < numCompetitors; c++) {
130                        active[c] = true;
131                }
132
133                while ((numActiveCompetitors = findActiveCompetitors()) > 1) {
134                        shuffleCompetitors(state, numActiveCompetitors);
135                        playTournamentRound(state, numActiveCompetitors);
136                }
137        }
138
139        /**
140         * Assign fitness value to each competing individual according to overall points which it has
141         * gathered during the series of tournaments.
142         *
143         * @param state
144         */
145        private void assignFitness(EvolutionState state) {
146                for (int c = 0; c < numCompetitors; c++) {
147                        Individual competitor = competitors[c];
148                        ((SimpleFitness) competitor.fitness).setFitness(state, points[c], false);
149                }
150        }
151
152        /**
153         * Finds still active competitors according to <code>active</code> array. Found competitor
154         * indices are stored in <code>activeCompetitors</code> array and their number is returned.
155         *
156         * @return number of still active competitors
157         */
158        private int findActiveCompetitors() {
159                int competitors = 0;
160                for (int c = 0; c < numCompetitors; c++) {
161                        if (active[c]) {
162                                activeCompetitors[competitors++] = c;
163                        }
164                }
165                return competitors;
166        }
167
168        /**
169         * Randomly shuffles competitors indices taken from <
170         *
171         * @param state
172         * @param source
173         * @param target
174         * @param count
175         */
176        private void shuffleCompetitors(EvolutionState state, int count) {
177                int left = count;
178                for (int i = 0; i < count; i++) {
179                        int rand = state.random[0].nextInt(left);
180                        competition[i] = activeCompetitors[rand];
181                        activeCompetitors[rand] = activeCompetitors[--left];
182                }
183        }
184
185        /**
186         * Arranges a competition between neighbours in <code>competition</code> array.
187         *
188         * @param state
189         * @param numCompetitors
190         */
191        private void playTournamentRound(EvolutionState state, int numCompetitors) {
192                for (int i = 0; i + 1 < numCompetitors; i += 2) {
193                        Individual c1 = competitors[competition[i]];
194                        Individual c2 = competitors[competition[i + 1]];
195
196                        // TODO: consider if it is needed to call compete method twice
197                        // maybe it should use internal individual's fitness or return both results at once?
198                        InteractionResult score1 = problem.compete(state, c1, c2).first;
199                        InteractionResult score2 = problem.compete(state, c2, c1).first;
200
201                        if (score1.betterThan(score2)) {
202                                points[competition[i]]++;
203                                active[competition[i + 1]] = false;
204                        } else {
205                                points[competition[i + 1]]++;
206                                active[competition[i]] = false;
207                        }
208                }
209
210                // TODO: in case of odd number of competitors, should the one given a "bye" achieve a point
211                // in this round?
212                if (numCompetitors % 2 != 0) {
213                        points[competition[numCompetitors - 1]]++;
214                }
215        }
216}
Note: See TracBrowser for help on using the repository browser.