From 4d8b4a627382f6f666554cc92fe27549e6b484ae Mon Sep 17 00:00:00 2001 From: oblonski <4sschroeder@gmail.com> Date: Mon, 15 Sep 2014 08:26:12 +0200 Subject: [PATCH] add multiple termination criteria --- .../algorithm/VehicleRoutingAlgorithm.java | 18 +++--- .../io/VehicleRoutingAlgorithms.java | 60 +++++++++++++++---- .../VehicleRoutingAlgorithmTest.java | 39 ++++++++++++ .../algorithm/io/TestAlgorithmReader.java | 2 +- .../algorithmConfigForReaderTest.xml | 3 + 5 files changed, 100 insertions(+), 22 deletions(-) diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/VehicleRoutingAlgorithm.java b/jsprit-core/src/main/java/jsprit/core/algorithm/VehicleRoutingAlgorithm.java index 97475eb6..41fcdeac 100644 --- a/jsprit-core/src/main/java/jsprit/core/algorithm/VehicleRoutingAlgorithm.java +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/VehicleRoutingAlgorithm.java @@ -97,15 +97,6 @@ public class VehicleRoutingAlgorithm { private int maxIterations = 100; - private PrematureAlgorithmTermination prematureAlgorithmTermination = new PrematureAlgorithmTermination() { - - @Override - public boolean isPrematureBreak(DiscoveredSolution discoveredSolution) { - return false; - } - - }; - private TerminationManager terminationManager = new TerminationManager(); private VehicleRoutingProblemSolution bestEver = null; @@ -158,7 +149,8 @@ public class VehicleRoutingAlgorithm { } /** - * Sets premature termination. + * Sets premature termination and overrides existing termination criteria. If existing ones should not be + * overridden use .addTerminationCriterion(...). * * @param prematureAlgorithmTermination the termination criterion */ @@ -168,6 +160,12 @@ public class VehicleRoutingAlgorithm { // this.prematureAlgorithmTermination = prematureAlgorithmTermination; } + /** + * Adds a termination criterion to the collection of already specified termination criteria. If one + * of the termination criteria is fulfilled, the algorithm terminates prematurely. + * + * @param terminationCriterion the termination criterion + */ public void addTerminationCriterion(PrematureAlgorithmTermination terminationCriterion){ terminationManager.addTermination(terminationCriterion); } diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/io/VehicleRoutingAlgorithms.java b/jsprit-core/src/main/java/jsprit/core/algorithm/io/VehicleRoutingAlgorithms.java index 42705a3b..8827a82b 100644 --- a/jsprit-core/src/main/java/jsprit/core/algorithm/io/VehicleRoutingAlgorithms.java +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/io/VehicleRoutingAlgorithms.java @@ -18,7 +18,6 @@ package jsprit.core.algorithm.io; import jsprit.core.algorithm.*; -import jsprit.core.algorithm.SearchStrategy.DiscoveredSolution; import jsprit.core.algorithm.acceptor.*; import jsprit.core.algorithm.io.VehicleRoutingAlgorithms.TypedMap.*; import jsprit.core.algorithm.listener.AlgorithmEndsListener; @@ -606,8 +605,16 @@ public class VehicleRoutingAlgorithms { metaAlgorithm.getSearchStrategyManager().addSearchStrategyModuleListener(new VehicleSwitched(vehicleFleetManager)); //define prematureBreak - PrematureAlgorithmTermination prematureAlgoBreaker = getPrematureBreaker(config,algorithmListeners); - metaAlgorithm.setPrematureAlgorithmTermination(prematureAlgoBreaker); + PrematureAlgorithmTermination prematureAlgorithmTermination = getPrematureTermination(config, algorithmListeners); + if(prematureAlgorithmTermination != null) metaAlgorithm.setPrematureAlgorithmTermination(prematureAlgorithmTermination); + else{ + List terminationCriteria = config.configurationsAt("terminationCriteria.termination"); + for(HierarchicalConfiguration terminationConfig : terminationCriteria){ + PrematureAlgorithmTermination termination = getTerminationCriterion(terminationConfig, algorithmListeners); + if(termination != null) metaAlgorithm.addTerminationCriterion(termination); + } + } + //misc // algorithmListeners.add(new PrioritizedVRAListener(Priority.LOW, new SolutionVerifier())); @@ -634,17 +641,48 @@ public class VehicleRoutingAlgorithms { "makes sure your config file contains one of these options"); } - private static PrematureAlgorithmTermination getPrematureBreaker(XMLConfiguration config, Set algorithmListeners) { + private static PrematureAlgorithmTermination getTerminationCriterion(HierarchicalConfiguration config, Set algorithmListeners) { + String basedOn = config.getString("[@basedOn]"); + if(basedOn == null){ + log.info("set default prematureBreak, i.e. no premature break at all."); + return null; + } + if(basedOn.equals("iterations")){ + log.info("set prematureBreak based on iterations"); + String iter = config.getString("iterations"); + if(iter == null) throw new IllegalStateException("iterations is missing"); + int iterations = Integer.valueOf(iter); + return new IterationWithoutImprovementTermination(iterations); + } + if(basedOn.equals("time")){ + log.info("set prematureBreak based on time"); + String timeString = config.getString("time"); + if(timeString == null) throw new IllegalStateException("time is missing"); + double time = Double.valueOf(timeString); + TimeTermination timeBreaker = new TimeTermination(time); + algorithmListeners.add(new PrioritizedVRAListener(Priority.LOW, timeBreaker)); + return timeBreaker; + } + if(basedOn.equals("variationCoefficient")){ + log.info("set prematureBreak based on variation coefficient"); + String thresholdString = config.getString("threshold"); + String iterationsString = config.getString("iterations"); + if(thresholdString == null) throw new IllegalStateException("threshold is missing"); + if(iterationsString == null) throw new IllegalStateException("iterations is missing"); + double threshold = Double.valueOf(thresholdString); + int iterations = Integer.valueOf(iterationsString); + VariationCoefficientTermination variationCoefficientBreaker = new VariationCoefficientTermination(iterations, threshold); + algorithmListeners.add(new PrioritizedVRAListener(Priority.LOW, variationCoefficientBreaker)); + return variationCoefficientBreaker; + } + throw new IllegalStateException("prematureBreak basedOn " + basedOn + " is not defined"); + } + + private static PrematureAlgorithmTermination getPrematureTermination(XMLConfiguration config, Set algorithmListeners) { String basedOn = config.getString("prematureBreak[@basedOn]"); if(basedOn == null){ log.info("set default prematureBreak, i.e. no premature break at all."); - return new PrematureAlgorithmTermination() { - - @Override - public boolean isPrematureBreak(DiscoveredSolution discoveredSolution) { - return false; - } - }; + return null; } if(basedOn.equals("iterations")){ log.info("set prematureBreak based on iterations"); diff --git a/jsprit-core/src/test/java/jsprit/core/algorithm/VehicleRoutingAlgorithmTest.java b/jsprit-core/src/test/java/jsprit/core/algorithm/VehicleRoutingAlgorithmTest.java index d7c3c2f6..b8462332 100644 --- a/jsprit-core/src/test/java/jsprit/core/algorithm/VehicleRoutingAlgorithmTest.java +++ b/jsprit-core/src/test/java/jsprit/core/algorithm/VehicleRoutingAlgorithmTest.java @@ -143,4 +143,43 @@ public class VehicleRoutingAlgorithmTest { assertEquals(50,counter.getCountIterations()); } + @Test + public void whenAddingPrematureTwoTerminationCriteria_itIsExecutedCorrectly(){ + SearchStrategyManager stratManager = mock(SearchStrategyManager.class); + VehicleRoutingAlgorithm algorithm = new VehicleRoutingAlgorithm(mock(VehicleRoutingProblem.class),stratManager); + when(stratManager.getRandomStrategy()).thenReturn(mock(SearchStrategy.class)); + when(stratManager.getProbabilities()).thenReturn(Arrays.asList(1.0)); + algorithm.setMaxIterations(1000); + PrematureAlgorithmTermination termination = new PrematureAlgorithmTermination() { + + private int nuOfIterations = 1; + + @Override + public boolean isPrematureBreak(DiscoveredSolution discoveredSolution) { + if(nuOfIterations == 50) return true; + nuOfIterations++; + return false; + } + + }; + PrematureAlgorithmTermination termination2 = new PrematureAlgorithmTermination() { + + private int nuOfIterations = 1; + + @Override + public boolean isPrematureBreak(DiscoveredSolution discoveredSolution) { + if(nuOfIterations == 25) return true; + nuOfIterations++; + return false; + } + + }; + CountIterations counter = new CountIterations(); + algorithm.addListener(counter); + algorithm.addTerminationCriterion(termination); + algorithm.addTerminationCriterion(termination2); + algorithm.searchSolutions(); + assertEquals(25,counter.getCountIterations()); + } + } diff --git a/jsprit-core/src/test/java/jsprit/core/algorithm/io/TestAlgorithmReader.java b/jsprit-core/src/test/java/jsprit/core/algorithm/io/TestAlgorithmReader.java index bcd4d4d2..4a839675 100644 --- a/jsprit-core/src/test/java/jsprit/core/algorithm/io/TestAlgorithmReader.java +++ b/jsprit-core/src/test/java/jsprit/core/algorithm/io/TestAlgorithmReader.java @@ -99,7 +99,7 @@ public class TestAlgorithmReader { IterationCounter iCounter = new IterationCounter(); vra.addListener(iCounter); vra.searchSolutions(); - Assert.assertEquals(100,iCounter.iterations); + Assert.assertEquals(25,iCounter.iterations); } diff --git a/jsprit-core/src/test/resources/algorithmConfigForReaderTest.xml b/jsprit-core/src/test/resources/algorithmConfigForReaderTest.xml index 7129aa61..e30dc37c 100755 --- a/jsprit-core/src/test/resources/algorithmConfigForReaderTest.xml +++ b/jsprit-core/src/test/resources/algorithmConfigForReaderTest.xml @@ -25,6 +25,9 @@ 100 + + 25 +