Free cookie consent management tool by TermsFeed Policy Generator

source: branches/OKBJavaConnector/ECJClient/src/ec/eval/MasterProblem.java @ 8614

Last change on this file since 8614 was 6152, checked in by bfarka, 14 years ago

added ecj and custom statistics to communicate with the okb services #1441

File size: 12.5 KB
Line 
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
8package ec.eval;
9
10import ec.*;
11import ec.util.*;
12import ec.coevolve.GroupedProblemForm;
13import ec.simple.SimpleProblemForm;
14import ec.steadystate.QueueIndividual;
15import java.util.ArrayList;
16
17import java.io.*;
18
19/**
20 * MasterProblem.java
21 *
22
23 <p>The MasterProblem is a special ECJ problem that performs evaluations by sending them to
24 a remote Slave process to be evaluated.  As it implements both the
25 <i>SimpleProblemForm</i> and the <i>GroupedProblemForm</i> interfaces, the MasterProblem
26 can perform both traditional EC evaluations as well as coevolutionary evaluations.
27 
28 <p>When a MasterProblem is specified by the Evaluator, the Problem is set up as usual, but then
29 the MasterProblem replaces it.  The Problem is not garbage collected -- instead, it's hung off the
30 MasterProblem's <tt>problem</tt> variable.  In some sense the Problem is "pushed aside".
31 
32 <p>If the Evaluator begins by calling prepareToEvaluate(), and we're not doing coevolution, then
33 the MasterProblem does not evaluate individuals immediately.  Instead, it waits for at most
34 <i>jobSize</i> individuals be submitted via evaluate(), and then sends them all off in a group,
35 called a <i>job</i>, to the remote slave.  In other situations (coevolution, or no prepareToEvaluate())
36 the MasterProblem sends off individuals immediately.
37 
38 <p>It may be the case that no Slave has space in its queue to accept a new job containing, among others,
39 your new individual.  In this case, calling evaluate() will block until one comes available.  You can avoid
40 this by testing for availability first by calling canEvaluate().  Note that canEvaluate() and evaluate()
41 together are not atomic and so you should not rely on this facility if your system uses multiple threads.
42 
43 <P>When the individuals or their fitnesses return, they are immediately updated in place.  You have three
44 options to wait for them:
45 
46 <ul>
47 <li><p>You can wait for all the individuals to finish evaluation by calling finishEvaluating().
48 If you call this method before a job is entirely filled, it will be sent in truncated format (which
49 generally is perfectly fine).  You then block until all the jobs have been completed and the individuals
50 updated.
51   
52 <li><p>You can block until at least one individual is available, by calling getNextEvaluatedIndividual(),
53 which blocks and then returns the individual that was just completed.
54   
55 <li><p>You can test in non-blocking fashion to see if an individual is available, by calling
56 evaluatedIndividualAvailable().  If this returns true, you may then call getNextEvaluatedIndividual()
57 to get the individual.  Note that this isn't atomic, so don't use it if you have multiple threads.
58 </ul>
59 
60 <p><b>Parameters</b><br>
61 <table>
62 <tr><td valign=top><i>base.</i><tt>debug-info</tt><br>
63 <font size=-1>boolean</font></td>
64 <td valign=top>(whether the system should display information useful for debugging purposes)<br>
65
66 <tr><td valign=top><i>base.</i><tt>job-size</tt><br>
67 <font size=-1>integer &gt; 0 </font></td>
68 <td valign=top>(how large should a job be at most?)<br>
69 </td></tr>
70
71
72 <!-- technically these are handled by the SlaveMonitor -->
73
74 <tr><td valign=top><tt>eval.master.port</tt><br>
75 <font size=-1>int</font></td>
76 <td valign=top>(the port where the slaves will connect)<br>
77 </td></tr>
78 <tr><td valign=top><tt>eval.compression</tt><br>
79 <font size=-1>boolean</font></td>
80 <td valign=top>(whether the communication with the slaves should be compressed or not)<br>
81 </td></tr>
82 <tr><td valign=top><tt>eval.masterproblem.max-jobs-per-slave</tt><br>
83 <font size=-1>int</font></td>
84 <td valign=top>(the maximum load (number of jobs) per slave at any point in time)<br>
85 </td></tr>
86
87 </table>
88
89 * @author Liviu Panait, Keith Sullivan, and Sean Luke
90 * @version 1.0
91 */
92
93public class MasterProblem extends Problem implements SimpleProblemForm, GroupedProblemForm
94    {
95    public static final String P_DEBUG_INFO = "debug-info";
96    public static final String P_JOB_SIZE = "job-size";
97       
98    int jobSize;
99    boolean showDebugInfo;
100    public Problem problem;
101    public boolean batchMode;
102    public SlaveMonitor monitor;
103
104    // except for the problem, everything else is shallow-cloned
105    public Object clone()
106        {
107        MasterProblem c = (MasterProblem)(super.clone());
108
109        // shallow-cloned stuff
110        c.monitor = monitor;
111        c.batchMode = batchMode;
112        c.jobSize = jobSize;
113        c.showDebugInfo = showDebugInfo;
114
115        // deep-cloned stuff
116        c.problem = (Problem)(problem.clone());
117
118        return c;
119        }
120
121    // setup
122    public void setup(final EvolutionState state, final Parameter base)
123        {
124        Thread.currentThread().setName("MainThread: ");
125        super.setup(state, base);
126        showDebugInfo = state.parameters.getBoolean(base.push(P_DEBUG_INFO),null,false);
127               
128        jobSize = state.parameters.getIntWithDefault(base.push(P_JOB_SIZE),null,1);
129        if (jobSize<=0)
130            state.output.fatal("The job size must be an integer > 0.", base.push(P_JOB_SIZE));
131
132        batchMode = false;
133        }
134
135    // prepare for a batch of evaluations
136    public void prepareToEvaluate(final EvolutionState state, final int threadnum)
137        {
138        if (jobSize > 1) queue = new ArrayList();
139        batchMode = true;
140        }
141
142    // wait until a batch of evaluations is finished
143    public void finishEvaluating(final EvolutionState state, final int threadnum)
144        {
145        if(showDebugInfo)
146            state.output.message(Thread.currentThread().getName() + "Waiting for all slaves to finish.");
147        flush(state, threadnum);
148        queue = null;  // get rid of it just in case
149               
150        monitor.waitForAllSlavesToFinishEvaluating( state );
151        batchMode = false;
152        if(showDebugInfo)
153            state.output.message(Thread.currentThread().getName() + "All slaves have finished their jobs.");
154        }
155
156    // evaluate a regular individual
157    public void evaluate(EvolutionState state, Individual ind, int subpopulation, int threadnum)
158        {
159        if (jobSize > 1 && batchMode == true)    // chunked evaluation mechanism
160            {
161            queue.add(new QueueIndividual(ind, subpopulation));
162            if (queue.size() >= jobSize)
163                flush(state, threadnum);
164            }
165        else    /// ordinary evaluation mechanism 
166            evaluate(state, new Individual[] { ind }, new int[] { subpopulation }, threadnum);           
167        }
168       
169       
170    ArrayList queue;
171    void flush(EvolutionState state, int threadnum)
172        {
173        int subpopulation;
174        if (queue!=null && queue.size() > 0 )
175            {
176            Individual[] inds = new Individual[queue.size()];
177            int[] subpopulations = new int[queue.size()];
178            for(int i = 0; i < queue.size(); i++)
179                {
180                QueueIndividual qind = (QueueIndividual)(queue.get(i));
181                inds[i] = qind.ind;
182                subpopulations[i] = qind.subpop;
183                }
184            evaluate(state, inds, subpopulations, threadnum);
185            }
186        queue = new ArrayList();
187        }
188
189
190    // send a group of individuals to one slave for evaluation
191    void evaluate(EvolutionState state, Individual inds[], int[] subpopulations, int threadnum)
192        {
193        if(showDebugInfo)
194            state.output.message(Thread.currentThread().getName() + "Starting a " + (batchMode ? "batched " : "") + "SimpleProblemForm evaluation.");
195
196        // Acquire a slave socket
197        Job job = new Job();
198        job.type = Slave.V_EVALUATESIMPLE;
199        job.inds = inds;
200        job.subPops = subpopulations ;
201        job.updateFitness = new boolean[inds.length];
202        for (int i=0 ; i < inds.length; i++)
203            job.updateFitness[i]=true;
204        monitor.scheduleJobForEvaluation(state,job);
205        if( !batchMode )
206            monitor.waitForAllSlavesToFinishEvaluating( state );
207        if(showDebugInfo) state.output.message(Thread.currentThread().getName() + "Finished a " + (batchMode ? "batched " : "") + "SimpleProblemForm evaluation.");
208        }
209       
210       
211       
212
213    /* (non-Javadoc)
214     * @see ec.simple.SimpleProblemForm#describe(ec.EvolutionState, ec.Individual, int, int)
215     */
216    public void describe(EvolutionState state, Individual ind, int subpopulation, int threadnum, int log)
217        {
218        if ((problem instanceof SimpleProblemForm))
219            {
220            ((SimpleProblemForm)problem).describe(state, ind, subpopulation, threadnum, log);
221            }
222        }
223
224    /* (non-Javadoc)
225     * @see ec.coevolve.GroupedProblemForm#preprocessPopulation(ec.EvolutionState, ec.Population)
226     */
227    public void preprocessPopulation(EvolutionState state, Population pop, boolean countVictoriesOnly)
228        {
229        if (!(problem instanceof GroupedProblemForm))
230            {
231            state.output.fatal("MasterProblem.preprocessPopulation(...) invoked, but the underlying Problem is not of GroupedProblemForm");
232            }
233               
234        ((GroupedProblemForm) problem).preprocessPopulation(state, pop, countVictoriesOnly);
235        }
236
237    /* (non-Javadoc)
238     * @see ec.coevolve.GroupedProblemForm#postprocessPopulation(ec.EvolutionState, ec.Population)
239     */
240    public void postprocessPopulation(EvolutionState state, Population pop, boolean countVictoriesOnly)
241        {
242        if (!(problem instanceof GroupedProblemForm))
243            {
244            state.output.fatal("MasterProblem.postprocessPopulation(...) invoked, but the underlying Problem is not of GroupedProblemForm");
245            }
246               
247        ((GroupedProblemForm) problem).postprocessPopulation(state, pop, countVictoriesOnly);
248        }
249
250    // regular coevolutionary evaluation
251    public void evaluate(EvolutionState state, Individual[] inds,
252        boolean[] updateFitness, boolean countVictoriesOnly, int[] subpops, int threadnum)
253        {
254        if(showDebugInfo)
255            state.output.message("Starting a GroupedProblemForm evaluation.");
256
257        // Acquire a slave socket
258        Job job = new Job();
259        job.type = Slave.V_EVALUATEGROUPED;
260        job.subPops = subpops;
261        job.countVictoriesOnly = countVictoriesOnly;
262        job.inds = inds;
263        job.updateFitness = updateFitness;
264        monitor.scheduleJobForEvaluation(state,job);
265               
266        if( !batchMode )
267            monitor.waitForAllSlavesToFinishEvaluating( state );
268
269        if(showDebugInfo)
270            state.output.message("Finished the GroupedProblemForm evaluation.");
271        }
272
273    /** Custom serialization */
274    private void writeObject(ObjectOutputStream out) throws IOException
275        {
276        out.writeObject(problem);
277        }
278
279    /** Custom serialization */
280    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException
281        {
282        problem = (Problem) in.readObject();
283        }
284
285    /** Initialize contacts with the slaves */
286    public void initializeContacts( final EvolutionState state )
287        {
288        if(showDebugInfo)
289            state.output.message(Thread.currentThread().getName() + "Spawning the server thread.");
290        monitor = new SlaveMonitor(state, showDebugInfo);
291        }
292
293    /** Reinitialize contacts with the slaves */
294    public void reinitializeContacts( final EvolutionState state )
295        {
296        initializeContacts(state);
297        }
298
299    /** Gracefully close contacts with the slaves */
300    public void closeContacts(EvolutionState state, int result)
301        {
302        monitor.shutdown();
303        }
304       
305    public boolean canEvaluate()
306        {
307        return (monitor.numAvailableSlaves() != 0);
308        }
309       
310    /** This will only return true if (1) the EvolutionState is a SteadyStateEvolutionState and
311        (2) an individual has returned from the system.  If you're not doing steady state evolution,
312        you should not call this method.  */
313    public boolean evaluatedIndividualAvailable()
314        {
315        return monitor.evaluatedIndividualAvailable();
316        }
317   
318    /** This method blocks until an individual is available from the slaves (which will cause evaluatedIndividualAvailable()
319        to return true), at which time it returns the individual.  You should only call this method
320        if you're doing steady state evolution -- otherwise, the method will block forever. */
321    public QueueIndividual getNextEvaluatedIndividual()
322        {
323        return monitor.waitForIndividual();
324        }
325    }
Note: See TracBrowser for help on using the repository browser.