diff --git a/src/main/java/Evaluators/EvaluatorNESW.java b/src/main/java/Evaluators/EvaluatorNESW.java index dd4d9e62988f11321bc136166a5b037c9e2970b0..04cbb1286f03a6cffb45db1ef33e1b884d29e5c4 100644 --- a/src/main/java/Evaluators/EvaluatorNESW.java +++ b/src/main/java/Evaluators/EvaluatorNESW.java @@ -17,7 +17,9 @@ public class EvaluatorNESW implements Evaluator { @Override public double evaluateFitness(Candidate candidate) { - if (candidate.fitness <= -1) { // Not calculated before + //TODO Is it a good idea to "cache" fitness this way? Maybe + //If fitness was not calculated yet, calculate it + if (candidate.getFitness() <= -1) { // Not calculated before double fitness; int hydrophobicBonds = evaluateBonds(candidate); @@ -25,22 +27,22 @@ public class EvaluatorNESW implements Evaluator { fitness =(double) (hydrophobicBonds * this.POINTS_PER_BOND) / (double) (overlaps + 1); - candidate.fitness = fitness; + candidate.setFitness(fitness); } - // Return cached value if this is not the first time the value is needed - return candidate.fitness; + + return candidate.getFitness(); } public int evaluateBonds(Candidate candidate) { int bonds = 0; - for (int i = 0; i < candidate.vertexList.size() - 2; i++) { - Vertex toCompare = candidate.vertexList.get(i); + for (int i = 0; i < candidate.getVertices().size() - 2; i++) { + Vertex toCompare = candidate.getVertices().get(i); if (isHydrophobic[i]==1) { - for (int j = i + 2; j < candidate.vertexList.size(); j++) { - Vertex vertex = candidate.vertexList.get(j); + for (int j = i + 2; j < candidate.getVertices().size(); j++) { + Vertex vertex = candidate.getVertices().get(j); if (isHydrophobic[j]==1) { if (toCompare.neighbouringPosition(vertex)) { bonds++; @@ -55,9 +57,9 @@ public class EvaluatorNESW implements Evaluator { public int evaluateOverlaps(Candidate candidate) { int overlaps = 0; - for (int i = 0; i < candidate.vertexList.size(); i++) { - Vertex toCompare = candidate.vertexList.get(i); - for (Vertex vertex : candidate.vertexList) { + for (int i = 0; i < candidate.getVertices().size(); i++) { + Vertex toCompare = candidate.getVertices().get(i); + for (Vertex vertex : candidate.getVertices()) { if (toCompare.equalsPosition(vertex) && toCompare != vertex) { overlaps++; } diff --git a/src/main/java/MainClasses/Candidate.java b/src/main/java/MainClasses/Candidate.java index 10683bb60ed9d382184ce299e8cb7ddd2a9a80f5..8c556970b9fe64006fd3d0463e36990d612861fe 100644 --- a/src/main/java/MainClasses/Candidate.java +++ b/src/main/java/MainClasses/Candidate.java @@ -5,33 +5,32 @@ import java.util.Arrays; public class Candidate { - public int[] outgoingDirection; // 0 = North | 1 = East | 2 = South | 3 = West - public ArrayList<Vertex> vertexList; - public double fitness; - - public Candidate(int[] oD) { - this.outgoingDirection = oD; - this.vertexList = constructVertexes(); + private final int[] folding; // 0 = North | 1 = East | 2 = South | 3 = West + private ArrayList<Vertex> vertices; + private double fitness; + public Candidate(int[] folding) { + this.folding = folding; + this.vertices = constructVertices(); this.fitness = -1d; // Not calculated yet } - public ArrayList<Vertex> constructVertexes() { + public ArrayList<Vertex> constructVertices() { ArrayList<Vertex> vertexList = new ArrayList<>(); int currentX = 0; int currentY = 0; - for (int currentVertex = 0; currentVertex < outgoingDirection.length; currentVertex++) { - vertexList.add(new Vertex(currentX, currentY, outgoingDirection[currentVertex])); + for (int currentVertex = 0; currentVertex < folding.length; currentVertex++) { + vertexList.add(new Vertex(currentX, currentY, folding[currentVertex])); // Update position - if (outgoingDirection[currentVertex] == 0) { + if (folding[currentVertex] == 0) { currentY++; - } else if (outgoingDirection[currentVertex] == 1) { + } else if (folding[currentVertex] == 1) { currentX++; - } else if (outgoingDirection[currentVertex] == 2) { + } else if (folding[currentVertex] == 2) { currentY--; - } else if (outgoingDirection[currentVertex] == 3) { + } else if (folding[currentVertex] == 3) { currentX--; } } @@ -39,22 +38,32 @@ public class Candidate { return vertexList; } - public ArrayList<Vertex> getVertexList() { - return vertexList; + public ArrayList<Vertex> getVertices() { + return vertices; } @Override public String toString() { return "Canidate{" + - "outgoingDirection=" + Arrays.toString(outgoingDirection) + + "outgoingDirection=" + Arrays.toString(folding) + '}'; } - public int[] getOutgoing() { - int[] newOut = new int[this.outgoingDirection.length]; + //TODO What if fitness is not set yet? + public double getFitness() { + return fitness; + } + + public void setFitness(double fitness) { + this.fitness = fitness; + } + + //TODO Try out return folding without copy; + public int[] getFolding() { + int[] newOut = new int[this.folding.length]; - for(int i = 0; i < this.outgoingDirection.length; i++) { - newOut[i] = this.outgoingDirection[i]; + for(int i = 0; i < this.folding.length; i++) { + newOut[i] = this.folding[i]; } return newOut; diff --git a/src/main/java/MainClasses/GeneticAlgorithm.java b/src/main/java/MainClasses/GeneticAlgorithm.java index 654517b93e4198d916a7c0702500fb69036bbeaa..04bd367debc95f7b41222690dc86f08d2b9de736 100644 --- a/src/main/java/MainClasses/GeneticAlgorithm.java +++ b/src/main/java/MainClasses/GeneticAlgorithm.java @@ -158,7 +158,7 @@ public class GeneticAlgorithm { for (Visualizer v : this.visualizers) { v.setFilename(String.format("gen_%d.png", gen)); //TODO Print real bond and overlap amount - v.drawProtein(this.population[bestIndex].getVertexList(), bestFitness, -1, -1, gen); + v.drawProtein(this.population[bestIndex].getVertices(), bestFitness, -1, -1, gen); } //TODO Print real bond and overlap amount @@ -168,7 +168,7 @@ public class GeneticAlgorithm { // Save the overall best if (bestFitness >= this.overallBestFitness) { this.overallBestFitness = bestFitness; - this.overallBest = new Candidate(this.population[bestIndex].getOutgoing()); + this.overallBest = new Candidate(this.population[bestIndex].getFolding()); } double averageFitness = this.totalFitness / Config.POPULATION_SIZE; diff --git a/src/main/java/Mutators/Crossover.java b/src/main/java/Mutators/Crossover.java index 594adb1c89a8f4798cbb3fde3296f34f9aa1fed4..a76a47ad4e479f61cc948c55cb9bd8677c60c4ae 100644 --- a/src/main/java/Mutators/Crossover.java +++ b/src/main/java/Mutators/Crossover.java @@ -26,38 +26,39 @@ public class Crossover<T extends Enum<?>> implements Mutator { @Override public Candidate[] mutatePopulation(Candidate[] population) { + Candidate[] mutatedPopulation = new Candidate[population.length]; if (this.crossoverChance > MINIMUM_CHANCE) { int populationSize = population.length; - int proteinLength = population[0].getOutgoing().length; + int proteinLength = population[0].getFolding().length; - for (Candidate candidate : population) { + for (int candidateId = 0; candidateId<population.length ; candidateId++) { + //Mutates only the selected Candidate not the partner + int[] mutatedFolding = population[candidateId].getFolding(); for (int j = 0; j < this.crossoverAttemptsPerCandidate; j++) { if (this.crossoverChance > this.rand.nextDouble()) { int crossoverPartner = this.rand.nextInt(populationSize); int crossoverPlace = this.rand.nextInt(proteinLength); - - int[] originalDirections = new int[candidate.outgoingDirection.length]; - for (int i = crossoverPlace; i < candidate.outgoingDirection.length; i++) { - originalDirections[i] = candidate.outgoingDirection[i]; - } + int[] partnerFolding = population[crossoverPartner].getFolding(); // Edit these directions - for (int i = crossoverPlace; i < candidate.outgoingDirection.length; i++) { - candidate.outgoingDirection[i] = population[crossoverPartner].outgoingDirection[i]; + for (int i = crossoverPlace; i < mutatedFolding.length; i++) { + mutatedFolding[i] = partnerFolding[i]; } + // Removed partner crossover mutation, because this can lead to unexpected double mutations if the partner mutates again // Edit partners directions - for (int i = crossoverPlace; i < candidate.outgoingDirection.length; i++) { - population[crossoverPartner].outgoingDirection[i] = originalDirections[i]; - } + //for (int i = crossoverPlace; i < candidate.outgoingDirection.length; i++) { + // population[crossoverPartner].outgoingDirection[i] = originalDirections[i]; + //} } } + mutatedPopulation[candidateId] = new Candidate(mutatedFolding); } System.out.printf("CrossoverChance: %.4f\n", this.crossoverChance); this.crossoverChance *= (1 - this.crossoverMultiplier); // Lower mutation rate with generation } - return population; + return mutatedPopulation; } } diff --git a/src/main/java/Mutators/SinglePoint.java b/src/main/java/Mutators/SinglePoint.java index 90e42058ea3b1fde3c071488f7aa02dd2f29412c..99bb28666ead13473b528188863eefcf4f3837a2 100644 --- a/src/main/java/Mutators/SinglePoint.java +++ b/src/main/java/Mutators/SinglePoint.java @@ -26,23 +26,26 @@ public class SinglePoint<T extends Enum<?>> implements Mutator { @Override public Candidate[] mutatePopulation(Candidate[] population) { + Candidate[] mutatedPopulation = new Candidate[population.length]; if (this.mutationChance > MINIMUM_CHANCE) { - int proteinLength = population[0].getOutgoing().length; - for (Candidate candidate : population) { + int proteinLength = population[0].getFolding().length; + + + for (int candidateId = 0; candidateId<population.length ; candidateId++) { + int[] mutatedFolding = population[candidateId].getFolding(); for (int j = 0; j < this.mutationAttemptsPerCandidate; j++) { if (this.mutationChance > this.rand.nextDouble()) { int mutationPlace = this.rand.nextInt(proteinLength); // TODO: Use the enums or get rid of this hard coded 3 and 4... if (this.isFRL) { - candidate.outgoingDirection[mutationPlace] = this.rand.nextInt(3); - candidate.vertexList = candidate.constructVertexes(); + mutatedFolding[mutationPlace] = this.rand.nextInt(3); } else { - candidate.outgoingDirection[mutationPlace] = this.rand.nextInt(4); - candidate.vertexList = candidate.constructVertexes(); + mutatedFolding[mutationPlace] = this.rand.nextInt(4); } } } + mutatedPopulation[candidateId] = new Candidate(mutatedFolding); } System.out.printf("MutationChance: %.4f\n", this.mutationChance); diff --git a/src/main/java/Selectors/FitnessProportional.java b/src/main/java/Selectors/FitnessProportional.java index 68225ac6d1134f43fd4573997405b0fe6fe16e05..57b5b805a9e3ff13af997be64ef431966fcbac2e 100644 --- a/src/main/java/Selectors/FitnessProportional.java +++ b/src/main/java/Selectors/FitnessProportional.java @@ -33,7 +33,7 @@ public class FitnessProportional implements Selector { j++; picked -= proportionalFitness[j]; } - newPopulation[i] = new Candidate(population[j].getOutgoing()); + newPopulation[i] = new Candidate(population[j].getFolding()); } return newPopulation; diff --git a/src/main/java/Selectors/OnlyBest.java b/src/main/java/Selectors/OnlyBest.java index fff027fa565b70d4994a3a2cf26d8226b4a0b087..4f0980bf5ba0b432a6f298c859a1b0fa445b76c3 100644 --- a/src/main/java/Selectors/OnlyBest.java +++ b/src/main/java/Selectors/OnlyBest.java @@ -28,7 +28,7 @@ public class OnlyBest implements Selector { } Candidate[] newPopulation = new Candidate[populationSize]; - int[] bestFolding = population[bestIndex].getOutgoing(); + int[] bestFolding = population[bestIndex].getFolding(); for (int i = 0; i < populationSize; i++) { newPopulation[i] = new Candidate(bestFolding); diff --git a/src/main/java/Selectors/Tournament.java b/src/main/java/Selectors/Tournament.java index 3cb928dca54fc23316db2d14988536bcb3a23732..e82b9fd78723bbf25ea2d50dcdb3ecb754a396ee 100644 --- a/src/main/java/Selectors/Tournament.java +++ b/src/main/java/Selectors/Tournament.java @@ -35,7 +35,7 @@ public class Tournament implements Selector { tournamentChoosenIndex = nextIndex; } } - newPopulation[i] = new Candidate(population[tournamentChoosenIndex].getOutgoing()); + newPopulation[i] = new Candidate(population[tournamentChoosenIndex].getFolding()); } return newPopulation;