Skip to content

Commit

Permalink
Merge pull request #50 from koosvary/feature/seamo
Browse files Browse the repository at this point in the history
Feature/seamo
  • Loading branch information
ScottWalkerAU authored Oct 11, 2018
2 parents b2c655f + c6d3361 commit cd2195b
Show file tree
Hide file tree
Showing 24 changed files with 1,135 additions and 201 deletions.
62 changes: 45 additions & 17 deletions api/src/main/java/org/iconic/ea/EvolutionaryAlgorithm.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,32 +21,39 @@
*/
package org.iconic.ea;

import lombok.extern.log4j.Log4j2;
import org.iconic.ea.chromosome.Chromosome;
import org.iconic.ea.chromosome.ChromosomeFactory;
import org.iconic.ea.operator.evolutionary.crossover.Crossover;
import org.iconic.ea.operator.evolutionary.mutation.Mutator;
import org.iconic.ea.operator.evolutionary.selection.Selection;
import org.iconic.ea.operator.evolutionary.selection.Selector;
import org.iconic.ea.operator.objective.CacheableObjective;
import org.iconic.ea.operator.objective.Objective;

import java.lang.reflect.Method;
import java.util.LinkedList;
import java.util.List;

public abstract class EvolutionaryAlgorithm<T extends Chromosome<R>, R> {
@Log4j2
public abstract class EvolutionaryAlgorithm<T extends Chromosome<R>, R extends Comparable<R>> {
private final ChromosomeFactory<T, R> chromosomeFactory;
private final List<Crossover<T, R>> crossovers;
private final List<Mutator<T, R>> mutators;
private final List<Selection<T, R>> selectors;
private final List<Objective<R>> objectives;
private final List<Selector<T>> selectors;
private double crossoverProbability;
private double mutationProbability;
private Objective<R> objective;
private List<T> chromosomes;

protected EvolutionaryAlgorithm() {
protected EvolutionaryAlgorithm(ChromosomeFactory<T, R> chromosomeFactory) {
this.chromosomeFactory = chromosomeFactory;
this.crossovers = new LinkedList<>();
this.mutators = new LinkedList<>();
this.selectors = new LinkedList<>();
this.objectives = new LinkedList<>();
this.chromosomes = new LinkedList<>();
this.crossoverProbability = 0.2;
this.mutationProbability = 0.1;
this.objective = null;
}

public abstract void initialisePopulation(int populationSize);
Expand All @@ -61,12 +68,18 @@ protected List<Mutator<T, R>> getMutators() {
return mutators;
}

protected List<Selection<T, R>> getSelectors() {
protected List<Selector<T>> getSelectors() {
return selectors;
}

protected List<Objective<R>> getObjectives() {
return objectives;
@SuppressWarnings("unchecked cast")
protected Objective<R> getObjective() {
if (isCached(objective)) {
CacheableObjective<R> cacheableObjective = (CacheableObjective<R>) getObjective();
return cacheableObjective.getObjective();
}

return objective;
}

public Crossover<T, R> getCrossover(final int i) {
Expand All @@ -77,14 +90,10 @@ public Mutator<T, R> getMutator(final int i) {
return getMutators().get(i);
}

public Selection<T, R> getSelector(final int i) {
public Selector<T> getSelector(final int i) {
return getSelectors().get(i);
}

public Objective<R> getObjective(final int i) {
return getObjectives().get(i);
}

public void addCrossover(Crossover<T, R> crossover) {
getCrossovers().add(crossover);
}
Expand All @@ -93,12 +102,27 @@ public void addMutator(Mutator<T, R> mutator) {
getMutators().add(mutator);
}

public void addSelector(Selection<T, R> selector) {
public void addSelector(Selector<T> selector) {
getSelectors().add(selector);
}

public void addObjective(Objective<R> objective) {
getObjectives().add(objective);
@SuppressWarnings("unchecked cast")
public void setObjective(final Objective<R> objective) {
if (isCached(objective)) {
this.objective = new CacheableObjective<R>(objective);
} else {
this.objective = objective;
}
}

private static boolean isCached(final Objective<?> objective) {
try {
Method m = EvolutionaryAlgorithm.class.getDeclaredMethod("setObjective", Objective.class);
return false;
} catch (NoSuchMethodException ex) {
log.warn("Method setObjective(Objective) not found");
}
return false;
}

public List<T> getChromosomes() { return chromosomes; }
Expand All @@ -122,4 +146,8 @@ public double getMutationProbability() {
public void setMutationProbability(double mutationProbability) {
this.mutationProbability = mutationProbability;
}

public ChromosomeFactory<T, R> getChromosomeFactory() {
return chromosomeFactory;
}
}
7 changes: 7 additions & 0 deletions api/src/main/java/org/iconic/ea/chromosome/Chromosome.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
*/
package org.iconic.ea.chromosome;

import lombok.extern.log4j.Log4j2;
import org.iconic.ea.chromosome.cartesian.CartesianChromosome;
import org.iconic.ea.data.DataManager;
import org.iconic.ea.operator.primitive.FunctionalPrimitive;

Expand All @@ -33,6 +35,7 @@
* output of the same form as its input.
* @param <T> The type class of the data to pass through the chromosome
*/
@Log4j2
public abstract class Chromosome<T> {
private boolean changed;
private double fitness;
Expand Down Expand Up @@ -152,6 +155,7 @@ public String getExpression(String preorderExpression, List<FunctionalPrimitive<
leadingPrimitive = matchPrimitive(firstFunction, primitives);

if(leadingPrimitive==null){
log.warn("Unrecognised function in expression");
return "Unrecognised function in expression";
}

Expand Down Expand Up @@ -220,6 +224,7 @@ else if(preorderExpression.charAt(i) == ')'){
}

/* this should only output on invalid expressions */
log.warn("Unable to parse expression");
return "Somethingwentwrong";
}

Expand All @@ -244,4 +249,6 @@ private FunctionalPrimitive<T, T> matchPrimitive(String primString, List<Functio
* @return The size of the chromosome
*/
public abstract int getSize();

public abstract Chromosome<T> clone();
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
*/
package org.iconic.ea.chromosome.cartesian;

import lombok.extern.log4j.Log4j2;
import org.iconic.ea.chromosome.Chromosome;
import org.iconic.ea.chromosome.LinearChromosome;
import org.iconic.ea.data.DataManager;
Expand All @@ -38,6 +39,7 @@
* Cycles in the graph are prevented by restricting nodes in the graph such that they can only connect to
* preceding nodes. The genome is linearly encoded and can support multiple outputs.</p>
*/
@Log4j2
public class CartesianChromosome<T> extends Chromosome<T> implements LinearChromosome<Integer>, Cloneable {
private Map<Integer, List<Integer>> phenome;
private List<Integer> outputs;
Expand All @@ -47,7 +49,7 @@ public class CartesianChromosome<T> extends Chromosome<T> implements LinearChrom
private final int columns;
private final int levelsBack;
private final int maxArity;
List<Map<Integer, T>> results;
List<Map<Integer, T>> results;

/**
* <p>Constructs a new cartesian chromosome with the provided number of inputs, columns, rows, and
Expand Down Expand Up @@ -78,7 +80,7 @@ public CartesianChromosome(
this.outputs = outputs;
this.phenome = new HashMap<>();
this.genome = genome;
results = new ArrayList<>();
results = new ArrayList<>();
// Create a comparator for calculating the maximum arity
final Comparator<FunctionalPrimitive<T, T>> comparator =
Comparator.comparing(FunctionalPrimitive::getArity);
Expand All @@ -88,11 +90,11 @@ public CartesianChromosome(

if (max.isPresent()) {
maxArity = max.get().getArity();
} else{ // If no max value is present something has gone horribly wrong (how'd it even get here?)
throw new IllegalStateException(
"Invalid number of primitives present in chromosome." +
"There should be at least one primitive present.");
}
} else { // If no max value is present something has gone horribly wrong (how'd it even get here?)
throw new IllegalStateException(
"Invalid number of primitives present in chromosome." +
"There should be at least one primitive present.");
}
}

/**
Expand All @@ -110,7 +112,7 @@ public int getNumberOfNodes() {
* @param node the position of the node to produce an index for
* @param inputs the number of inputs in the chromosome the node belongs to
* @param maxArity the maximum arity of the chromosome the node belongs to
* @return the index of the node within its genome
* @return the index of the node within its genome
*/
static public int nodeToIndex(int node, int inputs, int maxArity) {
return (node < inputs) ? node : (maxArity + 1) * (node - inputs) + inputs;
Expand Down Expand Up @@ -277,15 +279,16 @@ public List<Map<Integer, T>> evaluate(final DataManager<T> dataManager) {

calculatedValues.add(output);
}
results = new ArrayList<>(calculatedValues);
setChanged(false);
results = new ArrayList<>(calculatedValues);
return calculatedValues;
}

public List<Map<Integer, T>> getResults(){
return results;
}
public List<Map<Integer, T>> getResults() {
return results;
}

/**
/**
* <p>Returns a human-readable representation of a node in this chromosome</p>
*
* @param node the node to format
Expand Down Expand Up @@ -355,37 +358,36 @@ public String toString() {
return outputBuilder.toString();
}

public String getExpression(){
public String getExpression() {
Map<Integer, List<Integer>> nodes = getPhenome();
String[] expressions = new String[genome.size()+getOutputs().size()];
String[] expressions = new String[genome.size() + getOutputs().size()];
Set<Integer> keysSet = nodes.keySet();
Integer[] keys = keysSet.toArray(new Integer[0]);
List<Integer> actualNodes = null;
String alph = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
for(int i = 0; i < getInputs(); i++){
expressions[i] = String.valueOf(alph.charAt(i));
for (int i = 0; i < getInputs(); i++) {
expressions[i] = String.valueOf(alph.charAt(i));
}
for(int i = 0; i < getOutputs().size(); i++){
for (int i = 0; i < getOutputs().size(); i++) {
actualNodes = nodes.get(keys[i]);
for(int j = 0; j < actualNodes.size(); j++){
for (int j = 0; j < actualNodes.size(); j++) {
final int index = nodeToIndex(actualNodes.get(j), getInputs(), maxArity);
if(index < getInputs())
if (index < getInputs())
continue;
final int functionGene = genome.get(index);
final FunctionalPrimitive<?, ?> primitive = primitives.get(functionGene);
final int arity = primitive.getArity();
if(arity == 1){
if (arity == 1) {
final int connectionGene = genome.get(index + 1);
expressions[index] = "(" + primitive.getSymbol() + "(" + expressions[nodeToIndex(connectionGene, getInputs(), maxArity)] + "))";
}
else{
} else {
final int fConnectionGene = genome.get(index + 1);
final int sConnectionGene = genome.get(index + 2);
expressions[index] = "(" + expressions[nodeToIndex(fConnectionGene, getInputs(), maxArity)] + primitive.getSymbol() + expressions[nodeToIndex(sConnectionGene, getInputs(), maxArity)] + ")";
}
}
}
return expressions[nodeToIndex(actualNodes.get(actualNodes.size()-1), getInputs(), maxArity)];
return expressions[nodeToIndex(actualNodes.get(actualNodes.size() - 1), getInputs(), maxArity)];
}

/**
Expand Down Expand Up @@ -418,7 +420,13 @@ private void setOutputs(List<Integer> outputs) {
* @param phenome The new phenome of the chromosome
*/
private void setPhenome(Map<Integer, List<Integer>> phenome) {
this.phenome = phenome;
this.phenome = new LinkedHashMap<>();

for (Map.Entry<Integer, List<Integer>> output: phenome.entrySet()) {
List<Integer> genes = new LinkedList<>();
genes.addAll(output.getValue());
this.phenome.put(output.getKey(), genes);
}
}

/**
Expand Down Expand Up @@ -519,6 +527,7 @@ public CartesianChromosome<T> clone() {
clone.setGenome(getGenome());
clone.setOutputs(getOutputs());
clone.setFitness(getFitness());
clone.setPhenome(getPhenome());
clone.setChanged(isChanged());

return clone;
Expand All @@ -530,4 +539,27 @@ public CartesianChromosome<T> clone() {
public int getSize() {
return outputs.size() + phenome.size();
}
}

/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
return Objects.hash(this.getPhenome());
}

/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
} else if (o instanceof CartesianChromosome) {
CartesianChromosome<?> other = (CartesianChromosome<?>) o;
return Objects.deepEquals(this.getPhenome(), other.getPhenome()) &&
Objects.equals(this.isChanged(), other.isChanged());
}
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.iconic.ea.chromosome.Chromosome;
import org.iconic.ea.chromosome.LinearChromosome;
import org.iconic.ea.chromosome.TreeChromosome;
import org.iconic.ea.chromosome.cartesian.CartesianChromosome;
import org.iconic.ea.chromosome.graph.Node;
import org.iconic.ea.data.DataManager;
import org.iconic.ea.data.FeatureClass;
Expand Down Expand Up @@ -264,4 +265,31 @@ public ExpressionChromosome<T> clone() {
public int getSize() {
return root.getSize();
}


/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
return Objects.hash(this.getGenome(), this.getHeadLength(), this.getTailLength());
}

/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
} else if (o instanceof ExpressionChromosome<?>) {
ExpressionChromosome<?> other = (ExpressionChromosome<?>) o;
return Objects.deepEquals(this.getGenome(), other.getGenome()) &&
Objects.equals(this.isChanged(), other.isChanged() &&
Objects.equals(this.getHeadLength(), other.getHeadLength()) &&
Objects.equals(this.getTailLength(), other.getTailLength())
);
}
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ public CartesianChromosome<R> apply(final List<FunctionalPrimitive<R, R>> functi
mutant.getInputs(), mutant.getInputs() + numNodes + numOutputs - 1
);

//ensure the mutant gets updated the next time it's evaluated
mutant.setChanged(true);

//the main loop runs until an active gene is mutated
while (!activeNodeMutated) {
//picking the gene to mutate
Expand Down
Loading

0 comments on commit cd2195b

Please sign in to comment.