Skip to content

Commit

Permalink
NSGA-II
Browse files Browse the repository at this point in the history
  • Loading branch information
chen0040 committed Jun 17, 2017
1 parent 74f87d2 commit 8cf7be8
Show file tree
Hide file tree
Showing 18 changed files with 527 additions and 3 deletions.
159 changes: 159 additions & 0 deletions src/main/java/com/github/chen0040/moea/algorithms/NSGAII.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
package com.github.chen0040.moea.algorithms;


import com.github.chen0040.data.utils.TupleTwo;
import com.github.chen0040.moea.components.*;
import com.github.chen0040.moea.enums.ReplacementType;
import com.github.chen0040.moea.utils.InvertedCompareUtils;
import com.github.chen0040.moea.utils.TournamentSelection;
import com.github.chen0040.moea.utils.TournamentSelectionResult;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;


/**
* Created by xschen on 17/6/2017.
* NSGA-II
*/
@Getter
@Setter
public class NSGAII {
private Mediator mediator = new Mediator();

@Setter(AccessLevel.NONE)
private NondominatedPopulation archive = new NondominatedPopulation();

@Setter(AccessLevel.NONE)
private int currentGeneration = 0;

@Setter(AccessLevel.NONE)
private NondominatedSortingPopulation population = new NondominatedSortingPopulation();

public NondominatedPopulation solve(){
initialize();
int maxGenerations = mediator.getMaxGenerations();
for(int generation = 0; generation < maxGenerations; ++generation) {
evolve();
}

return archive;
}

public void initialize(){
population.setMediator(mediator);
population.initialize();
evaluate(population);
population.sort();
currentGeneration = 0;
}

public void evolve()
{
Population offspring = new Population();
offspring.setMediator(mediator);

int populationSize = mediator.getPopulationSize();

while (offspring.size() < populationSize)
{
TournamentSelectionResult<Solution> tournament = TournamentSelection.select(population.getSolutions(), mediator.getRandomGenerator(), (s1, s2) ->
{
int flag = 0;
if ((flag = InvertedCompareUtils.ConstraintCompare(s1, s2))==0)
{
if ((flag = InvertedCompareUtils.ParetoObjectiveCompare(s1, s2)) == 0)
{
flag = InvertedCompareUtils.CrowdingDistanceCompare(s1, s2);
}
}

return flag < 0; // should return better
});

TupleTwo<Solution, Solution> tournament_winners = tournament.getWinners();

TupleTwo<Solution, Solution> children = Crossover.apply(mediator, tournament_winners._1(), tournament_winners._2());

Mutation.apply(mediator, children._1());
Mutation.apply(mediator, children._2());
offspring.add(children._1());
offspring.add(children._2());
}

evaluate(offspring);

ReplacementType replacementType = mediator.getReplacementType();
if(replacementType == ReplacementType.Generational) {
merge1(offspring);
} else if(replacementType == ReplacementType.Tournament) {
merge2(offspring);
}

currentGeneration++;
}

private void evaluate(Population population) {
for (int i = 0; i < population.size(); ++i)
{
Solution s = population.getSolutions().get(i);
s.evaluate(mediator);

boolean is_archivable = archive.add(s);
if (archive.size() > mediator.getMaxArchive())
{
archive.truncate(mediator.getMaxArchive());
}
}
}

protected void merge2(Population children)
{
int populationSize = mediator.getPopulationSize();

Population offspring = new Population();

for (int i = 0; i < populationSize; i++)
{
Solution s1 = children.get(i);
Solution s2 = population.get(i);
int flag = 0;
if ((flag = InvertedCompareUtils.ConstraintCompare(s1, s2)) == 0)
{
if ((flag = InvertedCompareUtils.ParetoObjectiveCompare(s1, s2)) == 0)
{
flag = InvertedCompareUtils.CrowdingDistanceCompare(s1, s2);
}
}

if (flag < 0)
{
offspring.add(children.get(i));
}
else if (flag > 0)
{
offspring.add(children.get(i));
}
else
{
offspring.add(children.get(i));
offspring.add(population.get(i));
}
}

population.clear();

population.add(offspring);

population.prune(populationSize);
}

protected void merge1(Population children)
{
int populationSize = mediator.getPopulationSize();

population.add(children);

population.truncate(populationSize);
}
}
25 changes: 25 additions & 0 deletions src/main/java/com/github/chen0040/moea/components/Crossover.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.github.chen0040.moea.components;


import com.github.chen0040.data.utils.TupleTwo;
import com.github.chen0040.moea.enums.CrossoverType;


