Free cookie consent management tool by TermsFeed Policy Generator

source: branches/OKBJavaConnector/ECJClient/src/ec/Evolve.java @ 9286

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

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

File size: 30.8 KB
Line 
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
8package ec;
9import ec.util.*;
10import java.io.File;
11import java.io.PrintWriter;
12
13/*
14 * Evolve.java
15 *
16 * Created: Wed Aug 11 17:49:01 1999
17 * By: Sean Luke
18 */
19
20/**
21 * Evolve is the main entry class for an evolutionary computation run.
22 *
23 * <p> An EC run is done with one of two argument formats:
24 *
25 * <p><tt>java ec.Evolve -file </tt><i>parameter_file [</i><tt>-p </tt><i>parameter=value]*</i>
26 *
27 * <p>This starts a new evolutionary run, using the parameter file <i>parameter_file</i>.
28 * The user can provide optional overriding parameters on the command-line with the <tt>-p</tt> option.
29 *
30 * <p><tt>java ec.Evolve -checkpoint </tt><i>checkpoint_file</i>
31 *
32 * <p>This starts up an evolutionary run from a previous checkpoint file.
33 *
34 * <p>The basic Evolve class has a main() loop with a simple job iteration facility.
35 * If you'd like to run the evolutionary system four times, each with a different random
36 * seed, you might do:
37 *
38 * <p><tt>java ec.Evolve -file </tt><i>parameter_file</i> <tt>-p jobs=4</tt>
39 *
40 * <p>Here, Evolve will run the first time with the random seed equal to whatever's specified
41 * in your file, then job#2 will be run with the seed + 1, job#3 with the seed + 2,
42 * and job#4 with the seed + 3.  If you have multiple seeds, ECJ will try to make sure they're
43 * all different even across jobs by adding the job number * numberOfSeeds to each of them.
44 * This means that if you're doing multiple jobs with multiple seeds, you should probably set
45 * seed.0 to x, seed.1 to x+1, seed.2 to x+2, etc. for best results.  It also works if seed.0
46 * is x, seed.1 is y (a number much bigger than x), seed.2 is z (a number much bigger than y) etc.
47 *
48 * If you set seed.0=time etc. for multiple jobs, the values of each seed will be set to the
49 * current time that the job starts plus the job number * numberOfSeeds.  As current time always
50 * goes up, this shouldn't be an issue.  However it's theoretically possible that if you checkpoint and restart
51 * on another system with a clock set back in time, you could get the same seed in a later job.
52 *
53 * <p><b>main() has been designed to be modified.</b>  The comments for the Evolve.java file contain
54 * a lot discussion of how ECJ's main() bootstraps the EvolutionState object and runs it, plus a much
55 * simpler example of main() and explanations for how main() works.
56 *
57
58 <p><b>Parameters</b><br>
59 <table>
60
61 <tr><td valign=top><tt>jobs</tt></br>
62 <font size=-1> int >= 1 (default)</font></td>
63 <td valign=top>(The number of jobs to iterate.  The current job number (0...jobs-1) will be added to each seed UNLESS the seed is loaded from the system time.  The job number also gets added as a prefix (if the number of jobs is more than 1)).</td></tr>
64
65 <tr><td valign=top><tt>nostore</tt><br>
66 <font size=-1> bool = <tt>true</tt> or <tt>false</tt> (default)</font></td>
67 <td valign=top>(should the ec.util.Output facility <i>not</i> store announcements in memory?)</td></tr>
68
69 <tr><td valign=top><tt>flush</tt><br>
70 <font size=-1> bool = <tt>true</tt> or <tt>false</tt> (default)</font></td>
71 <td valign=top>(should I flush all output as soon as it's printed (useful for debugging when an exception occurs))</td></tr>
72
73 <tr><td valign=top><tt>evalthreads</tt><br>
74 <font size=-1>int &gt;= 1</font></td>
75 <td valign=top>(the number of threads to spawn for evaluation)</td></tr>
76
77 <tr><td valign=top><tt>breedthreads</tt><br>
78 <font size=-1>int &gt;= 1</font></td>
79 <td valign=top>(the number of threads to spawn for breeding)</td></tr>
80
81 <tr><td valign=top><tt>seed.</tt><i>n</i><br>
82 <font size=-1>int != 0, or string  = <tt>time</tt></font></td>
83 <td valign=top>(the seed for random number generator #<i>n</i>.  <i>n</i> should range from 0 to Max(evalthreads,breedthreads)-1.  If value is <tt>time</tt>, then the seed is based on the system clock plus <i>n</i>.)</td></tr>
84
85 <tr><td valign=top><tt>state</tt><br>
86 <font size=-1>classname, inherits and != ec.EvolutionState</font></td>
87 <td valign=top>(the EvolutionState object class)</td></tr>
88
89 <tr><td valign=top><tt>print-accessed-params</tt><br>
90 <font size=-1>bool = <tt>true</tt> or <tt>false</tt> (default)</td>
91 <td valign=top>(at the end of a run, do we print out a list of all the parameters requested during the run?)</td></tr>
92
93 <tr><td valign=top><tt>print-used-params</tt><br>
94 <font size=-1>bool = <tt>true</tt> or <tt>false</tt> (default)</td>
95 <td valign=top>(at the end of a run, do we print out a list of all the parameters actually <i>used</i> during the run?)</td></tr>
96
97 <tr><td valign=top><tt>print-unaccessed-params</tt><br>
98 <font size=-1>bool = <tt>true</tt> or <tt>false</tt> (default)</td>
99 <td valign=top>(at the end of a run, do we print out a list of all the parameters NOT requested during the run?)</td></tr>
100
101 <tr><td valign=top><tt>print-unused-params</tt><br>
102 <font size=-1>bool = <tt>true</tt> or <tt>false</tt> (default)</td>
103 <td valign=top>(at the end of a run, do we print out a list of all the parameters NOT actually used during the run?)</td></tr>
104
105 <tr><td valign=top><tt>print-all-params</tt><br>
106 <font size=-1>bool = <tt>true</tt> or <tt>false</tt> (default)</td>
107 <td valign=top>(at the end of a run, do we print out a list of all the parameters stored in the parameter database?)</td></tr>
108
109 </table>
110 *
111 *
112 * @author Sean Luke
113 * @version 1.0
114 */
115
116public class Evolve
117    {
118    public final static String P_PRINTACCESSEDPARAMETERS = "print-accessed-params";
119    public final static String P_PRINTUSEDPARAMETERS = "print-used-params";
120    public final static String P_PRINTALLPARAMETERS = "print-all-params";
121    public final static String P_PRINTUNUSEDPARAMETERS = "print-unused-params";
122    public final static String P_PRINTUNACCESSEDPARAMETERS = "print-unaccessed-params";
123
124    /** The argument indicating that we're starting up from a checkpoint file. */
125    public static final String A_CHECKPOINT = "-checkpoint";
126   
127    /** The argument indicating that we're starting fresh from a new parameter file. */
128    public static final String A_FILE = "-file";
129
130    /** evalthreads parameter */
131    public static final String P_EVALTHREADS = "evalthreads";
132
133    /** breedthreads parameter */
134    public static final String P_BREEDTHREADS = "breedthreads";
135
136    /** seed parameter */
137    public static final String P_SEED = "seed";
138
139    /** 'time' seed parameter value */
140    public static final String V_SEED_TIME = "time";
141
142    /** state parameter */
143    public static final String P_STATE = "state";
144   
145    /** 'auto' thread parameter value */
146    public static final String V_THREADS_AUTO = "auto";
147
148
149    /** Restores an EvolutionState from checkpoint if "-checkpoint FILENAME" is in the command-line arguments. */
150    public static EvolutionState possiblyRestoreFromCheckpoint(String[] args)
151        {
152        for(int x=0;x<args.length-1;x++)
153            if (args[x].equals(A_CHECKPOINT))
154                {
155                System.err.println("Restoring from Checkpoint " + args[x+1]);
156                try
157                    {
158                    return Checkpoint.restoreFromCheckpoint(args[x+1]);
159                    }
160                catch(Exception e)
161                    {
162                    Output.initialError("An exception was generated upon starting up from a checkpoint.\nHere it is:\n" + e);
163                    }
164                }
165        return null;  // should never happen
166        }
167               
168    /** Loads a ParameterDatabase from checkpoint if "-params" is in the command-line arguments. */
169    public static ParameterDatabase loadParameterDatabase(String[] args)
170        {
171        ParameterDatabase parameters = null;
172        for(int x=0;x<args.length-1;x++)
173            if (args[x].equals(A_FILE))
174                try
175                    {
176                    parameters = new ParameterDatabase(
177                        new File(new File(args[x+1]).getAbsolutePath()),
178                        args);
179                    break;
180                    }
181                catch(Exception e)
182                    {
183                    Output.initialError(
184                        "An exception was generated upon reading the parameter file \"" +
185                        args[x+1] + "\".\nHere it is:\n" + e);
186                    }
187        if (parameters==null)
188            Output.initialError("No parameter file was specified." );
189        return parameters;
190        }
191   
192   
193    /** Loads the number of threads. */
194    public static int determineThreads(Output output, ParameterDatabase parameters, Parameter threadParameter)
195        {
196        int thread = 1;
197        String tmp_s = parameters.getString(threadParameter,null);
198        if (tmp_s==null) // uh oh
199            {
200            output.fatal("Threads number must exist.",threadParameter,null);
201            }
202        else if (V_THREADS_AUTO.equalsIgnoreCase(tmp_s))
203            {
204            Runtime runtime = Runtime.getRuntime();
205            try { return ((Integer)runtime.getClass().getMethod("availableProcessors", (Class[])null).
206                    invoke(runtime,(Object[])null)).intValue(); }
207            catch (Exception e)
208                {
209                output.fatal("Whoa! This Java version is too old to have the Runtime.availableProcessors() method available.\n" +
210                    "This means you can't use 'auto' as a threads option.",threadParameter,null);
211                }
212            }
213        else
214            {
215            try
216                {
217                thread = parameters.getInt(threadParameter,null);
218                }
219            catch (NumberFormatException e)
220                {
221                output.fatal("Invalid, non-integer threads value ("+thread+")",threadParameter,null);
222                }
223            }
224        return thread;
225        }
226       
227    /** Primes the generator.  Mersenne Twister seeds its first 624 numbers using a basic
228        linear congruential generator; thereafter it uses the MersenneTwister algorithm to
229        build new seeds.  Those first 624 numbers are generally just fine, but to be extra
230        safe, you can prime the generator by calling nextInt() on it some (N>1) * 624 times.
231        This method does exactly that, presently with N=2. */
232    public static MersenneTwisterFast primeGenerator(MersenneTwisterFast generator)
233        {
234        for(int i = 0; i < 624 * 2; i++)
235            generator.nextInt();
236        return generator;
237        }
238
239    /** Loads a random generator seed.  First, the seed is loaded from the seedParameter.  If the parameter
240        is V_SEED_TIME, the seed is set to the currentTime value.  Then the seed is incremented by the offset.
241        This method is broken out of initialize(...) primarily to share code with ec.eval.MasterProblem.*/
242    public static int determineSeed(Output output, ParameterDatabase parameters, Parameter seedParameter, long currentTime, int offset, boolean auto)
243        {
244        int seed = 1;  // have to initialize to make the compiler happy
245        String tmp_s = parameters.getString(seedParameter,null);
246        if (tmp_s==null && !auto) // uh oh
247            {
248            output.fatal("Seed must exist.",seedParameter,null);
249            }
250        else if (V_SEED_TIME.equalsIgnoreCase(tmp_s) || (tmp_s == null && auto))
251            {
252            if (tmp_s == null && auto)
253                output.warnOnce("Using automatic determination number of threads, but not all seeds are defined.\nThe rest will be defined using the wall clock time.");
254            seed = (int)currentTime;  // using low-order bits so it's probably okay
255            if (seed==0)
256                output.fatal("Whoa! This Java version is returning 0 for System.currentTimeMillis(), which ain't right.  This means you can't use '"+V_SEED_TIME+"' as a seed ",seedParameter,null);
257            }
258        else
259            {
260            try
261                {
262                seed = parameters.getInt(seedParameter,null);
263                }
264            catch (NumberFormatException e)
265                {
266                output.fatal("Invalid, non-integer seed value ("+seed+")",seedParameter,null);
267                }
268            }
269        return seed + offset;
270        }
271
272
273    /** Initializes an evolutionary run given the parameters and a random seed adjustment (added to each random seed).
274        The adjustment offers a convenient way to change the seeds of the random number generators each time you
275        do a new evolutionary run.  You are of course welcome to replace the random number generators after initialize(...)
276        but before startFresh(...) */
277               
278    public static EvolutionState initialize(ParameterDatabase parameters, int randomSeedOffset)
279        {
280        Output output;
281        // 1. create the output
282
283        output = new Output(true);
284
285        // stdout is always log #0.  stderr is always log #1.
286        // stderr accepts announcements, and both are fully verbose
287        // by default.
288        output.addLog(ec.util.Log.D_STDOUT,false);
289        output.addLog(ec.util.Log.D_STDERR,true);
290               
291        // now continue intialization
292        return initialize(parameters, randomSeedOffset, output);
293        }
294
295
296    /** Initializes an evolutionary run given the parameters and a random seed adjustment (added to each random seed),
297        with the Output pre-constructed.
298        The adjustment offers a convenient way to change the seeds of the random number generators each time you
299        do a new evolutionary run.  You are of course welcome to replace the random number generators after initialize(...)
300        but before startFresh(...) */
301               
302    public static EvolutionState initialize(ParameterDatabase parameters, int randomSeedOffset, Output output)
303        {
304        EvolutionState state=null;
305        MersenneTwisterFast[] random;
306        int[] seeds;
307        int breedthreads = 1;
308        int evalthreads = 1;
309        boolean store;
310        int x;
311
312        // output was already created for us. 
313        output.systemMessage(Version.message());
314               
315        // 2. set up thread values
316       
317        breedthreads = Evolve.determineThreads(output, parameters, new Parameter(P_BREEDTHREADS));
318        evalthreads = Evolve.determineThreads(output, parameters, new Parameter(P_EVALTHREADS));
319        boolean auto = (V_THREADS_AUTO.equalsIgnoreCase(parameters.getString(new Parameter(P_BREEDTHREADS),null)) ||
320            V_THREADS_AUTO.equalsIgnoreCase(parameters.getString(new Parameter(P_EVALTHREADS),null)));  // at least one thread is automatic.  Seeds may need to be dynamic.
321
322        // 3. create the Mersenne Twister random number generators,
323        // one per thread
324
325        random = new MersenneTwisterFast[breedthreads > evalthreads ?
326            breedthreads : evalthreads];
327        seeds = new int[random.length];
328                                               
329        String seedMessage = "Seed: ";
330        int time = (int)(System.currentTimeMillis());
331        for (x=0;x<random.length;x++)
332            {
333            seeds[x] = determineSeed(output,parameters,new Parameter(P_SEED).push(""+x),
334                time+x,random.length * randomSeedOffset, auto);
335            for (int y=0;y<x;y++)
336                if (seeds[x]==seeds[y])
337                    output.fatal(P_SEED+"."+x+" ("+seeds[x]+") and "+P_SEED+"."+y+" ("+seeds[y]+") ought not be the same seed.",null,null);
338            random[x] = Evolve.primeGenerator(new MersenneTwisterFast(seeds[x]));    // we prime the generator to be more sure of randomness.
339            seedMessage = seedMessage + seeds[x] + " ";
340            }
341
342        // 4.  Start up the evolution
343               
344        // what evolution state to use?
345        state = (EvolutionState)
346            parameters.getInstanceForParameter(new Parameter(P_STATE),null,
347                EvolutionState.class);
348        state.parameters = parameters;
349        state.random = random;
350        state.output = output;
351        state.evalthreads = evalthreads;
352        state.breedthreads = breedthreads;
353        state.randomSeedOffset = randomSeedOffset;
354
355        output.systemMessage("Threads:  breed/" + breedthreads + " eval/" + evalthreads);
356        output.systemMessage(seedMessage);
357               
358        return state;
359        }
360               
361               
362    /** Begins a fresh evolutionary run with a given state.  The state should have been
363        provided by initialize(...).  The jobPrefix is added to the front of output and
364        checkpoint filenames.  If it's null, nothing is added to the front.  */
365       
366    public static void cleanup(EvolutionState state)
367        {
368        // flush the output
369        state.output.flush();
370
371        // Possibly print out the run parameters
372        PrintWriter pw = new PrintWriter(System.err);
373               
374        // before we print out access information, we need to still "get" these
375        // parameters, so that they show up as accessed and gotten.
376        state.parameters.getBoolean(new Parameter(P_PRINTUSEDPARAMETERS),null,false);
377        state.parameters.getBoolean(new Parameter(P_PRINTACCESSEDPARAMETERS),null,false);
378        state.parameters.getBoolean(new Parameter(P_PRINTUNUSEDPARAMETERS),null,false);
379        state.parameters.getBoolean(new Parameter(P_PRINTUNACCESSEDPARAMETERS),null,false);
380        state.parameters.getBoolean(new Parameter(P_PRINTALLPARAMETERS),null,false);
381               
382        //...okay, here we go...
383               
384        if (state.parameters.getBoolean(new Parameter(P_PRINTUSEDPARAMETERS),null,false))
385            {
386            pw.println("\n\nUsed Parameters\n===============\n");
387            state.parameters.listGotten(pw);
388            }
389
390        if (state.parameters.getBoolean(new Parameter(P_PRINTACCESSEDPARAMETERS),null,false))
391            {
392            pw.println("\n\nAccessed Parameters\n===================\n");
393            state.parameters.listAccessed(pw);
394            }
395
396        if (state.parameters.getBoolean(new Parameter(P_PRINTUNUSEDPARAMETERS),null,false))
397            {
398            pw.println("\n\nUnused Parameters\n"+
399                "================= (Ignore parent.x references) \n");
400            state.parameters.listNotGotten(pw);
401            }
402
403        if (state.parameters.getBoolean(new Parameter(P_PRINTUNACCESSEDPARAMETERS),null,false))
404            {
405            pw.println("\n\nUnaccessed Parameters\n"+
406                "===================== (Ignore parent.x references) \n");
407            state.parameters.listNotAccessed(pw);
408            }
409
410        if (state.parameters.getBoolean(new Parameter(P_PRINTALLPARAMETERS),null,false))
411            {
412            pw.println("\n\nAll Parameters\n==============\n");
413            // list only the parameters visible.  Shadowed parameters not shown
414            state.parameters.list(pw,false);
415            }
416
417        pw.flush();
418
419        System.err.flush();
420        System.out.flush();
421               
422        // finish by closing down Output.  This is because gzipped and other buffered
423        // streams just don't shut write themselves out, and finalize isn't called
424        // on them because Java's being obnoxious.  Pretty stupid.
425        state.output.close();
426        }
427
428
429
430
431/*
432
433 * MAIN
434 *
435 * Evolve has... evolved from previous Evolves.  The goal behind these changes is:
436 *       1. To provide a simple jobs facility
437 *       2. To make it easy for you to make your own main(), including more
438 *          sophisticated jobs facilities.
439 *
440 * Before we get into the specifics of this file, let's first look at the main
441 * evolution loop in EvolutionState.java.  The general code is:
442 *       1.  If I was loaded from a checkpoint, call the hook startFromCheckpoint()
443 *       2.  If I'm instead starting from scratch, call the hook startFresh()
444 *       3.  Loop:
445 *               4. result = evolve()
446 *               5. If result != EvolutionState.R_NOTDONE, break from loop
447 *       6.      Call the hook finish(result)
448 *
449 * That's all there's to it.  Various EvolutionState classes need to implement
450 * the startFromCheckpoint, startFresh, evolve, and finish methods.  This basic
451 * evolution loop is encapsulated in a convenience method called EvolutionState.run(...).
452 *
453 * Evolve.java is little more than code to fire up the right EvolutionState class,
454 * call run(...), and then shut down.  The complexity mostly comes from bringing
455 * up the class (loading it from checkpoint or from scratch) and in shutting down.
456 * Here's the general mechanism:
457 *
458 * - To load from checkpoint, we must find the checkpoint filename and call
459 *       Checkpoint.restoreFromCheckpoint(filename) to generate the EvolutionState
460 *       instance.  Evolve.java provides a convenience function for this called
461 *       possiblyRestoreFromCheckpoint(...), which returns null if there *isn't*
462 *       a checkpoint file to load from.  Else it returns the unfrozen EvolutionState.
463 *       
464 * - To instead set up from scratch, you have to do a bunch of stuff to set up the state.
465 *       First, you need to load a parameter database.  Evolve.java has a convenience function
466 *       for that called loadParameterDatabase(...).  Second, you must do a series
467 *       of items: (1) generate an Output object (2) identify the number of threads
468 *       (3) create the MersenneTwisterFast random number generators (4) instantiate
469 *       the EvolutionState subclass instance (5) plug these items, plus the random
470 *       seed offset and the parameter database, into the instance.  These five
471 *       steps are done for you in a convenience function called initialize(...).
472 *
473 * -     Now the state is ready to go. Call run(...) on your EvolutionState
474 *       (or do the evolution loop described above manually if you wish)
475 *
476 * - Finally, to shut down, you need to (1) flush the Output (2) print out
477 *       the used, accessed, unused, unaccessed, and all parameters if the user
478 *       requested a printout at the end [rarely] (3) flush System.err and System.out
479 *       for good measure, and (4) close Output -- which closes its streams except
480 *       for System.err and System.out.  There is a convenience function for this as
481 *       well.  It's called cleanup(...).
482 *       
483 * - Last, you shut down with System.exit(0) -- very important because it quits
484 *       any remaining threads the user might have had running and forgot about.
485 *       
486 * So there you have it.  Several convenience functions in Evolve...
487 *       Evolve.possiblyRestoreFromCheckpoint
488 *       Evolve.loadParameterDatabase
489 *       Evolve.initialize
490 *       EvolutionState.run
491 *       Evolve.cleanup
492 * ... result in a very simple basic main() function:
493 *       
494 *
495 *               public static void main(String[] args)
496 *                       {
497 *                       EvolutionState state = possiblyRestoreFromCheckpoint(args);
498 *                       if (state!=null)  // loaded from checkpoint
499 *                               state.run(EvolutionState.C_STARTED_FROM_CHECKPOINT);
500 *                       else
501 *                               {
502 *                               state = initialize(loadParameterDatabase(args), 0);
503 *                               state.run(EvolutionState.C_STARTED_FRESH);
504 *                               }
505 *                       cleanup(state);
506 *                       System.exit(0);
507 *                       }
508 *
509 *
510 * Piece of cake!
511 *
512 * The more extravagant main(...) you see below just has a few extra gizmos for
513 * doing basic job iteration.  EvolutionState has two convenience slots for
514 * doing job iteration:
515 *
516 *       job                                     (an Object[]    use this as you like)
517 *       runtimeArguments        (a String[]             put args in here)
518 *
519 * The reason these are slots in EvolutionState is so you can store this information
520 * across checkpoints and continue where you had started job-number-wise when the
521 * user starts up from a checkpoint again.
522 *
523 * You'll probably want the EvolutionState to output its stat files etc. using unique
524 * prefixes to differentiate between jobs (0.stat, 1.stat, or whatever you like -- it
525 * doesn't have to be numbers), and you'll also probably want checkpoint files to be
526 * similarly prefixed.  So you'll probably want to do:
527 *
528 *       state.output.setFilePrefix(jobPrefix);
529 *       state.checkpointPrefix = jobPrefix + state.checkpointPrefix;
530 *
531 * The extravagant main below is basically doing this.  We're using state.job to stash
532 * away a single iterated job number, stored as an Integer in state.job[0], and then
533 * iterating that way, making sure we stash the job number and runtime arguments each time
534 * so we can recover them when loading from checkpoint.  We use the "jobs" parameter
535 * to determine how many jobs to run.  If this number is 1, we don't even bother to set
536 * the file prefixes, so ECJ generates files just like it used to.
537 *
538 * It's important to note that this main was created with the assumption that you might
539 * modify it for your own purposes.  Do you want a nested loop, perhaps to do all combinations
540 * of two parameters or something?  Rewrite it to use two array slots in the job array.
541 * Want to store more information on a per-job basis?  Feel free to use the job array any
542 * way you like -- it's ONLY used by this main() loop.
543 *
544 */
545
546
547
548
549
550
551    /** Top-level evolutionary loop.  */
552
553    public static void main(String[] args)
554        {
555        EvolutionState state;
556        ParameterDatabase parameters;
557               
558        // if we're loading from checkpoint, let's finish out the most recent job
559        state = possiblyRestoreFromCheckpoint(args);
560        int currentJob = 0;                             // the next job number (0 by default)
561
562        // this simple job iterator just uses the 'jobs' parameter, iterating from 0 to 'jobs' - 1
563        // inclusive.  The current job number is stored in state.jobs[0], so we'll begin there if
564        // we had loaded from checkpoint.
565               
566        if (state != null)  // loaded from checkpoint
567            {
568            // extract the next job number from state.job[0] (where in this example we'll stash it)
569            try
570                {
571                if (state.runtimeArguments == null)
572                    Output.initialError("Checkpoint completed from job started by foreign program (probably GUI).  Exiting...");
573                args = state.runtimeArguments;                          // restore runtime arguments from checkpoint
574                currentJob = ((Integer)(state.job[0])).intValue() + 1;  // extract next job number
575                }
576            catch (Exception e)
577                {
578                Output.initialError("EvolutionState's jobs variable is not set up properly.  Exiting...");
579                }
580
581            state.run(EvolutionState.C_STARTED_FROM_CHECKPOINT);
582            cleanup(state);
583            }
584
585        // A this point we've finished out any previously-checkpointed job.  If there was
586        // one such job, we've updated the current job number (currentJob) to the next number.
587        // Otherwise currentJob is 0.
588
589        // Now we're going to load the parameter database to see if there are any more jobs.
590        // We could have done this using the previous parameter database, but it's no big deal.
591        parameters = loadParameterDatabase(args);
592        if (currentJob == 0)  // no current job number yet
593            currentJob = parameters.getIntWithDefault(new Parameter("current-job"), null, 0);
594        if (currentJob < 0)
595            Output.initialError("The 'current-job' parameter must be >= 0 (or not exist, which defaults to 0)");
596           
597        int numJobs = parameters.getIntWithDefault(new Parameter("jobs"), null, 1);
598        if (numJobs < 1)
599            Output.initialError("The 'jobs' parameter must be >= 1 (or not exist, which defaults to 1)");
600               
601               
602        // Now we know how many jobs remain.  Let's loop for that many jobs.  Each time we'll
603        // load the parameter database scratch (except the first time where we reuse the one we
604        // just loaded a second ago).  The reason we reload from scratch each time is that the
605        // experimenter is free to scribble all over the parameter database and it'd be nice to
606        // have everything fresh and clean.  It doesn't take long to load the database anyway,
607        // it's usually small.
608        for(int job = currentJob ; job < numJobs; job++)
609            {
610            try
611                {
612                // load the parameter database (reusing the very first if it exists)
613                if (parameters == null)
614                    parameters = loadParameterDatabase(args);
615                           
616                // Initialize the EvolutionState, then set its job variables
617                state = initialize(parameters, job);                // pass in job# as the seed increment
618                state.output.systemMessage("Job: " + job);
619                state.job = new Object[1];                                  // make the job argument storage
620                state.job[0] = new Integer(job);                    // stick the current job in our job storage
621                state.runtimeArguments = args;                              // stick the runtime arguments in our storage
622                if (numJobs > 1)                                                    // only if iterating (so we can be backwards-compatible),
623                    {
624                    String jobFilePrefix = "job." + job + ".";
625                    state.output.setFilePrefix(jobFilePrefix);     // add a prefix for checkpoint/output files
626                    state.checkpointPrefix = jobFilePrefix + state.checkpointPrefix;  // also set up checkpoint prefix
627                    }
628                                   
629                // Here you can set up the EvolutionState's parameters further before it's setup(...).
630                // This includes replacing the random number generators, changing values in state.parameters,
631                // changing instance variables (except for job and runtimeArguments, please), etc.
632
633
634
635
636
637                // now we let it go
638                state.run(EvolutionState.C_STARTED_FRESH);
639                cleanup(state);  // flush and close various streams, print out parameters if necessary
640                parameters = null;  // so we load a fresh database next time around
641                }
642            catch (Throwable e)  // such as an out of memory error caused by this job
643                {
644                e.printStackTrace();
645                state = null;
646                System.gc();  // take a shot!
647                }
648            }
649
650        System.exit(0);
651        }
652    }
Note: See TracBrowser for help on using the repository browser.