1 package net.bmahe.genetics4j.gp.mutation; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 import java.util.Optional; 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.spec.chromosome.ProgramTreeChromosomeSpec; 21 import net.bmahe.genetics4j.gp.spec.mutation.Rule; 22 import net.bmahe.genetics4j.gp.utils.TreeNodeUtils; 23 24 public class ProgramRulesApplicatorMutator implements Mutator { 25 final static public Logger logger = LogManager.getLogger(ProgramRulesApplicatorMutator.class); 26 27 private final List<Rule> rules; 28 private final AbstractEAConfiguration eaConfiguration; 29 30 public ProgramRulesApplicatorMutator(final List<Rule> _rules, final AbstractEAConfiguration _eaConfiguration) { 31 Validate.notNull(_rules); 32 Validate.isTrue(_rules.isEmpty() == false); 33 Validate.notNull(_eaConfiguration); 34 35 this.rules = _rules; 36 this.eaConfiguration = _eaConfiguration; 37 } 38 39 protected TreeNode<Operation<?>> duplicateAndApplyRule(final Program program, final TreeNode<Operation<?>> root) { 40 Validate.notNull(root); 41 42 logger.trace("A - {}", TreeNodeUtils.toStringTreeNode(root)); 43 44 final Operation<?> rootOperation = root.getData(); 45 final List<TreeNode<Operation<?>>> children = root.getChildren(); 46 47 TreeNode<Operation<?>> currentRoot = new TreeNode<Operation<?>>(rootOperation); 48 49 if (children.size() > 0) { 50 final List<TreeNode<Operation<?>>> newChildren = new ArrayList<>(); 51 for (int i = 0; i < children.size(); i++) { 52 final TreeNode<Operation<?>> childNode = children.get(i); 53 54 final TreeNode<Operation<?>> childCopy = duplicateAndApplyRule(program, childNode); 55 newChildren.add(childCopy); 56 57 } 58 currentRoot.addChildren(newChildren); 59 } 60 61 boolean done = false; 62 while (done == false) { 63 final TreeNode<Operation<?>> localRoot = currentRoot; 64 65 logger.trace("B - {}", TreeNodeUtils.toStringTreeNode(localRoot)); 66 67 final Optional<Rule> applicableRule = rules.stream().filter((rule) -> rule.test(localRoot)).findFirst(); 68 final Optional<TreeNode<Operation<?>>> newRootOpt = applicableRule.map(x -> x.apply(program, localRoot)); 69 70 done = newRootOpt.map(newRoot -> TreeNodeUtils.areSame(newRoot, localRoot)).orElse(true); 71 72 if (newRootOpt.isPresent()) { 73 currentRoot = newRootOpt.get(); 74 } 75 } 76 77 return currentRoot; 78 } 79 80 @Override 81 public Genotype mutate(final Genotype original) { 82 Validate.notNull(original); 83 84 logger.trace("Mutating genotype: {}", original); 85 86 final Chromosome[] newChromosomes = new Chromosome[original.getSize()]; 87 final Chromosome[] chromosomes = original.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().getSimpleName()); 99 } 100 101 final ProgramTreeChromosomeSpec programTreeChromosomeSpec = (ProgramTreeChromosomeSpec) chromosomeSpec; 102 103 final TreeChromosome<Operation<?>> treeChromosome = (TreeChromosome<Operation<?>>) chromosome; 104 final TreeNode<Operation<?>> root = treeChromosome.getRoot(); 105 106 if (logger.isTraceEnabled()) { 107 logger.trace("Original chromosome {} - {}", chromosomeIndex, TreeNodeUtils.toStringTreeNode(root)); 108 } 109 110 final TreeNode<Operation<?>> newRoot = duplicateAndApplyRule(programTreeChromosomeSpec.program(), root); 111 final TreeChromosome<Operation<?>> newTreeChromosome = new TreeChromosome<>(newRoot); 112 newChromosomes[chromosomeIndex] = newTreeChromosome; 113 114 } 115 116 return new Genotype(newChromosomes); 117 } 118 }