View Javadoc
1   package net.bmahe.genetics4j.gp.mutation;
2   
3   import java.util.List;
4   import java.util.random.RandomGenerator;
5   
6   import org.apache.commons.lang3.Validate;
7   
8   import net.bmahe.genetics4j.core.Genotype;
9   import net.bmahe.genetics4j.core.chromosomes.Chromosome;
10  import net.bmahe.genetics4j.core.chromosomes.TreeChromosome;
11  import net.bmahe.genetics4j.core.chromosomes.TreeNode;
12  import net.bmahe.genetics4j.core.mutation.Mutator;
13  import net.bmahe.genetics4j.core.spec.AbstractEAConfiguration;
14  import net.bmahe.genetics4j.core.spec.chromosome.ChromosomeSpec;
15  import net.bmahe.genetics4j.gp.Operation;
16  import net.bmahe.genetics4j.gp.OperationFactory;
17  import net.bmahe.genetics4j.gp.program.Program;
18  import net.bmahe.genetics4j.gp.program.ProgramHelper;
19  import net.bmahe.genetics4j.gp.spec.chromosome.ProgramTreeChromosomeSpec;
20  
21  public class ProgramRandomPruneMutator implements Mutator {
22  
23  	private final ProgramHelper programHelper;
24  	private final RandomGenerator randomGenerator;
25  	private final AbstractEAConfiguration eaConfiguration;
26  	private final double populationMutationProbability;
27  
28  	public ProgramRandomPruneMutator(final ProgramHelper _programHelper, final RandomGenerator _randomGenerator,
29  			final AbstractEAConfiguration _eaConfiguration, final double populationMutationProbability) {
30  		Validate.notNull(_programHelper);
31  		Validate.notNull(_randomGenerator);
32  		Validate.notNull(_eaConfiguration);
33  		Validate.inclusiveBetween(0.0, 1.0, populationMutationProbability);
34  
35  		this.programHelper = _programHelper;
36  		this.randomGenerator = _randomGenerator;
37  		this.eaConfiguration = _eaConfiguration;
38  		this.populationMutationProbability = populationMutationProbability;
39  	}
40  
41  	protected TreeNode<Operation<?>> duplicateAndCut(final Program program, final TreeNode<Operation<?>> root,
42  			final int cutPoint, final int nodeIndex) {
43  		Validate.notNull(root);
44  		Validate.isTrue(cutPoint >= 0);
45  
46  		final Operation<?> rootData = root.getData();
47  
48  		if (nodeIndex == cutPoint) {
49  			final OperationFactory randomTerminal = programHelper.pickRandomTerminal(program, rootData.returnedType());
50  			final Operation<?> operation = randomTerminal.build(program.inputSpec());
51  			return new TreeNode<Operation<?>>(operation);
52  		} else {
53  			final List<TreeNode<Operation<?>>> children = root.getChildren();
54  
55  			final TreeNode<Operation<?>> duplicateRoot = new TreeNode<Operation<?>>(rootData);
56  
57  			int currentIndex = nodeIndex + 1;
58  			for (int i = 0; i < children.size(); i++) {
59  				final TreeNode<Operation<?>> treeNode = children.get(i);
60  				final int childSize = treeNode.getSize();
61  
62  				final TreeNode<Operation<?>> childCopy = duplicateAndCut(program, treeNode, cutPoint, currentIndex);
63  				duplicateRoot.addChild(childCopy);
64  				currentIndex += childSize;
65  			}
66  
67  			return duplicateRoot;
68  		}
69  	}
70  
71  	@Override
72  	public Genotype mutate(final Genotype original) {
73  		Validate.notNull(original);
74  
75  		if (randomGenerator.nextDouble() < populationMutationProbability == false) {
76  			return original;
77  		}
78  
79  		final Chromosome[] newChromosomes = new Chromosome[original.getSize()];
80  		final Chromosome[] chromosomes = original.getChromosomes();
81  		for (int chromosomeIndex = 0; chromosomeIndex < chromosomes.length; chromosomeIndex++) {
82  			final ChromosomeSpec chromosomeSpec = eaConfiguration.getChromosomeSpec(chromosomeIndex);
83  			final Chromosome chromosome = chromosomes[chromosomeIndex];
84  
85  			if (chromosomeSpec instanceof ProgramTreeChromosomeSpec == false) {
86  				throw new IllegalArgumentException("This mutator does not support chromosome specs " + chromosomeSpec);
87  			}
88  
89  			if (chromosome instanceof TreeChromosome<?> == false) {
90  				throw new IllegalArgumentException(
91  						"This mutator does not support chromosome of type " + chromosome.getClass().getSimpleName());
92  			}
93  
94  			final ProgramTreeChromosomeSpec programTreeChromosomeSpec = (ProgramTreeChromosomeSpec) chromosomeSpec;
95  
96  			final TreeChromosome<Operation<?>> treeChromosome = (TreeChromosome<Operation<?>>) chromosome;
97  			final int chromosomeSize = treeChromosome.getSize();
98  
99  			if (chromosomeSize > 2) {
100 				final int cutPoint = randomGenerator.nextInt(chromosomeSize - 1) + 1;
101 
102 				final TreeNode<Operation<?>> root = treeChromosome.getRoot();
103 				final TreeNode<Operation<?>> newRoot = duplicateAndCut(programTreeChromosomeSpec.program(),
104 						root,
105 						cutPoint,
106 						0);
107 				final TreeChromosome<Operation<?>> newTreeChromosome = new TreeChromosome<>(newRoot);
108 				newChromosomes[chromosomeIndex] = newTreeChromosome;
109 			} else {
110 				newChromosomes[chromosomeIndex] = chromosome;
111 			}
112 
113 		}
114 
115 		return new Genotype(newChromosomes);
116 	}
117 }