1 package net.bmahe.genetics4j.gp.mutation;
2
3 import java.util.List;
4 import java.util.Objects;
5 import java.util.random.RandomGenerator;
6
7 import org.apache.commons.lang3.Validate;
8 import org.apache.logging.log4j.LogManager;
9 import org.apache.logging.log4j.Logger;
10
11 import net.bmahe.genetics4j.core.Genotype;
12 import net.bmahe.genetics4j.core.chromosomes.Chromosome;
13 import net.bmahe.genetics4j.core.chromosomes.TreeChromosome;
14 import net.bmahe.genetics4j.core.chromosomes.TreeNode;
15 import net.bmahe.genetics4j.core.mutation.Mutator;
16 import net.bmahe.genetics4j.core.spec.AbstractEAConfiguration;
17 import net.bmahe.genetics4j.core.spec.chromosome.ChromosomeSpec;
18 import net.bmahe.genetics4j.gp.Operation;
19 import net.bmahe.genetics4j.gp.program.Program;
20 import net.bmahe.genetics4j.gp.program.ProgramGenerator;
21 import net.bmahe.genetics4j.gp.spec.chromosome.ProgramTreeChromosomeSpec;
22 import net.bmahe.genetics4j.gp.spec.mutation.TrimTree;
23
24 public class TrimTreeMutator implements Mutator {
25 final static public Logger logger = LogManager.getLogger(TrimTreeMutator.class);
26
27 private final ProgramGenerator programGenerator;
28 private final RandomGenerator randomGenerator;
29 private final AbstractEAConfiguration eaConfiguration;
30 private final TrimTree trimTree;
31
32 public TrimTreeMutator(final ProgramGenerator _programGenerator,
33 final RandomGenerator _randomGenerator,
34 final AbstractEAConfiguration _eaConfiguration,
35 final TrimTree _trimTree) {
36 Objects.requireNonNull(_programGenerator);
37 Objects.requireNonNull(_randomGenerator);
38 Objects.requireNonNull(_eaConfiguration);
39 Objects.requireNonNull(_trimTree);
40
41 this.programGenerator = _programGenerator;
42 this.randomGenerator = _randomGenerator;
43 this.eaConfiguration = _eaConfiguration;
44 this.trimTree = _trimTree;
45 }
46
47 protected TreeNode<Operation<?>> duplicateAndMutate(final Program program, final TreeNode<Operation<?>> root,
48 final int maxDepth, final int currentDepth) {
49 Objects.requireNonNull(program);
50 Objects.requireNonNull(root);
51
52 final Operation<?> rootData = root.getData();
53
54 if (currentDepth == maxDepth && root.getSize() > 1) {
55 return programGenerator.generate(program, 1, rootData.returnedType());
56 }
57
58 final List<TreeNode<Operation<?>>> children = root.getChildren();
59
60 final TreeNode<Operation<?>> duplicateRoot = new TreeNode<Operation<?>>(rootData);
61
62 for (int i = 0; i < children.size(); i++) {
63 final TreeNode<Operation<?>> treeNode = children.get(i);
64 final int childSize = treeNode.getSize();
65
66 final TreeNode<Operation<?>> childCopy = duplicateAndMutate(program, treeNode, maxDepth, currentDepth + 1);
67 duplicateRoot.addChild(childCopy);
68 }
69
70 return duplicateRoot;
71 }
72
73 private int maxDepthValue(final Program program, final TrimTree trimTree) {
74 Objects.requireNonNull(program);
75 Objects.requireNonNull(trimTree);
76
77 return trimTree.maxDepth().orElseGet(() -> program.maxDepth());
78 }
79
80 @Override
81 public Genotype mutate(final long generation, final Genotype originalGenotype) {
82 Validate.isTrue(generation >= 0);
83 Objects.requireNonNull(originalGenotype);
84
85 logger.trace("Mutating genotype {}", originalGenotype);
86
87 final Chromosome[] newChromosomes = new Chromosome[originalGenotype.getSize()];
88 final Chromosome[] chromosomes = originalGenotype.getChromosomes();
89 for (int chromosomeIndex = 0; chromosomeIndex < chromosomes.length; chromosomeIndex++) {
90 final ChromosomeSpec chromosomeSpec = eaConfiguration.getChromosomeSpec(chromosomeIndex);
91 final Chromosome chromosome = chromosomes[chromosomeIndex];
92
93 if (chromosomeSpec instanceof ProgramTreeChromosomeSpec == false) {
94 throw new IllegalArgumentException("This mutator does not support chromosome specs " + chromosomeSpec);
95 }
96
97 if (chromosome instanceof TreeChromosome<?> == false) {
98 throw new IllegalArgumentException(
99 "This mutator does not support chromosome of type " + chromosome.getClass().getSimpleName());
100 }
101
102 final ProgramTreeChromosomeSpec programTreeChromosomeSpec = (ProgramTreeChromosomeSpec) chromosomeSpec;
103 final Program program = programTreeChromosomeSpec.program();
104
105 final TreeChromosome<Operation<?>> treeChromosome = (TreeChromosome<Operation<?>>) chromosome;
106
107 final int maxDepthValue = maxDepthValue(program, trimTree);
108
109 if (treeChromosome.getRoot().getDepth() > maxDepthValue) {
110 final TreeNode<Operation<?>> root = treeChromosome.getRoot();
111 final TreeNode<Operation<?>> newRoot = duplicateAndMutate(program, root, maxDepthValue, 0);
112 final TreeChromosome<Operation<?>> newTreeChromosome = new TreeChromosome<>(newRoot);
113 newChromosomes[chromosomeIndex] = newTreeChromosome;
114 } else {
115 newChromosomes[chromosomeIndex] = chromosome;
116 }
117
118 logger.trace("\tChromosome {} - {}", chromosomeIndex, newChromosomes[chromosomeIndex]);
119 }
120
121 return new Genotype(newChromosomes);
122 }
123 }