/*
Copyright 2006 by Sean Luke
Licensed under the Academic Free License version 3.0
See the file "LICENSE" for more information
*/
package ec.gp.breed;
import ec.*;
import ec.util.*;
import ec.gp.*;
/*
* MutateSwapPipeline.java
*
* Created: Wed Dec 15 21:41:30 1999
* By: Sean Luke
*/
/**
* MutateSwapPipeline works very similarly to the Swap algorithm
* described in Kumar Chellapilla,
* "A Preliminary Investigation into Evolving Modular Programs without Subtree
* Crossover", GP98.
*
* MutateSwapPipeline picks a random tree, then picks
* randomly from all the swappable nodes in the tree, and swaps two of its subtrees.
* If its chosen tree has no swappable nodes, it repeats
* the choose-tree process. If after tries times
* it has failed to find a tree with swappable nodes, it gives up and simply
* copies the individual.
*
*
"Swapping" means to take a node n, and choose two children
* nodes of n, x and y, such that x's return
* type is swap-compatible with y's slot, and y's return
* type is swap-compatible with x's slot. The subtrees rooted at
* x and y are swapped.
*
*
A "Swappable" node means a node which is capable of swapping
* given the existing function set. In general to swap a node foo,
* it must have at least two children whose return types are type-compatible
* with each other's slots in foo.
*
*
This method is very expensive in searching nodes for
* "swappability". However, if the number of types is 1 (the
* GP run is typeless) then the type-constraint-checking
* code is bypassed and the method runs a little faster.
Typical Number of Individuals Produced Per produce(...) call
...as many as the source produces
Number of Sources
1
Parameters
base.tries
int >= 1
(number of times to try finding valid pairs of nodes)
base.tree.0
0 < int < (num trees in individuals), if exists
(tree chosen for mutation; if parameter doesn't exist, tree is picked at random)
Default Base
gp.breed.mutate-swap
* @author Sean Luke
* @version 1.0
*/
public class MutateSwapPipeline extends GPBreedingPipeline
{
public static final String P_MUTATESWAP = "mutate-swap";
public static final String P_NUM_TRIES = "tries";
public static final int NUM_SOURCES = 1;
/** The number of times the pipeline tries to build a valid mutated
tree before it gives up and just passes on the original */
int numTries;
/** Is our tree fixed? If not, this is -1 */
int tree;
public Parameter defaultBase() { return GPBreedDefaults.base().push(P_MUTATESWAP); }
public int numSources() { return NUM_SOURCES; }
public void setup(final EvolutionState state, final Parameter base)
{
super.setup(state,base);
Parameter def = defaultBase();
numTries = state.parameters.getInt(base.push(P_NUM_TRIES),
def.push(P_NUM_TRIES),1);
if (numTries == 0)
state.output.fatal("MutateSwapPipeline has an invalid number of tries (it must be >= 1).",base.push(P_NUM_TRIES),def.push(P_NUM_TRIES));
tree = TREE_UNFIXED;
if (state.parameters.exists(base.push(P_TREE).push(""+0),
def.push(P_TREE).push(""+0)))
{
tree = state.parameters.getInt(base.push(P_TREE).push(""+0),
def.push(P_TREE).push(""+0),0);
if (tree==-1)
state.output.fatal("Tree fixed value, if defined, must be >= 0");
}
}
/** This very expensive method (for types)
might be improved in various ways I guess. */
private boolean swappable(final GPInitializer initializer,
final GPNode node)
{
if (node.children.length < 2)
return false; // fast check
if (initializer.numAtomicTypes + initializer.numSetTypes == 1)
return true; // next fast check
// we're typed, so now we have to check our type compatibility
for(int x=0;x= 2
// pick a random first node
int x = state.random[thread].nextInt(node.children.length);
// pick a random second node
int y = state.random[thread].nextInt(node.children.length-1);
if (y >= x) y++; // adjust for first node
// swap the nodes
GPNode tmp = node.children[x];
node.children[x] = node.children[y];
node.children[y] = tmp;
node.children[x].argposition = (byte)x;
node.children[y].argposition = (byte)y;
// no need to set parent -- it's the same parent of course
}
private void _swapSomething(final GPNode node, final EvolutionState state, final int thread)
{
int numSwappable = 0;
GPInitializer initializer = ((GPInitializer)state.initializer);
for(int x=0;x 0
int swapItem = state.random[thread].nextInt(numSwappable);
numSwappable=0;
// find it
for(int x=0;x= i.trees.length))
// uh oh
state.output.fatal("MutateSwapPipeline attempted to fix tree.0 to a value which was out of bounds of the array of the individual's trees. Check the pipeline's fixed tree values -- they may be negative or greater than the number of trees in an individual");
GPIndividual j;
if (sources[0] instanceof BreedingPipeline)
// it's already a copy, so just smash the tree in
{
j=i;
}
else // need to copy it
{
j = (GPIndividual)(i.lightClone());
// Fill in various tree information that didn't get filled in there
j.trees = new GPTree[i.trees.length];
for(int x=0;x1) t = state.random[thread].nextInt(i.trees.length);
else t = 0;
else t = tree;
// is the tree swappable?
GPInitializer initializer = ((GPInitializer)state.initializer);
int numswap = numSwappableNodes(initializer, j.trees[t].child,0);
if (numswap==0) continue; // uh oh, try again
// swap the node, or if we're unsuccessful, just leave it alone
pickSwappableNode(initializer, j.trees[t].child,state.random[thread].nextInt(numswap));
// node is now in swappableNode, swap it
swapSomething(swappableNode,state,thread);
j.evaluated = false;
break;
}
// add the new individual, replacing its previous source
inds[q] = j;
}
return n;
}
}
Ads help maintain this website.