Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added unit tests for ParetoSet implementations #270

Merged
merged 7 commits into from
Nov 21, 2024
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>
* &#64;Override
* public void setBuilder(SolutionBuilder&#60;S, I&#62; 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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ public class TestMove extends Move<TestSolution, TestInstance> {
private final double score;
private final FMode fmode;

public static List<TestMove> generateSeq(int... data){
public static List<TestMove> generateSeq(double... data){
return generateSeq("TestInstance", data);
}

public static List<TestMove> generateSeq(String instanceName, int... data){
public static List<TestMove> generateSeq(String instanceName, double... data){
var testInstance = new TestInstance(instanceName);
var testSolution = new TestSolution(testInstance);
var moves = new ArrayList<TestMove>();
Expand Down
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;
}
}
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;
}

}
Loading
Loading