/*
Copyright 2006 by Sean Luke
Licensed under the Academic Free License version 3.0
See the file "LICENSE" for more information
*/
package ec;
import ec.util.*;
import java.io.File;
import java.io.PrintWriter;
/*
* Evolve.java
*
* Created: Wed Aug 11 17:49:01 1999
* By: Sean Luke
*/
/**
* Evolve is the main entry class for an evolutionary computation run.
*
* An EC run is done with one of two argument formats:
*
*
java ec.Evolve -file parameter_file [-p parameter=value]*
*
*
This starts a new evolutionary run, using the parameter file parameter_file.
* The user can provide optional overriding parameters on the command-line with the -p option.
*
*
java ec.Evolve -checkpoint checkpoint_file
*
*
This starts up an evolutionary run from a previous checkpoint file.
*
*
The basic Evolve class has a main() loop with a simple job iteration facility.
* If you'd like to run the evolutionary system four times, each with a different random
* seed, you might do:
*
*
java ec.Evolve -file parameter_file -p jobs=4
*
*
Here, Evolve will run the first time with the random seed equal to whatever's specified
* in your file, then job#2 will be run with the seed + 1, job#3 with the seed + 2,
* and job#4 with the seed + 3. If you have multiple seeds, ECJ will try to make sure they're
* all different even across jobs by adding the job number * numberOfSeeds to each of them.
* This means that if you're doing multiple jobs with multiple seeds, you should probably set
* seed.0 to x, seed.1 to x+1, seed.2 to x+2, etc. for best results. It also works if seed.0
* is x, seed.1 is y (a number much bigger than x), seed.2 is z (a number much bigger than y) etc.
*
* If you set seed.0=time etc. for multiple jobs, the values of each seed will be set to the
* current time that the job starts plus the job number * numberOfSeeds. As current time always
* goes up, this shouldn't be an issue. However it's theoretically possible that if you checkpoint and restart
* on another system with a clock set back in time, you could get the same seed in a later job.
*
*
main() has been designed to be modified. The comments for the Evolve.java file contain
* a lot discussion of how ECJ's main() bootstraps the EvolutionState object and runs it, plus a much
* simpler example of main() and explanations for how main() works.
*
Parameters
jobs
int >= 1 (default)
(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)).
nostore
bool = true or false (default)
(should the ec.util.Output facility not store announcements in memory?)
flush
bool = true or false (default)
(should I flush all output as soon as it's printed (useful for debugging when an exception occurs))
evalthreads
int >= 1
(the number of threads to spawn for evaluation)
breedthreads
int >= 1
(the number of threads to spawn for breeding)
seed.n
int != 0, or string = time
(the seed for random number generator #n. n should range from 0 to Max(evalthreads,breedthreads)-1. If value is time, then the seed is based on the system clock plus n.)
state
classname, inherits and != ec.EvolutionState
(the EvolutionState object class)
print-accessed-params
bool = true or false (default)
(at the end of a run, do we print out a list of all the parameters requested during the run?)
print-used-params
bool = true or false (default)
(at the end of a run, do we print out a list of all the parameters actually used during the run?)
print-unaccessed-params
bool = true or false (default)
(at the end of a run, do we print out a list of all the parameters NOT requested during the run?)
print-unused-params
bool = true or false (default)
(at the end of a run, do we print out a list of all the parameters NOT actually used during the run?)
print-all-params
bool = true or false (default)
(at the end of a run, do we print out a list of all the parameters stored in the parameter database?)
*
*
* @author Sean Luke
* @version 1.0
*/
public class Evolve
{
public final static String P_PRINTACCESSEDPARAMETERS = "print-accessed-params";
public final static String P_PRINTUSEDPARAMETERS = "print-used-params";
public final static String P_PRINTALLPARAMETERS = "print-all-params";
public final static String P_PRINTUNUSEDPARAMETERS = "print-unused-params";
public final static String P_PRINTUNACCESSEDPARAMETERS = "print-unaccessed-params";
/** The argument indicating that we're starting up from a checkpoint file. */
public static final String A_CHECKPOINT = "-checkpoint";
/** The argument indicating that we're starting fresh from a new parameter file. */
public static final String A_FILE = "-file";
/** The argument indicating that we're starting fresh from a parameter file stored in a jar file or as some resource. */
public static final String A_FROM = "-from";
/** The argument indicating the class where the resource is relative to. */
public static final String A_AT = "-at";
/** The argument indicating a request to print out the help message. */
public static final String A_HELP = "-help";
/** evalthreads parameter */
public static final String P_EVALTHREADS = "evalthreads";
/** breedthreads parameter */
public static final String P_BREEDTHREADS = "breedthreads";
/** seed parameter */
public static final String P_SEED = "seed";
/** 'time' seed parameter value */
public static final String V_SEED_TIME = "time";
/** state parameter */
public static final String P_STATE = "state";
/** 'auto' thread parameter value */
public static final String V_THREADS_AUTO = "auto";
/** Should we muzzle stdout and stderr? */
public static final String P_SILENT = "silent";
/** Should we muzzle stdout and stderr? [deprecated] */
static final String P_MUZZLE = "muzzle";
/** Optionally prints the help message. */
public static void checkForHelp(String[] args)
{
for(int x=0;x1) * 624 times.
This method does exactly that, presently with N=2. */
public static MersenneTwisterFast primeGenerator(MersenneTwisterFast generator)
{
// 624 = MersenneTwisterFast.N which is private duh
for(int i = 0; i < 624 * 2 + 1; i++)
generator.nextInt();
return generator;
}
/** Loads a random generator seed. First, the seed is loaded from the seedParameter. If the parameter
is V_SEED_TIME, the seed is set to the currentTime value. Then the seed is incremented by the offset.
This method is broken out of initialize(...) primarily to share code with ec.eval.MasterProblem.*/
public static int determineSeed(Output output, ParameterDatabase parameters, Parameter seedParameter, long currentTime, int offset, boolean auto)
{
int seed = 1; // have to initialize to make the compiler happy
String tmp_s = parameters.getString(seedParameter,null);
if (tmp_s==null && !auto) // uh oh
{
output.fatal("Seed must exist.",seedParameter,null);
}
else if (V_SEED_TIME.equalsIgnoreCase(tmp_s) || (tmp_s == null && auto))
{
if (tmp_s == null && auto)
output.warnOnce("Using automatic determination number of threads, but not all seeds are defined.\nThe rest will be defined using the wall clock time.");
seed = (int)currentTime; // using low-order bits so it's probably okay
if (seed==0)
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);
}
else
{
try
{
seed = parameters.getInt(seedParameter,null);
}
catch (NumberFormatException e)
{
output.fatal("Invalid, non-integer seed value ("+seed+")",seedParameter,null);
}
}
return seed + offset;
}
/** Constructs and sets up an Output object. */
public static Output buildOutput()
{
Output output;
// 1. create the output
output = new Output(true);
// stdout is always log #0. stderr is always log #1.
// stderr accepts announcements, and both are fully verbose
// by default.
output.addLog(ec.util.Log.D_STDOUT,false);
output.addLog(ec.util.Log.D_STDERR,true);
return output;
}
/** Initializes an evolutionary run given the parameters and a random seed adjustment (added to each random seed).
The adjustment offers a convenient way to change the seeds of the random number generators each time you
do a new evolutionary run. You are of course welcome to replace the random number generators after initialize(...)
but before startFresh(...)
This method works by first setting up an Output (using buildOutput), then calling initialize(ParameterDatabase, seed, output)
*/
public static EvolutionState initialize(ParameterDatabase parameters, int randomSeedOffset)
{
return initialize(parameters, randomSeedOffset, buildOutput());
}
/** Initializes an evolutionary run given the parameters and a random seed adjustment (added to each random seed),
with the Output pre-constructed.
The adjustment offers a convenient way to change the seeds of the random number generators each time you
do a new evolutionary run. You are of course welcome to replace the random number generators after initialize(...)
but before startFresh(...) */
public static EvolutionState initialize(ParameterDatabase parameters, int randomSeedOffset, Output output)
{
EvolutionState state=null;
MersenneTwisterFast[] random;
int[] seeds;
int breedthreads = 1;
int evalthreads = 1;
boolean store;
int x;
// Should we muzzle stdout and stderr?
if (parameters.exists(new Parameter(P_MUZZLE), null))
output.warning("" + new Parameter(P_MUZZLE) + " has been deprecated. We suggest you use " +
new Parameter(P_SILENT) + " or similar newer options.");
if (parameters.getBoolean(new Parameter(P_SILENT), null, false) ||
parameters.getBoolean(new Parameter(P_MUZZLE), null, false))
{
output.getLog(0).silent = true;
output.getLog(1).silent = true;
}
// output was already created for us.
output.systemMessage(Version.message());
// 2. set up thread values
breedthreads = Evolve.determineThreads(output, parameters, new Parameter(P_BREEDTHREADS));
evalthreads = Evolve.determineThreads(output, parameters, new Parameter(P_EVALTHREADS));
boolean auto = (V_THREADS_AUTO.equalsIgnoreCase(parameters.getString(new Parameter(P_BREEDTHREADS),null)) ||
V_THREADS_AUTO.equalsIgnoreCase(parameters.getString(new Parameter(P_EVALTHREADS),null))); // at least one thread is automatic. Seeds may need to be dynamic.
// 3. create the Mersenne Twister random number generators,
// one per thread
random = new MersenneTwisterFast[breedthreads > evalthreads ?
breedthreads : evalthreads];
seeds = new int[random.length];
String seedMessage = "Seed: ";
int time = (int)(System.currentTimeMillis());
for (x=0;x= 0 (or not exist, which defaults to 0)");
int numJobs = parameters.getIntWithDefault(new Parameter("jobs"), null, 1);
if (numJobs < 1)
Output.initialError("The 'jobs' parameter must be >= 1 (or not exist, which defaults to 1)");
// Now we know how many jobs remain. Let's loop for that many jobs. Each time we'll
// load the parameter database scratch (except the first time where we reuse the one we
// just loaded a second ago). The reason we reload from scratch each time is that the
// experimenter is free to scribble all over the parameter database and it'd be nice to
// have everything fresh and clean. It doesn't take long to load the database anyway,
// it's usually small.
for(int job = currentJob ; job < numJobs; job++)
{
// We used to have a try/catch here to catch errors thrown by this job and continue to the next.
// But the most common error is an OutOfMemoryException, and printing its stack trace would
// just create another OutOfMemoryException! Which dies anyway and has a worthless stack
// trace as a result.
// try
{
// load the parameter database (reusing the very first if it exists)
if (parameters == null)
parameters = loadParameterDatabase(args);
// Initialize the EvolutionState, then set its job variables
state = initialize(parameters, job); // pass in job# as the seed increment
state.output.systemMessage("Job: " + job);
state.job = new Object[1]; // make the job argument storage
state.job[0] = Integer.valueOf(job); // stick the current job in our job storage
state.runtimeArguments = args; // stick the runtime arguments in our storage
if (numJobs > 1) // only if iterating (so we can be backwards-compatible),
{
String jobFilePrefix = "job." + job + ".";
state.output.setFilePrefix(jobFilePrefix); // add a prefix for checkpoint/output files
state.checkpointPrefix = jobFilePrefix + state.checkpointPrefix; // also set up checkpoint prefix
}
// Here you can set up the EvolutionState's parameters further before it's setup(...).
// This includes replacing the random number generators, changing values in state.parameters,
// changing instance variables (except for job and runtimeArguments, please), etc.
// now we let it go
state.run(EvolutionState.C_STARTED_FRESH);
cleanup(state); // flush and close various streams, print out parameters if necessary
parameters = null; // so we load a fresh database next time around
}
/*
catch (Throwable e) // such as an out of memory error caused by this job
{
e.printStackTrace();
state = null;
System.gc(); // take a shot!
}
*/
}
System.exit(0);
}
}
Ads help maintain this website.