/*
Copyright 2012 by James McDermott
Licensed under the Academic Free License version 3.0
See the file "LICENSE" for more information
*/
package ec.app.gpsemantics;
import ec.app.gpsemantics.func.*;
import ec.util.*;
import ec.*;
import ec.gp.*;
import ec.gp.koza.*;
import ec.simple.*;
import java.util.ArrayList;
/*
* Semantic.java
*
*/
/**
* Implements Goldberg and O'Reilly's semantic Order and Majority
* problems. See the README.
*
Parameters
base.data
classname, inherits or == ec.gp.gpdata
(the class for the prototypical GPData object)
Parameter bases
base.data
species (the GPData object)
*
* Class representing Semantic Order and Majority problems. This
* problem has a size: typical size is 16, which means the terminals
* are [X0, N0, ... X16, N16]. For Order, fitness is 1 for every time
* when Xi occurs before Ni, in an inorder traversal. For Majority,
* fitness is 1 for every time when Xi occurs more often than Ni.
*
* @author James McDermott
* @version 1.0
*/
public class Semantic extends GPProblem implements SimpleProblemForm
{
final static String P_PROBLEM_NAME = "problem_name";
final static String P_SIZE = "size";
final static String P_ORDER = "Order";
final static String P_MAJORITY = "Majority";
String problemName;
int problemSize;
public void setup(final EvolutionState state,
final Parameter base)
{
// very important, remember this
super.setup(state,base);
Parameter fsSize = new Parameter(GPDefaults.P_GP).push(GPInitializer.P_FUNCTIONSETS).push("" + 0).push(GPFunctionSet.P_SIZE);
int numFuncs = state.parameters.getInt(fsSize,null,1);
problemSize = (numFuncs - 1) / 2;
problemName = state.parameters.getString(base.push(P_PROBLEM_NAME), base.push(P_ORDER));
if (!problemName.equals(P_ORDER) && !problemName.equals(P_MAJORITY))
state.output.error("The problem name is unrecognized",
base.push(P_PROBLEM_NAME));
System.out.println("Problem name " + problemName);
System.out.println("Problem size " + problemSize);
state.output.exitIfErrors();
}
public void evaluate(final EvolutionState state,
final Individual ind,
final int subpopulation,
final int threadnum)
{
if (!ind.evaluated) // don't bother reevaluating
{
// trees[0].child is the root
ArrayList output = getSemanticOutput(((GPIndividual) ind).trees[0]);
double score = 0.0;
for (int i = 0; i < output.size(); i++)
{
SemanticNode n = (SemanticNode) output.get(i);
if (n.value() == 'X')
{
score += 1;
}
}
SimpleFitness f = ((SimpleFitness) ind.fitness);
f.setFitness(state, score, false);
ind.evaluated = true;
}
}
/**
* @param t Tree to be "executed"
* @return expressed output
*/
ArrayList getSemanticOutput(GPTree t)
{
ArrayList p = new ArrayList();
ArrayList nodes = new ArrayList();
// Is there a better way to get all the nodes in a depth-first
// traversal? Note that the paper specifies inorder traversal,
// but since we're only getting the terminals, preorder,
// inorder, and postorder are equivalent.
int nterminals = t.child.numNodes(GPNode.NODESEARCH_TERMINALS);
for (int i = 0; i < nterminals; i++)
{
nodes.add(t.child.nodeInPosition(i, GPNode.NODESEARCH_TERMINALS));
}
if (problemName.equals(P_ORDER))
{
// Order: first occurence counts
for (int i = 0; i < nodes.size(); i++)
{
SemanticNode node = (SemanticNode) nodes.get(i);
if (!nodeSameIndexExists(p, node.index()))
{
p.add(node);
}
}
}
else
{
// Majority: most common counts
for (int n = 0; n < problemSize; n++)
{
int xCount = 0;
int nCount = 0;
int lastXNode = -1;
for (int i = 0; i < nodes.size(); i++)
{
SemanticNode node = (SemanticNode) nodes.get(i);
if (node.value() == 'X' && node.index() == n)
{
xCount += 1;
lastXNode = i;
}
else if (node.value() == 'N' && node.index() == n)
{
nCount += 1;
}
}
if (xCount >= nCount && xCount > 0)
{
p.add((SemanticNode) nodes.get(lastXNode));
}
}
}
return p;
}
/**
* Given a list and an index, check whether a node of that index
* exists in the list.
*
* @param p List of nodes
* @param n index
* @return whether node of index n exists in p.
*/
boolean nodeSameIndexExists(ArrayList p, int n)
{
for (int i = 0; i < p.size(); i++)
{
if (((SemanticNode) p.get(i)).index() == n)
{
return true;
}
}
return false;
}
String phenotypeToString(ArrayList p)
{
String retval = "";
for (int i = 0; i < p.size(); i++) {
retval += p.get(i).toString() + " ";
}
return retval;
}
// In one paper, there is a parameter for scaling, ie the fitness
// contribution of each Xi can be uniform, or linearly or
// exponentially scaled. We don't do that in this version.
public void describe(
final EvolutionState state,
final Individual ind,
final int subpopulation,
final int threadnum,
final int log)
{
state.output.println("\n\nBest Individual: output = " + phenotypeToString(getSemanticOutput(((GPIndividual) ind).trees[0])), log);
}
}
Ads help maintain this website.