diff --git a/jastadd-mquat-benchmark/src/main/java/de/tudresden/inf/st/mquat/benchmark/SolverFactory.java b/jastadd-mquat-benchmark/src/main/java/de/tudresden/inf/st/mquat/benchmark/SolverFactory.java index 180b8aa4fc704d7f710dbf8e89ede1d795cc6a2a..7cf92ce3643eb11bf4faf2c2509d591310409b16 100644 --- a/jastadd-mquat-benchmark/src/main/java/de/tudresden/inf/st/mquat/benchmark/SolverFactory.java +++ b/jastadd-mquat-benchmark/src/main/java/de/tudresden/inf/st/mquat/benchmark/SolverFactory.java @@ -32,7 +32,8 @@ public class SolverFactory { new ILPDirectSolver(), new SimpleSolver(), new RandomSolver(0, 0), - new GeneticSolver() + new GeneticSolver(GeneticSolver.SelectorType.NSGA2, 200000, 1000), + new GeneticSolver(GeneticSolver.SelectorType.SPEA2, 200000, 1000) ).collect(Collectors.toMap(BenchmarkableSolver::getName, Function.identity())); } return availableSolvers; diff --git a/jastadd-mquat-benchmark/src/main/resources/scenarios.json b/jastadd-mquat-benchmark/src/main/resources/scenarios.json index 541fefc50479875f77b0482a120a4f7e4e56d69d..19e26b908bffd6468810adbe185f5990e7e2eb52 100644 --- a/jastadd-mquat-benchmark/src/main/resources/scenarios.json +++ b/jastadd-mquat-benchmark/src/main/resources/scenarios.json @@ -16,7 +16,6 @@ "sandBoxed": true, // "repetitions": 10, "scenarios": [ - // { "id": 0, "name": "size0", "variants": 1, "requests": 1, "depth": 1, "resources": 1 }, diff --git a/jastadd-mquat-solver-genetic/src/main/java/de/tudresden/inf/st/mquat/solving/genetic/GeneticSolver.java b/jastadd-mquat-solver-genetic/src/main/java/de/tudresden/inf/st/mquat/solving/genetic/GeneticSolver.java index 4f246498d468343d90f05bd2a3787df3a97ba143..d7bb89d48b292cefaef327e178d8432656cfc888 100644 --- a/jastadd-mquat-solver-genetic/src/main/java/de/tudresden/inf/st/mquat/solving/genetic/GeneticSolver.java +++ b/jastadd-mquat-solver-genetic/src/main/java/de/tudresden/inf/st/mquat/solving/genetic/GeneticSolver.java @@ -1,6 +1,5 @@ package de.tudresden.inf.st.mquat.solving.genetic; -import de.tudresden.inf.st.mquat.generator.ScenarioDescription; import de.tudresden.inf.st.mquat.jastadd.model.Root; import de.tudresden.inf.st.mquat.jastadd.model.Solution; import de.tudresden.inf.st.mquat.solving.BenchmarkableSolver; @@ -10,8 +9,7 @@ import de.tudresden.inf.st.mquat.solving.genetic.opt4j.Opt4jModule; import de.tudresden.inf.st.mquat.solving.genetic.opt4j.custom.operator.copy.TreeCopyOperatorModule; import de.tudresden.inf.st.mquat.solving.genetic.opt4j.custom.operator.crossover.TreeCrossoverOperatorModule; import de.tudresden.inf.st.mquat.solving.genetic.opt4j.custom.operator.mutate.TreeMutateOperatorModule; -import de.tudresden.inf.st.mquat.solving.genetic.opt4j.operators.diversity.TreeDiversityOperator; -import de.tudresden.inf.st.mquat.solving.genetic.opt4j.operators.diversity.TreeDiversityOperatorModule; +import de.tudresden.inf.st.mquat.solving.genetic.opt4j.custom.optimizer.TimeOutOptimizerModule; import de.tudresden.inf.st.mquat.utils.StopWatch; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -20,12 +18,12 @@ import org.opt4j.core.optimizer.Archive; import org.opt4j.core.start.Opt4JTask; import org.opt4j.optimizers.ea.EvolutionaryAlgorithmModule; import org.opt4j.optimizers.ea.Nsga2Module; -import org.opt4j.viewer.ViewerModule; +import org.opt4j.optimizers.ea.Spea2Module; -import java.util.ArrayList; -import java.util.List; import java.util.concurrent.TimeUnit; +//import org.opt4j.viewer.ViewerModule; + public class GeneticSolver implements BenchmarkableSolver { private static final Logger logger = LogManager.getLogger(GeneticSolver.class); @@ -38,25 +36,30 @@ public class GeneticSolver implements BenchmarkableSolver { private StopWatch stopWatch; private long maxSolvingTime; + private int generations; + private int populationSize; + private SelectorType selectorType; private boolean timedOut; public GeneticSolver() { - this(Long.MAX_VALUE); + this(SelectorType.NSGA2, 100, 100); } - public GeneticSolver(long maxSolvingTime) { - this.maxSolvingTime = maxSolvingTime; + public GeneticSolver(SelectorType evaluatorType, int generations, int populationSize) { + this.selectorType = evaluatorType; + this.generations = generations; + this.populationSize = populationSize; reset(); + } @Override public Solution solve(Root model) throws SolvingException { + reset(); stopWatch = StopWatch.start(); - List<Solution> solutions = new ArrayList<>(); - if (model.getNumRequest() == 0) { return Solution.emptySolutionOf(model); } @@ -65,39 +68,48 @@ public class GeneticSolver implements BenchmarkableSolver { Opt4jModule.setModel(model); EvolutionaryAlgorithmModule ea = new EvolutionaryAlgorithmModule(); - ea.setGenerations(20000); + ea.setGenerations(this.generations); // set population size - ea.setAlpha(100); + ea.setAlpha(this.populationSize); Opt4jModule mquatModule = new Opt4jModule(); + mquatModule.setMaxSolvingTime(this.maxSolvingTime); + TreeCrossoverOperatorModule crossover = new TreeCrossoverOperatorModule(); TreeMutateOperatorModule mutate = new TreeMutateOperatorModule(); TreeCopyOperatorModule copy = new TreeCopyOperatorModule(); + TimeOutOptimizerModule optimizerModule = new TimeOutOptimizerModule(); // ViewerModule viewer = new ViewerModule(); // viewer.setCloseOnStop(false); Opt4JTask task = new Opt4JTask(false); - task.init(ea, mquatModule, crossover, mutate, copy); -// task.init(diversity, ea, nsga2, mquatModule, viewer, crossover, mutate, copy); + switch (this.selectorType) { + case NSGA2: + Nsga2Module nsga2 = new Nsga2Module(); + task.init(optimizerModule, ea, nsga2, mquatModule, crossover, mutate, copy); +// task.init(optimizerModule, ea, nsga2, mquatModule, crossover, mutate, copy, viewer); + break; + case SPEA2: + Spea2Module spea2 = new Spea2Module(); + task.init(optimizerModule, ea, spea2, mquatModule, crossover, mutate, copy); +// task.init(optimizerModule, ea, spea2, mquatModule, crossover, mutate, copy, viewer); + } try { task.execute(); Archive archive = task.getInstance(Archive.class); for (Individual individual : archive) { // obtain the phenotype and objective, etc. of each individual Solution solution = (Solution) individual.getPhenotype(); - if (solution.isValid()) { - if (solutions.isEmpty() || solution.computeObjective() < solutions.get(solutions.size() - 1).computeObjective()) { - Solution clone = solution.deepCopy(); - solutions.add(clone); - logger.info("found a better solution with an objective of {}.", solution.computeObjective()); - } - } else { - logger.warn("Found an invalid solution with " + solution.evaluateValidity() + " errors."); + int validity = solution.evaluateValidity(); + double objective = solution.computeObjective(); + // TODO only works with minimized objective + if (lastSolution == null || validity < lastSolution.evaluateValidity() || (validity == lastSolution.evaluateValidity() && objective < lastSolution.computeObjective())) { + lastSolution = solution.deepCopy(); + logger.info("found a better solution with {} errors and an objective of {}.", validity, objective); } - } } catch (Exception e) { e.printStackTrace(); @@ -105,9 +117,7 @@ public class GeneticSolver implements BenchmarkableSolver { task.close(); } - if (solutions.size() > 0) { - lastSolution = solutions.get(solutions.size() - 1); - } else { + if (lastSolution == null) { lastSolution = Solution.emptySolutionOf(model); logger.warn("Found no solution!"); } @@ -126,7 +136,7 @@ public class GeneticSolver implements BenchmarkableSolver { @Override public String getName() { - return "genetic"; + return "genetic_" + this.selectorType.name(); } @Override @@ -154,4 +164,9 @@ public class GeneticSolver implements BenchmarkableSolver { public boolean hadTimeout() { return this.timedOut; } + + public enum SelectorType { + NSGA2, + SPEA2 + } } diff --git a/jastadd-mquat-solver-genetic/src/main/java/de/tudresden/inf/st/mquat/solving/genetic/opt4j/Opt4jModule.java b/jastadd-mquat-solver-genetic/src/main/java/de/tudresden/inf/st/mquat/solving/genetic/opt4j/Opt4jModule.java index 5fff25a053d85f763512784f4aa9719393e23ce1..6426e7fc712ab188d80843cdcbe337b22ed89746 100644 --- a/jastadd-mquat-solver-genetic/src/main/java/de/tudresden/inf/st/mquat/solving/genetic/opt4j/Opt4jModule.java +++ b/jastadd-mquat-solver-genetic/src/main/java/de/tudresden/inf/st/mquat/solving/genetic/opt4j/Opt4jModule.java @@ -1,10 +1,13 @@ package de.tudresden.inf.st.mquat.solving.genetic.opt4j; import de.tudresden.inf.st.mquat.jastadd.model.Root; +import de.tudresden.inf.st.mquat.solving.genetic.opt4j.custom.optimizer.MaxSolvingTime; import org.opt4j.core.problem.ProblemModule; public class Opt4jModule extends ProblemModule { + @MaxSolvingTime + public Long maxSolvingTime = Long.MAX_VALUE; private static Root model; public static Root getModel() { @@ -15,9 +18,14 @@ public class Opt4jModule extends ProblemModule { Opt4jModule.model = model; } + public void setMaxSolvingTime(long maxSolvingTime) { + this.maxSolvingTime = maxSolvingTime; + } + @Override protected void configure() { bindProblem(Opt4jCreator.class, Opt4jDecoder.class, Opt4jEvaluator.class); + bindConstant(MaxSolvingTime.class).to(maxSolvingTime); } @Override diff --git a/jastadd-mquat-solver-genetic/src/main/java/de/tudresden/inf/st/mquat/solving/genetic/opt4j/custom/operator/mutate/TreeMutateOperator.java b/jastadd-mquat-solver-genetic/src/main/java/de/tudresden/inf/st/mquat/solving/genetic/opt4j/custom/operator/mutate/TreeMutateOperator.java index ae0c46d1ca990e1cd60c6695e139f71530c00147..ca6a16ef048beea52f57359c76c345c8a993480c 100644 --- a/jastadd-mquat-solver-genetic/src/main/java/de/tudresden/inf/st/mquat/solving/genetic/opt4j/custom/operator/mutate/TreeMutateOperator.java +++ b/jastadd-mquat-solver-genetic/src/main/java/de/tudresden/inf/st/mquat/solving/genetic/opt4j/custom/operator/mutate/TreeMutateOperator.java @@ -78,7 +78,7 @@ public class TreeMutateOperator implements Mutate<TreeGenotype<Request, Instance for (ComponentRequirement cr : newImp.getComponentRequirementList()) { for (Instance ci : cr.getInstanceList()) { // create node - Assignment newAssignment = newImp.root().createRandomAssignment(false, request, cr.getComponentRef().getRef(), unassignedResources, new Random()); + Assignment newAssignment = newImp.root().createRandomAssignment(false, request, cr.getComponentRef().getRef(), unassignedResources, newImp, ci, new Random()); node.getSubStructure().put(ci, Opt4jCreator.createNode(newAssignment, node.getContainingGenotype())); } } diff --git a/jastadd-mquat-solver-genetic/src/main/java/de/tudresden/inf/st/mquat/solving/genetic/opt4j/custom/optimizer/MaxSolvingTime.java b/jastadd-mquat-solver-genetic/src/main/java/de/tudresden/inf/st/mquat/solving/genetic/opt4j/custom/optimizer/MaxSolvingTime.java new file mode 100644 index 0000000000000000000000000000000000000000..4b4ec40f39435b90da5262053fe8dede3191d896 --- /dev/null +++ b/jastadd-mquat-solver-genetic/src/main/java/de/tudresden/inf/st/mquat/solving/genetic/opt4j/custom/optimizer/MaxSolvingTime.java @@ -0,0 +1,20 @@ +package de.tudresden.inf.st.mquat.solving.genetic.opt4j.custom.optimizer; + +import com.google.inject.BindingAnnotation; +import org.opt4j.core.optimizer.Optimizer; + +import java.lang.annotation.Retention; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * The {@link MaxSolvingTime} is the default binding annotation for the maximum + * solving time for an {@link Optimizer}. + * + * @author johannes.mey + */ +@Retention(RUNTIME) +@BindingAnnotation +public @interface MaxSolvingTime { + +} diff --git a/jastadd-mquat-solver-genetic/src/main/java/de/tudresden/inf/st/mquat/solving/genetic/opt4j/custom/optimizer/TimeOutIteration.java b/jastadd-mquat-solver-genetic/src/main/java/de/tudresden/inf/st/mquat/solving/genetic/opt4j/custom/optimizer/TimeOutIteration.java new file mode 100644 index 0000000000000000000000000000000000000000..d13b17c51617ec11abdfbdbbe31884ecb63d0686 --- /dev/null +++ b/jastadd-mquat-solver-genetic/src/main/java/de/tudresden/inf/st/mquat/solving/genetic/opt4j/custom/optimizer/TimeOutIteration.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2014 Opt4J + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *******************************************************************************/ + +package de.tudresden.inf.st.mquat.solving.genetic.opt4j.custom.optimizer; + +import com.google.inject.Inject; +import com.google.inject.Singleton; +import org.opt4j.core.optimizer.Iteration; +import org.opt4j.core.optimizer.MaxIterations; + +/** + * The {@link Iteration} object is used as iteration counter for the + * optimization. + * + * @author lukasiewycz + * + */ +@Singleton +public class TimeOutIteration extends Iteration { + + protected final Long maxSolvingTime; + + /** + * Constructs a {@link Iteration} object. + * + * @param maxIterations + * the maximal number of iterations + */ + @Inject + public TimeOutIteration(@MaxIterations int maxIterations, @MaxSolvingTime Long maxSolvingTime) { + super(maxIterations); + this.maxSolvingTime = maxSolvingTime; + } + + /** + * Returns the maximal number of iterations. + * + * @return the maximal number of iterations + */ + public long maxTime() { + return maxSolvingTime; + } + +} diff --git a/jastadd-mquat-solver-genetic/src/main/java/de/tudresden/inf/st/mquat/solving/genetic/opt4j/custom/optimizer/TimeOutOptimizer.java b/jastadd-mquat-solver-genetic/src/main/java/de/tudresden/inf/st/mquat/solving/genetic/opt4j/custom/optimizer/TimeOutOptimizer.java new file mode 100644 index 0000000000000000000000000000000000000000..8ef0a66b20df2e02942691bd9db97a48eb4bb4c0 --- /dev/null +++ b/jastadd-mquat-solver-genetic/src/main/java/de/tudresden/inf/st/mquat/solving/genetic/opt4j/custom/optimizer/TimeOutOptimizer.java @@ -0,0 +1,65 @@ +package de.tudresden.inf.st.mquat.solving.genetic.opt4j.custom.optimizer; + +import com.google.inject.Inject; +import com.google.inject.Singleton; +import de.tudresden.inf.st.mquat.solving.genetic.GeneticSolver; +import de.tudresden.inf.st.mquat.utils.StopWatch; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.opt4j.core.optimizer.*; + +import java.util.concurrent.TimeUnit; + +/** + * The {@link org.opt4j.core.optimizer.OptimizationMediator} performs the overall optimization process + * for the {@link IterativeOptimizer}. + * + * @author reimann, glass, lukasiewycz + * + */ +@Singleton +public class TimeOutOptimizer extends AbstractOptimizer { + + private static final Logger logger = LogManager.getLogger(TimeOutOptimizer.class); + + protected final IterativeOptimizer iterativeOptimizer; + + /** + * Creates a new {@link org.opt4j.core.optimizer.OptimizationMediator}. + * + * @param iterativeOptimizer + * the iterative optimizer to use + * @param population + * the specified population + * @param archive + * the specified archive + * @param completer + * the specified completer + * @param control + * the control + * @param iteration + * the iteration counter + */ + @Inject + public TimeOutOptimizer(IterativeOptimizer iterativeOptimizer, Population population, Archive archive, + IndividualCompleter completer, Control control, TimeOutIteration iteration) { + super(population, archive, completer, control, iteration); + this.iterativeOptimizer = iterativeOptimizer; + } + + /* + * (non-Javadoc) + * + * @see org.opt4j.core.optimizer.Optimizer#optimize() + */ + @Override + public void optimize() throws StopException, TerminationException { + iterativeOptimizer.initialize(); + StopWatch watch = StopWatch.start(); + while (iteration.value() < iteration.max() && watch.time(TimeUnit.MILLISECONDS) < ((TimeOutIteration)iteration).maxTime()) { + iterativeOptimizer.next(); + nextIteration(); + } + logger.info("Stopped after {} iterations.", iteration.value()); + } +} diff --git a/jastadd-mquat-solver-genetic/src/main/java/de/tudresden/inf/st/mquat/solving/genetic/opt4j/custom/optimizer/TimeOutOptimizerModule.java b/jastadd-mquat-solver-genetic/src/main/java/de/tudresden/inf/st/mquat/solving/genetic/opt4j/custom/optimizer/TimeOutOptimizerModule.java new file mode 100644 index 0000000000000000000000000000000000000000..33fedb009a66cf800f3863f86e5501bd058c576c --- /dev/null +++ b/jastadd-mquat-solver-genetic/src/main/java/de/tudresden/inf/st/mquat/solving/genetic/opt4j/custom/optimizer/TimeOutOptimizerModule.java @@ -0,0 +1,11 @@ +package de.tudresden.inf.st.mquat.solving.genetic.opt4j.custom.optimizer; + +import org.opt4j.core.optimizer.OptimizerModule; + +public class TimeOutOptimizerModule extends OptimizerModule { + + @Override + protected void config() { + bindOptimizer(TimeOutOptimizer.class); + } +} diff --git a/jastadd-mquat-solver-genetic/src/test/java/de/tudresden/inf/st/mquat/solving/GeneticHandwrittenTest.java b/jastadd-mquat-solver-genetic/src/test/java/de/tudresden/inf/st/mquat/solving/GeneticHandwrittenTest.java index 22271aba9ac871c67ed47e818e0fb5d262adb37e..146ff18e2158235dd86b32e95f49899fe955a7fc 100644 --- a/jastadd-mquat-solver-genetic/src/test/java/de/tudresden/inf/st/mquat/solving/GeneticHandwrittenTest.java +++ b/jastadd-mquat-solver-genetic/src/test/java/de/tudresden/inf/st/mquat/solving/GeneticHandwrittenTest.java @@ -6,6 +6,6 @@ public class GeneticHandwrittenTest extends HandwrittenTestSuite { @Override protected Solver getSolver() { - return new GeneticSolver(10000); + return new GeneticSolver(GeneticSolver.SelectorType.NSGA2, 10000, 1000); } } diff --git a/jastadd-mquat-solver-genetic/src/test/java/de/tudresden/inf/st/mquat/solving/GeneticSolverTest.java b/jastadd-mquat-solver-genetic/src/test/java/de/tudresden/inf/st/mquat/solving/GeneticSolverTest.java index 9cc7a2615c1033e47ab942167f71a08a236d021f..4d61e3a271fe54980c764625aa1e1fd5e05f74c0 100644 --- a/jastadd-mquat-solver-genetic/src/test/java/de/tudresden/inf/st/mquat/solving/GeneticSolverTest.java +++ b/jastadd-mquat-solver-genetic/src/test/java/de/tudresden/inf/st/mquat/solving/GeneticSolverTest.java @@ -42,7 +42,7 @@ public class GeneticSolverTest { ScenarioGenerator generator = new ScenarioGenerator(new ScenarioDescription(tlc, iac, isd, cac, csd, dep, imp, res, req, cpu, seed)); Root model = generator.generate(); - GeneticSolver solver = new GeneticSolver(20000); + GeneticSolver solver = new GeneticSolver(GeneticSolver.SelectorType.NSGA2, 20000, 1000); Solution solution = solver.solve(model); diff --git a/jastadd-mquat-solver/src/test/java/de/tudresden/inf/st/mquat/solving/HandwrittenTestSuite.java b/jastadd-mquat-solver/src/test/java/de/tudresden/inf/st/mquat/solving/HandwrittenTestSuite.java index 9e5e59d4c1da16c955ec53995ae0298e39dfb85c..620b212443d1247de1081cb349e988d910b26831 100644 --- a/jastadd-mquat-solver/src/test/java/de/tudresden/inf/st/mquat/solving/HandwrittenTestSuite.java +++ b/jastadd-mquat-solver/src/test/java/de/tudresden/inf/st/mquat/solving/HandwrittenTestSuite.java @@ -12,6 +12,7 @@ import org.junit.rules.ErrorCollector; import java.io.IOException; import java.util.Iterator; +import java.util.concurrent.TimeUnit; import static org.hamcrest.core.IsEqual.equalTo; import static org.junit.Assert.assertEquals; @@ -31,6 +32,7 @@ public abstract class HandwrittenTestSuite { @Before public void setupSolverForTest() { this.solver = getSolver(); + solver.setTimeout(30, TimeUnit.SECONDS); } /**