-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added unit tests for ParetoSet implementations (#270)
* Changed type of parameter received in methods dedicated to generate lists of TestMove objects, since variable score is a double. * Added two classes that are useful to implement unit tests in multi-objective contexts. TestSolutionWithMultipleObjectives is similar to TestSolution, but can have more than one objective. TestMoveWithMultipleObjectives is similar to TestMove, but can have more than one objective. * Changed hashCode method to be consistent with equals. * Added unit tests for ParetoSimpleList class. * Removed unnecessary line. * Added unit tests for ParetoByFirstObjective and NDTree. * Added MOAlgorithm, needed to define a generic algorithm that returns a ParetoSet instead of a single solution.
- Loading branch information
1 parent
c199942
commit 75a904b
Showing
7 changed files
with
890 additions
and
2 deletions.
There are no files selected for viewing
97 changes: 97 additions & 0 deletions
97
common/src/main/java/es/urjc/etsii/grafo/algorithms/mo/MOAlgorithm.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
package es.urjc.etsii.grafo.algorithms.mo; | ||
|
||
import es.urjc.etsii.grafo.annotations.AlgorithmComponent; | ||
import es.urjc.etsii.grafo.create.builder.SolutionBuilder; | ||
import es.urjc.etsii.grafo.io.Instance; | ||
import es.urjc.etsii.grafo.mo.pareto.ParetoSet; | ||
import es.urjc.etsii.grafo.solution.Solution; | ||
|
||
import java.util.Objects; | ||
|
||
|
||
/** | ||
* Base algorithm class, all algorithms should extend this class or any of its subclasses. | ||
* | ||
* @param <S> Solution class | ||
* @param <I> Instance class | ||
*/ | ||
@AlgorithmComponent | ||
public abstract class MOAlgorithm<S extends Solution<S,I>, I extends Instance> { | ||
|
||
private SolutionBuilder<S,I> builder; | ||
private String algorithmName; | ||
|
||
/** | ||
* Initialize common algorithm fields | ||
* @param algorithmName algorithm name. See {@link #setName(String)} | ||
*/ | ||
protected MOAlgorithm(String algorithmName) { | ||
this.algorithmName = algorithmName; | ||
} | ||
|
||
/** | ||
* Algorithm name, uniquely identifies the algorithm inside an experiment | ||
* | ||
* @return algorithm name | ||
*/ | ||
public String getName(){ | ||
return this.algorithmName; | ||
} | ||
|
||
/** | ||
* Sets the algorithm name. | ||
* This method can be called after the algorithm has been built, | ||
* for example if we want to customize the name generated by the autoconfig module. | ||
* This method CANNOT be called after the algorithm has started executing, as it would break the experiment results. | ||
* The algorithm name is used to uniquely identify the algorithm inside an experiment. | ||
* | ||
* @param algorithmName must uniquely identify the algorithm inside an experiment | ||
*/ | ||
public void setName(String algorithmName){ | ||
this.algorithmName = algorithmName; | ||
} | ||
|
||
/** | ||
* Runs the algorithm | ||
* | ||
* @param instance Instance to solve | ||
* @return Built solution | ||
*/ | ||
public abstract ParetoSet<S, I> algorithm(I instance); | ||
|
||
/** | ||
* Create a new solution for the given instance. Solution is empty by default. | ||
* | ||
* @param instance Instance | ||
* @return Empty solution, by default created calling the constructor Solution(Instance i) | ||
*/ | ||
public S newSolution(I instance){ | ||
return this.builder.initializeSolution(instance); | ||
} | ||
|
||
/** | ||
* Get solution builder | ||
* | ||
* @return solution builder | ||
*/ | ||
protected SolutionBuilder<S, I> getBuilder() { | ||
return builder; | ||
} | ||
|
||
/** | ||
* Set solution builder, used by the framework. | ||
* In case an algorithms contains another algorithms, this method should be overridden as follows: | ||
* <pre> | ||
* @Override | ||
* public void setBuilder(SolutionBuilder<S, I> builder) { | ||
* super.setBuilder(builder); | ||
* this.algorithm.setBuilder(builder); | ||
* } | ||
* </pre> | ||
* | ||
* @param builder solution builder | ||
*/ | ||
public void setBuilder(SolutionBuilder<S, I> builder) { | ||
this.builder = Objects.requireNonNull(builder); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
98 changes: 98 additions & 0 deletions
98
common/src/main/java/es/urjc/etsii/grafo/testutil/TestMoveWithMultipleObjectives.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
package es.urjc.etsii.grafo.testutil; | ||
|
||
import es.urjc.etsii.grafo.algorithms.FMode; | ||
import es.urjc.etsii.grafo.solution.Move; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Arrays; | ||
import java.util.List; | ||
import java.util.Objects; | ||
|
||
public class TestMoveWithMultipleObjectives extends Move<TestSolutionWithMultipleObjectives, TestInstance> { | ||
private final double[] score; | ||
private final FMode[] fmode; | ||
|
||
public static List<TestMoveWithMultipleObjectives> generateSeq(double[]... data){ | ||
return generateSeq("TestInstance", data); | ||
} | ||
|
||
public static List<TestMoveWithMultipleObjectives> generateSeq(String instanceName, double[]... data){ | ||
var testInstance = new TestInstance(instanceName); | ||
var testSolution = new TestSolutionWithMultipleObjectives(testInstance); | ||
var moves = new ArrayList<TestMoveWithMultipleObjectives>(); | ||
for(var i: data){ | ||
moves.add(new TestMoveWithMultipleObjectives(testSolution, i)); | ||
} | ||
return moves; | ||
} | ||
|
||
public TestMoveWithMultipleObjectives(TestSolutionWithMultipleObjectives solution, double[] score, FMode[] fmode) { | ||
super(solution); | ||
this.score = score; | ||
this.fmode = fmode; | ||
} | ||
|
||
public TestMoveWithMultipleObjectives(TestSolutionWithMultipleObjectives solution, double[] v) { | ||
super(solution); | ||
this.score = v; | ||
this.fmode = new FMode[v.length]; | ||
for (int i = 0; i < v.length; i++) { | ||
fmode[i] = FMode.MINIMIZE; | ||
} | ||
} | ||
|
||
@Override | ||
protected TestSolutionWithMultipleObjectives _execute(TestSolutionWithMultipleObjectives solution) { | ||
int i = 0; | ||
for (double v : score) { | ||
solution.scores[i] += this.score[i]; | ||
i++; | ||
} | ||
return solution; | ||
} | ||
|
||
public double[] getScoreChanges() { | ||
return score; | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return "TestMove{" + | ||
"score=" + score + | ||
", maximizing=" + fmode + | ||
'}'; | ||
} | ||
|
||
@Override | ||
public boolean equals(Object o) { | ||
if (this == o) return true; | ||
if (o == null || getClass() != o.getClass()) return false; | ||
TestMoveWithMultipleObjectives testMove = (TestMoveWithMultipleObjectives) o; | ||
if (this.score.length != testMove.score.length) { | ||
return false; | ||
} | ||
for (int i = 0; i < this.score.length; i++) { | ||
if (Double.compare(testMove.score[i], score[i]) != 0 && fmode[i] != testMove.fmode[i]){ | ||
return false; | ||
} | ||
} | ||
return true; | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
return Objects.hash(Arrays.hashCode(score), Arrays.hashCode(fmode)); | ||
} | ||
|
||
public boolean isMaximizing(int i) { | ||
return fmode.length > i && fmode[i] == FMode.MAXIMIZE; | ||
} | ||
|
||
public boolean isMinimizing(int i) { | ||
return fmode.length > i && fmode[i] == FMode.MINIMIZE; | ||
} | ||
|
||
public FMode[] getFmode() { | ||
return fmode; | ||
} | ||
} |
109 changes: 109 additions & 0 deletions
109
common/src/main/java/es/urjc/etsii/grafo/testutil/TestSolutionWithMultipleObjectives.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
package es.urjc.etsii.grafo.testutil; | ||
|
||
import es.urjc.etsii.grafo.solution.Solution; | ||
|
||
import java.util.Arrays; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
import java.util.Objects; | ||
import java.util.function.Function; | ||
|
||
public class TestSolutionWithMultipleObjectives extends Solution<TestSolutionWithMultipleObjectives, TestInstance>{ | ||
|
||
protected double[] scores; | ||
|
||
public static TestSolutionWithMultipleObjectives[] from(double... scores) { | ||
return from(new TestInstance("TestInstance"), scores); | ||
} | ||
|
||
public static TestSolutionWithMultipleObjectives[] from(TestInstance instance, double... scores) { | ||
var solutions = new TestSolutionWithMultipleObjectives[scores.length]; | ||
for (int i = 0; i < scores.length; i++) { | ||
solutions[i] = new TestSolutionWithMultipleObjectives(instance, scores); | ||
} | ||
return solutions; | ||
} | ||
|
||
Map<String, Function<TestSolutionWithMultipleObjectives, Object>> properties = new HashMap<>(); | ||
|
||
|
||
public TestSolutionWithMultipleObjectives(TestInstance ins) { | ||
super(ins); | ||
} | ||
|
||
public TestSolutionWithMultipleObjectives(TestInstance ins, double[] scores) { | ||
this(ins); | ||
this.scores = scores; | ||
} | ||
|
||
public TestSolutionWithMultipleObjectives(TestInstance ins, double[] scores, Map<String, Function<TestSolutionWithMultipleObjectives, Object>> properties) { | ||
this(ins); | ||
this.scores = scores; | ||
this.properties = properties; | ||
} | ||
|
||
public TestSolutionWithMultipleObjectives(TestSolutionWithMultipleObjectives sol) { | ||
super(sol); | ||
this.scores = sol.scores; | ||
} | ||
|
||
@Override | ||
public TestSolutionWithMultipleObjectives cloneSolution() { | ||
return new TestSolutionWithMultipleObjectives(this); | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return "TestSolutionWithMultipleObjectives{" + | ||
"score=" + scores.toString() + | ||
'}'; | ||
} | ||
|
||
public void setTTB(long ttb) { | ||
this.lastModifiedTime = ttb; | ||
} | ||
|
||
public void resetTTB() { | ||
this.lastModifiedTime = Integer.MIN_VALUE; | ||
} | ||
|
||
|
||
@Override | ||
public Map<String, Function<TestSolutionWithMultipleObjectives, Object>> customProperties() { | ||
return this.properties; | ||
} | ||
|
||
@Override | ||
public boolean equals(Object o) { | ||
if (this == o) return true; | ||
if (o == null || getClass() != o.getClass()) return false; | ||
TestSolutionWithMultipleObjectives that = (TestSolutionWithMultipleObjectives) o; | ||
if (this.scores.length != that.scores.length) { | ||
return false; | ||
} | ||
for (int i = 0; i < this.scores.length; i++) { | ||
if (Double.compare(that.scores[i], scores[i]) != 0){ | ||
return false; | ||
} | ||
} | ||
return true; | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
return Arrays.hashCode(this.scores); | ||
} | ||
|
||
public void setScores(double[] scores){ | ||
this.scores = scores; | ||
} | ||
|
||
public double getObjective(int index){ | ||
return this.scores[index]; | ||
} | ||
|
||
public double[] getScores(){ | ||
return this.scores; | ||
} | ||
|
||
} |
Oops, something went wrong.