/*
Copyright 2013 by Sean Luke
Licensed under the Academic Free License version 3.0
See the file "LICENSE" for more information
*/
package ec.app.majority;
import ec.util.*;
import ec.*;
import ec.gp.*;
import ec.gp.koza.*;
import ec.simple.*;
/**
MajorityGP.java
Implements a GP-style vector rule for the one-dimensional Majority-Ones cellular automaton problem.
This code is in the spirit of Das, Crutchfield, Mitchel, and Hanson, "Evolving Globally Synchronized Cellular AUtomata",
http://web.cecs.pdx.edu/~mm/EGSCA.pdf
The primary difference is in the trials mechanism, in which we're using 25/25/50 rather than 50/50/0.
*/
public class MajorityGP extends GPProblem implements SimpleProblemForm
{
CA ca = null;
// How many trials in our training set
public static final int NUM_TRIALS = 128;
// CA description
public static final int CA_WIDTH = 149;
public static final int NEIGHBORHOOD = 7;
// How long can I run the CA if it's not converging?
public static final int STEPS = 200;
int[][] trials = new int[NUM_TRIALS][CA_WIDTH];
int[] majorities = new int[NUM_TRIALS];
// kinds of trial types
static final int MAJORITY_ZERO = 0;
static final int MAJORITY_ONE = 1;
static final int RANDOM = -1;
boolean makeTrial(EvolutionState state, int thread, int[] trial, int trialType)
{
if (trialType == RANDOM)
{
int count = 0;
for(int i = 0; i < CA_WIDTH; i++)
{
trial[i] = state.random[thread].nextInt(2);
count += trial[i];
}
return (count > CA_WIDTH / 2.0); // > 74
}
else if (trialType == MAJORITY_ONE)
{
while(!makeTrial(state, thread, trial, RANDOM));
return true;
}
else if (trialType == MAJORITY_ZERO) // uniform selection
{
while(makeTrial(state, thread, trial, RANDOM));
return false;
}
else
{
state.output.fatal("This should never happen");
return false;
}
}
public void generateTrials(EvolutionState state, int thread)
{
// the trials strategy here is: 25% ones, 25% zeros, and 50% random choice
//MersenneTwisterFast mtf = state.random[thread];
for(int i = 0; i < NUM_TRIALS / 4; i++)
{
majorities[i] = makeTrial(state, thread, trials[i], MAJORITY_ZERO) ? 1 : 0;
}
for(int i = NUM_TRIALS / 4; i < NUM_TRIALS / 2; i++)
{
majorities[i] = makeTrial(state, thread, trials[i], MAJORITY_ONE) ? 1 : 0;
}
for(int i = NUM_TRIALS / 2; i < NUM_TRIALS; i++)
{
majorities[i] = makeTrial(state, thread, trials[i], RANDOM) ? 1 : 0;
}
}
public void setup(final EvolutionState state, final Parameter base)
{
// very important, remember this
super.setup(state,base);
generateTrials(state, 0);
}
// the purpose of this code is to guarantee that I regenerate trials each generation
// and make sure that nobody is using them at the moment.
int lockCount = 0;
private Object[] lock = new Object[0];
public void prepareToEvaluate(final EvolutionState state, final int threadnum)
{
if (threadnum != 0)
synchronized(lock) { lockCount++ ; }
}
public void finishEvaluating(final EvolutionState state, final int threadnum)
{
if (threadnum != 0)
{
synchronized(lock) { lockCount--; lock.notifyAll(); }
}
else // I'm thread 0
{
synchronized(lock)
{
while(lockCount > 0)
try { lock.wait(); }
catch (InterruptedException e) { }
}
// at this point I'm all alone!
generateTrials(state, threadnum);
}
}
public static boolean all(int[] vals, int val)
{
for(int i = 0; i < vals.length; i++)
if (vals[i] != val) return false;
return true;
}
public void evaluate(final EvolutionState state,
final Individual ind,
final int subpopulation,
final int threadnum)
{
if (ca == null)
ca = new CA(CA_WIDTH, NEIGHBORHOOD);
// we always reevaluate
//if (!ind.evaluated) // don't bother reevaluating
{
MajorityData input = (MajorityData)(this.input);
int sum = 0;
// extract the rule
((GPIndividual)ind).trees[0].child.eval(
state,threadnum,input,stack,((GPIndividual)ind),this);
int[] rule = ca.getRule();
for(int i = 0; i < 64; i++)
rule[i] = (int)(((input.data0) >> i) & 0x1);
for(int i = 64; i < 128; i++)
rule[i] = (int)(((input.data1) >> (i - 64)) & 0x1);
ca.setRule(rule); // for good measure though it doesn't matter
for(int i = 0; i < NUM_TRIALS; i++)
{
// set up and run the CA
ca.setVals(trials[i]);
ca.step(STEPS, true);
// extract the fitness
if (all(ca.getVals(), majorities[i]))
sum ++;
}
SimpleFitness f = ((SimpleFitness)ind.fitness);
f.setFitness(state, sum / (double)NUM_TRIALS, (sum == NUM_TRIALS));
ind.evaluated = true;
}
}
public static final int NUM_TESTS = 10000;
double density = 0.0;
public void describe(
final EvolutionState state,
final Individual ind,
final int subpopulation,
final int threadnum,
final int log)
{
if (ca == null)
ca = new CA(CA_WIDTH, NEIGHBORHOOD);
int[] trial = new int[CA_WIDTH];
MajorityData input = (MajorityData)(this.input);
// extract the rule
((GPIndividual)ind).trees[0].child.eval(
state,threadnum,input,stack,((GPIndividual)ind),this);
int[] rule = ca.getRule();
for(int i = 0; i < 64; i++)
rule[i] = (int)(((input.data0) >> i) & 0x1);
for(int i = 64; i < 128; i++)
rule[i] = (int)(((input.data1) >> (i - 64)) & 0x1);
ca.setRule(rule); // for good measure though it doesn't matter
// print rule
String s = "Rule: ";
for(int i = 0; i < rule.length; i++)
s += rule[i];
state.output.println(s, log);
double sum = 0;
for(int i = 0; i < NUM_TESTS; i++)
{
// set up and run the CA
int result = makeTrial(state, threadnum, trial, RANDOM) ? 1 : 0;
ca.setVals(trial);
ca.step(STEPS, true);
// extract the fitness
if (all(ca.getVals(), result)) sum++;
}
density = (sum / NUM_TESTS);
state.output.println("Generalization Accuracy: " + density, 1); // stderr
state.output.println("Generalization Accuracy: " + density, log);
}
}
Ads help maintain this website.