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, final RandomGenerator _randomGenerator,
33 final AbstractEAConfiguration _eaConfiguration, final TrimTree _trimTree) {
34 Objects.requireNonNull(_programGenerator);
35 Objects.requireNonNull(_randomGenerator);
36 Objects.requireNonNull(_eaConfiguration);
37 Objects.requireNonNull(_trimTree);
38
39 this.programGenerator = _programGenerator;
40 this.randomGenerator = _randomGenerator;
41 this.eaConfiguration = _eaConfiguration;
42 this.trimTree = _trimTree;
43 }
44
45 protected TreeNode<Operation<?>> duplicateAndMutate(final Program program, final TreeNode<Operation<?>> root,
46 final int maxDepth, final int currentDepth) {
47 Objects.requireNonNull(program);
48 Objects.requireNonNull(root);
49
50 final Operation<?> rootData = root.getData();
51
52 if (currentDepth == maxDepth && root.getSize() > 1) {
53 return programGenerator.generate(program, 1, rootData.returnedType());
54 }
55
56 final List<TreeNode<Operation<?>>> children = root.getChildren();
57
58 final TreeNode<Operation<?>> duplicateRoot = new TreeNode<Operation<?>>(rootData);
59
60 for (int i = 0; i < children.size(); i++) {
61 final TreeNode<Operation<?>> treeNode = children.get(i);
62 final int childSize = treeNode.getSize();
63
64 final TreeNode<Operation<?>> childCopy = duplicateAndMutate(program, treeNode, maxDepth, currentDepth + 1);
65 duplicateRoot.addChild(childCopy);
66 }
67
68 return duplicateRoot;
69 }
70
71 private int maxDepthValue(final Program program, final TrimTree trimTree) {
72 Objects.requireNonNull(program);
73 Objects.requireNonNull(trimTree);
74
75 return trimTree.maxDepth()
76 .orElseGet(() -> program.maxDepth());
77 }
78
79 @Override
80 public Genotype mutate(final long generation, final Genotype originalGenotype) {
81 Validate.isTrue(generation >= 0);
82 Objects.requireNonNull(originalGenotype);
83
84 logger.trace("Mutating genotype {}", originalGenotype);
85
86 final Chromosome[] newChromosomes = new Chromosome[originalGenotype.getSize()];
87 final Chromosome[] chromosomes = originalGenotype.getChromosomes();
88 for (int chromosomeIndex = 0; chromosomeIndex < chromosomes.length; chromosomeIndex++) {
89 final ChromosomeSpec chromosomeSpec = eaConfiguration.getChromosomeSpec(chromosomeIndex);
90 final Chromosome chromosome = chromosomes[chromosomeIndex];
91
92 if (chromosomeSpec instanceof ProgramTreeChromosomeSpec == false) {
93 throw new IllegalArgumentException("This mutator does not support chromosome specs " + chromosomeSpec);
94 }
95
96 if (chromosome instanceof TreeChromosome<?> == false) {
97 throw new IllegalArgumentException(
98 "This mutator does not support chromosome of type " + chromosome.getClass()
99 .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()
110 .getDepth() > maxDepthValue) {
111 final TreeNode<Operation<?>> root = treeChromosome.getRoot();
112 final TreeNode<Operation<?>> newRoot = duplicateAndMutate(program, root, maxDepthValue, 0);
113 final TreeChromosome<Operation<?>> newTreeChromosome = new TreeChromosome<>(newRoot);
114 newChromosomes[chromosomeIndex] = newTreeChromosome;
115 } else {
116 newChromosomes[chromosomeIndex] = chromosome;
117 }
118
119 logger.trace("\tChromosome {} - {}", chromosomeIndex, newChromosomes[chromosomeIndex]);
120 }
121
122 return new Genotype(newChromosomes);
123 }
124 }