/**
* Created by xschen on 17/6/2017.
*/
public class Crossover {
public static TupleTwo<Solution, Solution> apply(Mediator mediator, Solution solution1, Solution solution2) {
Solution child1 = solution1.makeCopy();
Solution child2 = solution2.makeCopy();

CrossoverType crossoverType = mediator.getCrossoverType();
if(crossoverType == CrossoverType.OnePoint) {
child1.onePointCrossover(mediator, child2);
} else if(crossoverType == CrossoverType.Uniform) {
child2.uniformCrossover(mediator, child2);
}

return new TupleTwo<>(child1, child2);
}
}
23 changes: 23 additions & 0 deletions src/main/java/com/github/chen0040/moea/components/Mediator.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package com.github.chen0040.moea.components;


import com.github.chen0040.moea.enums.CrossoverType;
import com.github.chen0040.moea.enums.MutationType;
import com.github.chen0040.moea.enums.ReplacementType;
import com.github.chen0040.moea.tutorials.Tutorial;
import com.github.chen0040.moea.utils.CostFunction;
import lombok.Getter;
import lombok.Setter;
Expand All @@ -19,12 +23,31 @@ public class Mediator implements Serializable {

private int objectiveCount;
private int dimension;
private int maxGenerations = 1000;
private List<Double> lowerBounds = new ArrayList<>();
private List<Double> upperBounds = new ArrayList<>();
private RandomGenerator randomGenerator = new RandomGeneratorImpl();
private double mutationRate = 0.1;
private CostFunction costFunction;
private int populationSize = 1000;
private MutationType mutationType = MutationType.Uniform;
private CrossoverType crossoverType = CrossoverType.OnePoint;
private ReplacementType replacementType = ReplacementType.Generational;
private int maxArchive = 50;

public void read(Tutorial tutorial) {
objectiveCount = tutorial.getObjectiveCount();
dimension = tutorial.getDimension();

lowerBounds.clear();
lowerBounds.addAll(tutorial.getLowerBounds());

upperBounds.clear();
upperBounds.addAll(tutorial.getUpperBounds());

costFunction = (CostFunction) (s, objective_index, lowerBounds, upperBounds) -> tutorial.getCost(s, objective_index);
}


public double randomWithinBounds(int index){
double lowerBound = lowerBounds.get(index);
Expand Down
18 changes: 18 additions & 0 deletions src/main/java/com/github/chen0040/moea/components/Mutation.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.github.chen0040.moea.components;


import com.github.chen0040.moea.enums.MutationType;


/**
* Created by xschen on 17/6/2017.
*/
public class Mutation {
public static void apply(Mediator mediator, Solution solution) {
MutationType mutationType = mediator.getMutationType();
if(mutationType == MutationType.Uniform) {
solution.mutateUniformly(mediator);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ protected double getDistance(Solution s1, Solution s2)
}

// sort by costs and constraints and truncate
public void sortDescAndTruncate(int size)
public void truncate(int size)
{
// solutions must be sorted descendingly such that solutions[0] is the best solution
sortAndTruncate(size, NondominatedPopulation::invertedCompare);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public void sort(){
}

// sort by rank and crowding distance and truncate
public void sortDescAndTruncate(int size)
public void truncate(int size)
{
ensureRankedByObjectiveAndConstraint();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,4 +181,8 @@ public double getConstraint(int i) {
return constraints.get(i);
}


@Override public String toString() {
return "Solution{" + "costs=" + costs + ", data=" + data + '}';
}
}
10 changes: 10 additions & 0 deletions src/main/java/com/github/chen0040/moea/enums/CrossoverType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.github.chen0040.moea.enums;


/**
* Created by xschen on 17/6/2017.
*/
public enum CrossoverType {
OnePoint,
Uniform
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.github.chen0040.moea.enums;


/**
* Created by xschen on 17/6/2017.
*/
public enum MutationType {
Uniform
}
10 changes: 10 additions & 0 deletions src/main/java/com/github/chen0040/moea/enums/ReplacementType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.github.chen0040.moea.enums;


/**
* Created by xschen on 17/6/2017.
*/
public enum ReplacementType {
Tournament,
Generational
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.github.chen0040.moea.exceptions;


import lombok.Getter;
import lombok.Setter;


/**
* Created by xschen on 17/6/2017.
*/
@Getter
@Setter
public class OutOfRangeException extends RuntimeException {
private static final long serialVersionUID = -9128963842995898067L;
private final int actualSize;
private final int minSize;
private final int maxSize;

public OutOfRangeException(int actual_size, int min_size, int max_size) {
this.actualSize = actual_size;
this.minSize = min_size;
this.maxSize = max_size;
}
}

0 comments on commit 8cf7be8

Please sign in to comment.