/*
* This file is part of JGAP.
*
* JGAP offers a dual license model containing the LGPL as well as the MPL.
*
* For licensing information please see the file license.txt included with JGAP
* or have a look at the top of class org.jgap.Chromosome which representatively
* includes the JGAP license policy applicable for any file delivered with JGAP.
*/
package org.jgap.gp.function;
import org.apache.commons.lang.builder.*;
import org.jgap.*;
import org.jgap.gp.*;
import org.jgap.gp.impl.*;
import org.jgap.util.*;
/**
* A connector for independent subprograms (subtrees). Each subtree except the
* last one must have a memory- or stack-modifying command (such as push or
* store), otherwise there is no connection between the subtrees (which would
* be useless bloating).
*
* @author Klaus Meffert
* @since 3.0
*/
public class SubProgram
extends CommandGene implements ICloneable, IMutateable {
/** String containing the CVS revision. Read out via reflection!*/
private final static String CVS_REVISION = "$Revision: 1.18 $";
/**
* Number of subprograms. Redundant, because equal to m_types.length.
*/
private int m_subtrees;
/**
* Minimum arity allowed during mutation of arity.
*/
private int m_minArity;
/**
* Maximum arity allowed during mutation of arity.
*/
private int m_maxArity;
/**
* Return types of the subprograms to excecute.
*/
private Class[] m_types;
private boolean m_mutateable;
private int m_mode;
public SubProgram(final GPConfiguration a_conf, Class[] a_types)
throws InvalidConfigurationException {
this(a_conf, a_types, 0, null);
}
/**
* Collage constructor: Create a sub program that has a_arity elements
* of the same type a_types.
*
* @param a_conf the configuration to use
* @param a_arity number of children in the collage
* @param a_types uniform type of all children
* @throws org.jgap.InvalidConfigurationException
*
* @author Klaus Meffert
* @since 3.4
*/
public SubProgram(final GPConfiguration a_conf, int a_arity, Class a_types)
throws InvalidConfigurationException {
this(a_conf, a_arity, a_types, false);
}
/**
* Collage constructor: Create a sub program that has a_arity elements
* of the same type a_types.
*
* @param a_conf the configuration to use
* @param a_arity number of children in the collage
* @param a_types uniform type of all children
* @param a_mutateable true: allow mutation of the sub program, i.e., the
* number of children (=arity) may be varied automatically during evolution
* @throws org.jgap.InvalidConfigurationException
*
* @author Klaus Meffert
* @since 3.4
*/
public SubProgram(final GPConfiguration a_conf, int a_arity, Class a_types,
boolean a_mutateable)
throws InvalidConfigurationException {
this(a_conf, a_arity, a_types, a_arity, a_arity + 5, a_mutateable);
}
public SubProgram(final GPConfiguration a_conf, int a_arity, Class a_types,
int a_minArity, int a_maxArity, boolean a_mutateable)
throws InvalidConfigurationException {
super(a_conf, a_arity, a_types, 0, null);
if (a_arity < 1) {
throw new IllegalArgumentException("Arity must be >= 1");
}
if (a_minArity > a_arity) {
throw new IllegalArgumentException("Arity must not be smaller than"
+ " min. arity");
}
if (a_maxArity < a_arity) {
throw new IllegalArgumentException("Arity must not be bigger than"
+ " max. arity");
}
m_mode = 2;
m_types = new Class[a_arity];
for (int i = 0; i < a_arity; i++) {
m_types[i] = a_types;
}
m_subtrees = a_arity;
m_mutateable = a_mutateable;
m_minArity = a_minArity;
m_maxArity = a_maxArity;
}
public SubProgram(final GPConfiguration a_conf, Class[] a_types,
boolean a_mutateable)
throws InvalidConfigurationException {
this(a_conf, a_types, 0, null, a_mutateable);
}
public SubProgram(final GPConfiguration a_conf, Class[] a_types,
int a_subReturnType, int[] a_subChildTypes)
throws InvalidConfigurationException {
this(a_conf, a_types, a_subReturnType, a_subChildTypes, false);
}
public SubProgram(final GPConfiguration a_conf, Class[] a_types,
int a_subReturnType, int[] a_subChildTypes, boolean
a_mutateable)
throws InvalidConfigurationException {
super(a_conf, a_types.length, a_types[a_types.length - 1], a_subReturnType,
a_subChildTypes);
if (a_types.length < 1) {
throw new IllegalArgumentException("Number of subtrees must be >= 1");
}
m_mode = 1;
m_minArity = a_types.length;
m_maxArity = m_minArity + 5;
m_types = a_types;
m_subtrees = a_types.length;
m_mutateable = a_mutateable;
}
public String toString() {
String ret = "sub[";
for (int i = 1; i < m_subtrees; i++) {
ret += "&" + i + " --> ";
}
ret += "&" + m_subtrees + "]";
return ret;
}
/**
* @return textual name of this command
*
* @author Klaus Meffert
* @since 3.2
*/
public String getName() {
return "Sub program";
}
public int execute_int(ProgramChromosome c, int n, Object[] args) {
check(c);
int value = -1;
for (int i = 0; i < m_subtrees; i++) {
if (i < m_subtrees - 1) {
c.execute_void(n, i, args);
}
else {
value = c.execute_int(n, i, args); /**@todo evaluate m_types*/
}
// if (i < m_subtrees - 1) {
// ( (GPConfiguration) getConfiguration()).storeThruput(i,
// new Integer(value));
// }
}
return value;
}
public void execute_void(ProgramChromosome c, int n, Object[] args) {
check(c);
for (int i = 0; i < m_subtrees; i++) {
c.execute_void(n, i, args); /**@todo evaluate m_types*/
}
}
public long execute_long(ProgramChromosome c, int n, Object[] args) {
check(c);
long value = -1;
for (int i = 0; i < m_subtrees; i++) {
value = c.execute_long(n, i, args);
}
return value;
}
public float execute_float(ProgramChromosome c, int n, Object[] args) {
check(c);
float value = -1;
for (int i = 0; i < m_subtrees; i++) {
value = c.execute_float(n, i, args);
}
return value;
}
public double execute_double(ProgramChromosome c, int n, Object[] args) {
check(c);
double value = -1;
for (int i = 0; i < m_subtrees; i++) {
value = c.execute_double(n, i, args);
}
return value;
}
public Object execute_object(ProgramChromosome c, int n, Object[] args) {
check(c);
Object value = null;
for (int i = 0; i < m_subtrees; i++) {
value = c.execute_object(n, i, args);
}
return value;
}
public boolean isValid(ProgramChromosome a_program) {
return true;
}
public Class getChildType(IGPProgram a_ind, int a_chromNum) {
try {
return m_types[a_chromNum];
} catch (ArrayIndexOutOfBoundsException aex) {
return null;
}
}
/**
* The compareTo-method.
*
* @param a_other the other object to compare
* @return -1, 0, 1
*
* @author Klaus Meffert
* @since 3.0
*/
public int compareTo(Object a_other) {
int result = super.compareTo(a_other);
if (result != 0) {
return result;
}
SubProgram other = (SubProgram) a_other;
return new CompareToBuilder()
.append(m_types, other.m_types)
.toComparison();
}
/**
* The equals-method.
*
* @param a_other the other object to compare
* @return true if the objects are seen as equal
*
* @author Klaus Meffert
* @since 3.0
*/
public boolean equals(Object a_other) {
try {
SubProgram other = (SubProgram) a_other;
return super.equals(a_other) && new EqualsBuilder()
.append(m_types, other.m_types)
.isEquals();
} catch (ClassCastException cex) {
return false;
}
}
/**
* @return deep clone of this instance
*
* @author Klaus Meffert
* @since 3.2
*/
public Object clone() {
try {
// int[] subChildTypes = getSubChildTypes();
// if (subChildTypes != null) {
// subChildTypes = (int[]) subChildTypes.clone();
// }
// SubProgram result = new SubProgram(getGPConfiguration(), m_types,
// getSubReturnType(), subChildTypes, m_mutateable);
// result.m_subtrees = m_subtrees;
// result.m_types = (Class[]) m_types.clone();
// return result;
SubProgram result;
if (m_mode == 1) {
// First way of construction.
// --------------------------
Class[] types = new Class[m_subtrees];
for (int i = 0; i < m_subtrees; i++) {
types[i] = m_types[m_types.length - 1];
}
int[] subChildTypes = getSubChildTypes();
if (subChildTypes != null) {
subChildTypes = (int[]) subChildTypes.clone();
}
result = new SubProgram(getGPConfiguration(), types,
getSubReturnType(), subChildTypes, m_mutateable);
}
else {
// Second way of construction.
// ---------------------------
result = new SubProgram(getGPConfiguration(), m_subtrees, m_types[0],
m_minArity, m_maxArity, m_mutateable);
}
return result;
} catch (Throwable t) {
throw new CloneException(t);
}
}
public CommandGene applyMutation(int index, double a_percentage)
throws InvalidConfigurationException {
if (!m_mutateable) {
return this;
}
org.jgap.RandomGenerator randomGen = getGPConfiguration().
getRandomGenerator();
double random = randomGen.nextDouble();
if (random < a_percentage) {
return applyMutation();
}
return this;
}
/**@todo use dynamizeArity instead!*/
/**
* @return mutated command gene
* @throws InvalidConfigurationException
*/
public CommandGene applyMutation()
throws InvalidConfigurationException {
int size = getGPConfiguration().getRandomGenerator().nextInt(m_maxArity + 1 -
m_minArity) + m_minArity;
if (m_types.length == size) {
return this;
}
SubProgram result;
if (m_mode == 1) {
// First way of construction.
// --------------------------
Class[] types = new Class[size];
for (int i = 0; i < size; i++) {
types[i] = m_types[m_types.length - 1];
}
int[] subChildTypes = getSubChildTypes();
if (subChildTypes != null) {
subChildTypes = (int[]) subChildTypes.clone();
}
result = new SubProgram(getGPConfiguration(), types,
getSubReturnType(), subChildTypes, m_mutateable);
}
else {
// Second way of construction.
// ---------------------------
result = new SubProgram(getGPConfiguration(), size, m_types[0],
m_minArity, m_maxArity, m_mutateable);
}
return result;
}
/**
* Adaptation of the arity so that it represents a value within the interval
* [m_arityMin, m_arityMax].
*
* @author Klaus Meffert
* @since 3.4
*/
// public void dynamizeArity() {
// int size = getGPConfiguration().getRandomGenerator().nextInt(m_maxArity + 1 -
// m_minArity) + m_minArity;
// setArity(size);
// Class atype = m_types[0];
// m_types = new Class[size];
// for (int i = 0; i < size; i++) {
// m_types[i] = atype;
// }
// m_subtrees = size;
// }
}