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 }