/*
Copyright 2006 by Sean Luke and George Mason University
Licensed under the Academic Free License version 3.0
See the file "LICENSE" for more information
*/
package ec.vector.breed;
/*
* ListCrossoverPipeline.java
*
* Created: Sat 23 May 2009 11:57:17 AM EDT
* By: Stephen Donnelly
*/
import ec.vector.*;
import ec.*;
import ec.util.*;
/**
ListCrossoverPipeline is a crossover pipeline for vector individuals whose length
may be lengthened or shortened. There are two crossover options available: one-point
and two-point. One-point crossover picks a crossover point for each of the vectors
(the crossover point can be different), and then does one-point crossover using those
points. Two-point crossover picks TWO crossover points for each of the vectors (again,
the points can be different among the vectors), and swaps the middle regions between
the respective crossover points.
ListCrossoverPipeline will try tries times to meet certain constraints: first,
the resulting children must be no smaller than min-child-size. Second, the amount
of material removed from a parent must be no less than mix-crossover-percent and no
more than max-crossover-percent.
If toss is true, then only one child is generated, else at most two are generated.
Typical Number of Individuals Produced Per produce(...) call
2 * minimum typical number of individuals produced by each source, unless toss
is set, in which case it's simply the minimum typical number.
Number of Sources
2
Parameters
base.toss
bool = true or false (default)/td>
(after crossing over with the first new individual, should its second sibling individual be thrown away instead of adding it to
the population?)
base.tries
int >= 1
(number of times to try finding valid crossover points)
base.min-child-size
int >= 0 (default)
(the minimum allowed size of a child)
base.min-crossover-percent
0 (default) <= double <= 1
(the minimum percentage of an individual that may be removed during crossover)
base.max-crossover-percent
0 <= double <= 1 (default)
(the maximum percentage of an individual that may be removed during crossover)
Default Base
vector.list-xover
**/
public class ListCrossoverPipeline extends BreedingPipeline
{
public static final String P_TOSS = "toss";
public static final String P_LIST_CROSSOVER = "list-xover";
public static final String P_MIN_CHILD_SIZE = "min-child-size";
public static final String P_NUM_TRIES = "tries";
public static final String P_MIN_CROSSOVER_PERCENT = "min-crossover-percent";
public static final String P_MAX_CROSSOVER_PERCENT = "max-crossover-percent";
public static final int NUM_SOURCES = 2;
public boolean tossSecondParent;
public int crossoverType;
public int minChildSize;
public int numTries;
public double minCrossoverPercentage;
public double maxCrossoverPercentage;
protected VectorIndividual parents[];
public ListCrossoverPipeline() { parents = new VectorIndividual[2]; }
public Parameter defaultBase() { return VectorDefaults.base().push(P_LIST_CROSSOVER); }
public int numSources() { return NUM_SOURCES; }
public Object clone()
{
ListCrossoverPipeline c = (ListCrossoverPipeline)(super.clone());
c.parents = (VectorIndividual[]) parents.clone();
return c;
}
public void setup(final EvolutionState state, final Parameter base)
{
super.setup(state,base);
Parameter def = defaultBase();
tossSecondParent = state.parameters.getBoolean(base.push(P_TOSS),
def.push(P_TOSS),false);
minChildSize = state.parameters.getIntWithDefault(base.push(P_MIN_CHILD_SIZE),
def.push(P_MIN_CHILD_SIZE), 0);
numTries = state.parameters.getIntWithDefault(base.push(P_NUM_TRIES),
def.push(P_NUM_TRIES), 1);
minCrossoverPercentage = state.parameters.getDoubleWithDefault(base.push(P_MIN_CROSSOVER_PERCENT),
def.push(P_MIN_CROSSOVER_PERCENT), 0.0);
maxCrossoverPercentage = state.parameters.getDoubleWithDefault(base.push(P_MAX_CROSSOVER_PERCENT),
def.push(P_MAX_CROSSOVER_PERCENT), 1.0);
String crossoverTypeString = state.parameters.getStringWithDefault(base.push(VectorSpecies.P_CROSSOVERTYPE),
def.push(VectorSpecies.P_CROSSOVERTYPE),
VectorSpecies.V_TWO_POINT);
// determine the crossover method to use (only 1-point & 2-point currently supported)
if(crossoverTypeString.equalsIgnoreCase(VectorSpecies.V_ONE_POINT))
{
crossoverType = VectorSpecies.C_ONE_POINT;
}
else if(crossoverTypeString.equalsIgnoreCase(VectorSpecies.V_TWO_POINT))
{
crossoverType = VectorSpecies.C_TWO_POINT;
}
else
{
state.output.error("ListCrossoverPipeline:\n:" +
" Parameter crossover-type is currently set to: " + crossoverTypeString + "\n" +
" Currently supported crossover types are \"one\" and \"two\" point.\n");
}
// sanity check for crossover parameters
if(minChildSize < 0)
{
state.output.error("ListCrossoverPipeline:\n" +
" Parameter min-child-size is currently equal to: " + Integer.toString(minChildSize) + "\n" +
" min-child-size must be a positive integer\n");
}
if(numTries < 1)
{
state.output.error("ListCrossoverPipeline:\n" +
" Parameter tries is currently equal to: " + Integer.toString(numTries) + "\n" +
" tries must be greater than or equal to 1\n");
}
if(minCrossoverPercentage < 0.0 || minCrossoverPercentage > 1.0)
{
state.output.error("ListCrossoverPipeline:\n" +
" Parameter min-crossover-percent is currently equal to: " + Double.toString(minCrossoverPercentage) + "\n" +
" min-crossover-percent must be either a real-value double float between [0.0, 1.0] or left unspecified\n");
}
if(maxCrossoverPercentage < 0.0 || maxCrossoverPercentage > 1.0)
{
state.output.error("ListCrossoverPipeline:\n" +
" Parameter max-crossover-percent is currently equal to: " + Double.toString(maxCrossoverPercentage) + "\n" +
" max-crossover-percent must be either a real-value double float between [0.0, 1.0] or left unspecified\n");
}
if(minCrossoverPercentage > maxCrossoverPercentage)
{
state.output.error("ListCrossoverPipeline:\n" +
" Parameter min-crossover-percent must be less than max-crossover-percent\n");
}
if(minCrossoverPercentage == maxCrossoverPercentage)
{
state.output.warning("ListCrossoverPipeline:\n" +
" Parameter min-crossover-percent and max-crossover-percent are currently equal to: " +
Double.toString(minCrossoverPercentage) + "\n" +
" This effectively prevents any crossover from occurring\n");
}
}
public int typicalIndsProduced()
{
return (tossSecondParent? minChildProduction(): minChildProduction()*2);
}
public int produce(final int min,
final int max,
final int start,
final int subpopulation,
final Individual[] inds,
final EvolutionState state,
final int thread)
{
// how many individuals should we make?
int n = typicalIndsProduced();
if (n < min) n = min;
if (n > max) n = max;
// should we bother?
if (!state.random[thread].nextBoolean(likelihood))
return reproduce(n, start, subpopulation, inds, state, thread, true); // DO produce children from source -- we've not done so already
for(int q=start;q split[i][1]) // swap so 0 is before 1
{
int temp = split[i][0];
split[i][0] = split[i][1];
split[i][1] = temp;
}
int len = split[i][0] - split[i][1];
if (len >= min_chunks[i] && len <= max_chunks[i]) // okay
{
split[i][0] *= chunk_size;
split[i][1] *= chunk_size;
break;
}
attempts++;
if (attempts > numTries) break; // uh oh
}
}
}
else state.output.fatal("Unknown crossover type specified: " + crossoverType); // shouldn't ever happen
if (attempts >= numTries) break; // failed in two-point selection
// use the split indices generated above to split the parents into pieces
parents[0].split(split[0], pieces[0]);
parents[1].split(split[1], pieces[1]);
// create copies of the parents, swap the middle segment, and then rejoin the pieces
// - this is done to test whether or not the resulting children are of a valid size,
// - because we are using Object references to an undetermined array type, there is no way
// to cast it to the appropriate array type (i.e. short[] or double[]) to figure out the
// length of the pieces
// - instead, we use the join method on copies, and let each vector type figure out its own
// length with the genomeLength() method
VectorIndividual[] children = new VectorIndividual[2];
children[0] = (VectorIndividual)(parents[0].clone());
children[1] = (VectorIndividual)(parents[1].clone());
Object swap = pieces[0][1];
pieces[0][1] = pieces[1][1];
pieces[1][1] = swap;
children[0].join(pieces[0]);
children[1].join(pieces[1]);
if(children[0].genomeLength() > minChildSize && children[1].genomeLength() > minChildSize && isValidated(split, validationData))
{
valid_children = true;
}
attempts++;
}
// if the children produced were valid, updates the parents
if(valid_children == true)
{
parents[0].join(pieces[0]);
parents[1].join(pieces[1]);
parents[0].evaluated=false;
parents[1].evaluated=false;
}
// insert parents back into the population
inds[q] = parents[0];
q++;
if(q < n + start && tossSecondParent == false)
{
inds[q] = parents[1];
q++;
}
}
return n;
}
/** A hook called by ListCrossoverPipeline to allow subclasses to prepare for additional validation testing.
Primarily used by GECrossoverPipeline. */
public Object computeValidationData(EvolutionState state, VectorIndividual[] parents, int thread)
{
return null;
}
/** A hook called by ListCrossoverPipeline to allow subclasses to further validate children crossover points.
Primarily used by GECrossoverPipeline. */
public boolean isValidated(int[][] split, Object validationData)
{
return true;
}
}
Ads help maintain this website.