1 package net.bmahe.genetics4j.gp.mutation;
2
3 import java.util.ArrayList;
4 import java.util.List;
5 import java.util.Objects;
6 import java.util.Optional;
7
8 import org.apache.commons.lang3.Validate;
9 import org.apache.logging.log4j.LogManager;
10 import org.apache.logging.log4j.Logger;
11
12 import net.bmahe.genetics4j.core.Genotype;
13 import net.bmahe.genetics4j.core.chromosomes.Chromosome;
14 import net.bmahe.genetics4j.core.chromosomes.TreeChromosome;
15 import net.bmahe.genetics4j.core.chromosomes.TreeNode;
16 import net.bmahe.genetics4j.core.mutation.Mutator;
17 import net.bmahe.genetics4j.core.spec.AbstractEAConfiguration;
18 import net.bmahe.genetics4j.core.spec.chromosome.ChromosomeSpec;
19 import net.bmahe.genetics4j.gp.Operation;
20 import net.bmahe.genetics4j.gp.program.Program;
21 import net.bmahe.genetics4j.gp.spec.chromosome.ProgramTreeChromosomeSpec;
22 import net.bmahe.genetics4j.gp.spec.mutation.Rule;
23 import net.bmahe.genetics4j.gp.utils.TreeNodeUtils;
24
25 public class ProgramRulesApplicatorMutator implements Mutator {
26 final static public Logger logger = LogManager.getLogger(ProgramRulesApplicatorMutator.class);
27
28 private final List<Rule> rules;
29 private final AbstractEAConfiguration eaConfiguration;
30
31 public ProgramRulesApplicatorMutator(final List<Rule> _rules, final AbstractEAConfiguration _eaConfiguration) {
32 Objects.requireNonNull(_rules);
33 Validate.isTrue(_rules.isEmpty() == false);
34 Objects.requireNonNull(_eaConfiguration);
35
36 this.rules = _rules;
37 this.eaConfiguration = _eaConfiguration;
38 }
39
40 protected TreeNode<Operation<?>> duplicateAndApplyRule(final Program program, final TreeNode<Operation<?>> root) {
41 Objects.requireNonNull(root);
42
43 logger.trace("A - {}", TreeNodeUtils.toStringTreeNode(root));
44
45 final Operation<?> rootOperation = root.getData();
46 final List<TreeNode<Operation<?>>> children = root.getChildren();
47
48 TreeNode<Operation<?>> currentRoot = new TreeNode<Operation<?>>(rootOperation);
49
50 if (children.size() > 0) {
51 final List<TreeNode<Operation<?>>> newChildren = new ArrayList<>();
52 for (int i = 0; i < children.size(); i++) {
53 final TreeNode<Operation<?>> childNode = children.get(i);
54
55 final TreeNode<Operation<?>> childCopy = duplicateAndApplyRule(program, childNode);
56 newChildren.add(childCopy);
57
58 }
59 currentRoot.addChildren(newChildren);
60 }
61
62 boolean done = false;
63 while (done == false) {
64 final TreeNode<Operation<?>> localRoot = currentRoot;
65
66 logger.trace("B - {}", TreeNodeUtils.toStringTreeNode(localRoot));
67
68 final Optional<Rule> applicableRule = rules.stream()
69 .filter((rule) -> rule.test(localRoot))
70 .findFirst();
71 final Optional<TreeNode<Operation<?>>> newRootOpt = applicableRule.map(x -> x.apply(program, localRoot));
72
73 done = newRootOpt.map(newRoot -> TreeNodeUtils.areSame(newRoot, localRoot))
74 .orElse(true);
75
76 if (newRootOpt.isPresent()) {
77 currentRoot = newRootOpt.get();
78 }
79 }
80
81 return currentRoot;
82 }
83
84 @Override
85 public Genotype mutate(final long generation, final Genotype original) {
86 Objects.requireNonNull(original);
87
88 logger.trace("Mutating genotype: {}", original);
89
90 final Chromosome[] newChromosomes = new Chromosome[original.getSize()];
91 final Chromosome[] chromosomes = original.getChromosomes();
92 for (int chromosomeIndex = 0; chromosomeIndex < chromosomes.length; chromosomeIndex++) {
93 final ChromosomeSpec chromosomeSpec = eaConfiguration.getChromosomeSpec(chromosomeIndex);
94 final Chromosome chromosome = chromosomes[chromosomeIndex];
95
96 if (chromosomeSpec instanceof ProgramTreeChromosomeSpec == false) {
97 throw new IllegalArgumentException("This mutator does not support chromosome specs " + chromosomeSpec);
98 }
99
100 if (chromosome instanceof TreeChromosome<?> == false) {
101 throw new IllegalArgumentException(
102 "This mutator does not support chromosome of type " + chromosome.getClass()
103 .getSimpleName());
104 }
105
106 final ProgramTreeChromosomeSpec programTreeChromosomeSpec = (ProgramTreeChromosomeSpec) chromosomeSpec;
107
108 final TreeChromosome<Operation<?>> treeChromosome = (TreeChromosome<Operation<?>>) chromosome;
109 final TreeNode<Operation<?>> root = treeChromosome.getRoot();
110
111 if (logger.isTraceEnabled()) {
112 logger.trace("Original chromosome {} - {}", chromosomeIndex, TreeNodeUtils.toStringTreeNode(root));
113 }
114
115 final TreeNode<Operation<?>> newRoot = duplicateAndApplyRule(programTreeChromosomeSpec.program(), root);
116 final TreeChromosome<Operation<?>> newTreeChromosome = new TreeChromosome<>(newRoot);
117 newChromosomes[chromosomeIndex] = newTreeChromosome;
118
119 }
120
121 return new Genotype(newChromosomes);
122 }
123 }