diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/ruin/AbstractRuinStrategy.java b/jsprit-core/src/main/java/jsprit/core/algorithm/ruin/AbstractRuinStrategy.java index 5bee0ad6..8f7401bb 100644 --- a/jsprit-core/src/main/java/jsprit/core/algorithm/ruin/AbstractRuinStrategy.java +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/ruin/AbstractRuinStrategy.java @@ -20,6 +20,7 @@ package jsprit.core.algorithm.ruin; import jsprit.core.algorithm.ruin.listener.RuinListener; import jsprit.core.algorithm.ruin.listener.RuinListeners; +import jsprit.core.problem.VehicleRoutingProblem; import jsprit.core.problem.job.Job; import jsprit.core.problem.solution.route.VehicleRoute; import jsprit.core.util.RandomNumberGeneration; @@ -33,14 +34,12 @@ public abstract class AbstractRuinStrategy implements RuinStrategy{ protected Random random = RandomNumberGeneration.getRandom(); + protected VehicleRoutingProblem vrp; + public void setRandom(Random random) { this.random = random; } - protected AbstractRuinStrategy() { - ruinListeners = new RuinListeners(); - } - protected RuinShareFactory ruinShareFactory; public void setRuinShareFactory(RuinShareFactory ruinShareFactory){ @@ -51,6 +50,11 @@ public abstract class AbstractRuinStrategy implements RuinStrategy{ return ruinShareFactory; } + protected AbstractRuinStrategy(VehicleRoutingProblem vrp) { + this.vrp = vrp; + ruinListeners = new RuinListeners(); + } + @Override public Collection ruin(Collection vehicleRoutes){ ruinListeners.ruinStarts(vehicleRoutes); @@ -90,6 +94,7 @@ public abstract class AbstractRuinStrategy implements RuinStrategy{ } protected boolean removeJob(Job job, Collection vehicleRoutes) { + if(jobIsInitial(job)) return false; for (VehicleRoute route : vehicleRoutes) { if (removeJob(job, route)) { return true; @@ -98,7 +103,12 @@ public abstract class AbstractRuinStrategy implements RuinStrategy{ return false; } + private boolean jobIsInitial(Job job){ + return !vrp.getJobs().containsKey(job.getId()); //for initial jobs (being not contained in problem + } + protected boolean removeJob(Job job, VehicleRoute route) { + if(jobIsInitial(job)) return false; boolean removed = route.getTourActivities().removeJob(job); if (removed) { ruinListeners.removed(job,route); diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/ruin/RuinClusters.java b/jsprit-core/src/main/java/jsprit/core/algorithm/ruin/RuinClusters.java index 0492d1f7..99f392e1 100644 --- a/jsprit-core/src/main/java/jsprit/core/algorithm/ruin/RuinClusters.java +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/ruin/RuinClusters.java @@ -79,7 +79,7 @@ public final class RuinClusters extends AbstractRuinStrategy implements Iteratio private double epsFactor = 0.8; public RuinClusters(VehicleRoutingProblem vrp, final int initialNumberJobsToRemove, JobNeighborhoods jobNeighborhoods) { - super(); + super(vrp); this.vrp = vrp; setRuinShareFactory(new RuinShareFactory() { @Override @@ -156,9 +156,10 @@ public final class RuinClusters extends AbstractRuinStrategy implements Iteratio List cluster = dbscan.getRandomCluster(targetRoute); for(Job j : cluster){ if(toRemove == 0) break; - removeJob(j, vehicleRoutes); - lastRemoved.add(j); - unassignedJobs.add(j); + if(removeJob(j, vehicleRoutes)) { + lastRemoved.add(j); + unassignedJobs.add(j); + } toRemove--; } ruined.add(targetRoute); diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/ruin/RuinRadial.java b/jsprit-core/src/main/java/jsprit/core/algorithm/ruin/RuinRadial.java index 129801bf..2a4277f9 100644 --- a/jsprit-core/src/main/java/jsprit/core/algorithm/ruin/RuinRadial.java +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/ruin/RuinRadial.java @@ -54,7 +54,7 @@ public final class RuinRadial extends AbstractRuinStrategy { * @param jobDistance i.e. a measure to define the distance between two jobs and whether they are located close or distant to eachother */ public RuinRadial(VehicleRoutingProblem vrp, double fraction2beRemoved, JobDistance jobDistance) { - super(); + super(vrp); this.vrp = vrp; noJobsToMemorize = (int) Math.ceil(vrp.getJobs().values().size()*fraction2beRemoved); ruinShareFactory = new RuinShareFactory() { @@ -72,7 +72,7 @@ public final class RuinRadial extends AbstractRuinStrategy { } public RuinRadial(VehicleRoutingProblem vrp, int noJobs2beRemoved, JobDistance jobDistance) { - super(); + super(vrp); this.vrp = vrp; // this.fractionOfAllNodes2beRuined = fraction2beRemoved; noJobsToMemorize = noJobs2beRemoved; @@ -91,7 +91,7 @@ public final class RuinRadial extends AbstractRuinStrategy { } public RuinRadial(VehicleRoutingProblem vrp, int noJobs2beRemoved, JobNeighborhoods neighborhoods) { - super(); + super(vrp); this.vrp = vrp; noJobsToMemorize = noJobs2beRemoved; ruinShareFactory = new RuinShareFactory() { @@ -141,8 +141,9 @@ public final class RuinRadial extends AbstractRuinStrategy { Iterator neighborhoodIterator = jobNeighborhoods.getNearestNeighborsIterator(nNeighbors, targetJob); while(neighborhoodIterator.hasNext()){ Job job = neighborhoodIterator.next(); - removeJob(job,vehicleRoutes); - unassignedJobs.add(job); + if(removeJob(job,vehicleRoutes)){ + unassignedJobs.add(job); + } } return unassignedJobs; } diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/ruin/RuinRadialMultipleCenters.java b/jsprit-core/src/main/java/jsprit/core/algorithm/ruin/RuinRadialMultipleCenters.java index c4415c27..a9765b65 100644 --- a/jsprit-core/src/main/java/jsprit/core/algorithm/ruin/RuinRadialMultipleCenters.java +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/ruin/RuinRadialMultipleCenters.java @@ -48,7 +48,7 @@ public final class RuinRadialMultipleCenters extends AbstractRuinStrategy { private int noCenters = 1; public RuinRadialMultipleCenters(VehicleRoutingProblem vrp, int neighborhoodSize, JobDistance jobDistance) { - super(); + super(vrp); this.vrp = vrp; noJobsToMemorize = neighborhoodSize; ruinShareFactory = new RuinShareFactory() { @@ -116,8 +116,9 @@ public final class RuinRadialMultipleCenters extends AbstractRuinStrategy { while(neighborhoodIterator.hasNext()){ Job job = neighborhoodIterator.next(); if(available!=null) available.remove(job); - removeJob(job,vehicleRoutes); - unassignedJobs.add(job); + if(removeJob(job,vehicleRoutes)) { + unassignedJobs.add(job); + } } return unassignedJobs; } diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/ruin/RuinRandom.java b/jsprit-core/src/main/java/jsprit/core/algorithm/ruin/RuinRandom.java index 7e43ccd8..c084f356 100644 --- a/jsprit-core/src/main/java/jsprit/core/algorithm/ruin/RuinRandom.java +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/ruin/RuinRandom.java @@ -51,7 +51,7 @@ public final class RuinRandom extends AbstractRuinStrategy { * @param fraction which is the fraction of total c */ public RuinRandom(VehicleRoutingProblem vrp, double fraction) { - super(); + super(vrp); this.vrp = vrp; this.fractionOfAllNodes2beRuined = fraction; setRuinShareFactory(new RuinShareFactory() { @@ -96,9 +96,10 @@ public final class RuinRandom extends AbstractRuinStrategy { for (int i = 0; i < nOfJobs2BeRemoved; i++) { if(availableJobs.isEmpty()) break; Job job = pickRandomJob(availableJobs); - unassignedJobs.add(job); - availableJobs.remove(job); - removeJob(job,vehicleRoutes); + if(removeJob(job,vehicleRoutes)) { + unassignedJobs.add(job); + availableJobs.remove(job); + } } } diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/ruin/RuinWorst.java b/jsprit-core/src/main/java/jsprit/core/algorithm/ruin/RuinWorst.java index d32d55a5..f237bea4 100644 --- a/jsprit-core/src/main/java/jsprit/core/algorithm/ruin/RuinWorst.java +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/ruin/RuinWorst.java @@ -56,7 +56,7 @@ public final class RuinWorst extends AbstractRuinStrategy { } public RuinWorst(VehicleRoutingProblem vrp, final int initialNumberJobsToRemove) { - super(); + super(vrp); this.vrp = vrp; setRuinShareFactory(new RuinShareFactory() { @Override @@ -95,9 +95,10 @@ public final class RuinWorst extends AbstractRuinStrategy { while(toRemove > 0){ Job worst = getWorst(vehicleRoutes); if(worst == null) break; - removeJob(worst,vehicleRoutes); - availableJobs.remove(worst); - unassignedJobs.add(worst); + if(removeJob(worst,vehicleRoutes)) { + availableJobs.remove(worst); + unassignedJobs.add(worst); + } toRemove--; } } diff --git a/jsprit-core/src/test/java/jsprit/core/algorithm/InitialRoutesTest.java b/jsprit-core/src/test/java/jsprit/core/algorithm/InitialRoutesTest.java index 1dfb8609..8599dec7 100644 --- a/jsprit-core/src/test/java/jsprit/core/algorithm/InitialRoutesTest.java +++ b/jsprit-core/src/test/java/jsprit/core/algorithm/InitialRoutesTest.java @@ -19,6 +19,7 @@ package jsprit.core.algorithm; import jsprit.core.algorithm.box.GreedySchrimpfFactory; +import jsprit.core.algorithm.box.Jsprit; import jsprit.core.algorithm.box.SchrimpfFactory; import jsprit.core.problem.AbstractActivity; import jsprit.core.problem.Location; @@ -209,11 +210,40 @@ public class InitialRoutesTest { Collection solutions = vra.searchSolutions(); VehicleRoutingProblemSolution solution = Solutions.bestOf(solutions); - assertTrue(hasActivityIn(solution.getRoutes().iterator().next(),"1")); + SolutionPrinter.print(vrp,solution, SolutionPrinter.Print.VERBOSE); + + Job job = getInitialJob("1",vrp); + assertTrue(hasActivityIn(solution,"veh1", job)); + } + + private Job getInitialJob(String jobId, VehicleRoutingProblem vrp) { + for(VehicleRoute r : vrp.getInitialVehicleRoutes()){ + for(Job j : r.getTourActivities().getJobs()){ + if(j.getId().equals(jobId)) return j; + } + } + return null; } @Test - public void whenSolvingProblem2_deliverServices_and_allShipmentActs_shouldBeInRoute(){ + public void whenSolvingWithJsprit_deliverService1_shouldBeInRoute(){ + + VehicleRoutingProblem.Builder vrpBuilder = VehicleRoutingProblem.Builder.newInstance(); + new VrpXMLReader(vrpBuilder).read("src/test/resources/simpleProblem_iniRoutes_3.xml"); + VehicleRoutingProblem vrp = vrpBuilder.build(); + + VehicleRoutingAlgorithm vra = Jsprit.createAlgorithm(vrp); + Collection solutions = vra.searchSolutions(); + VehicleRoutingProblemSolution solution = Solutions.bestOf(solutions); + + SolutionPrinter.print(vrp,solution, SolutionPrinter.Print.VERBOSE); + + Job job = getInitialJob("1",vrp); + assertTrue(hasActivityIn(solution,"veh1", job)); + } + + @Test + public void whenSolvingProblem2With_deliverServices_and_allShipmentActs_shouldBeInRoute(){ VehicleRoutingProblem.Builder vrpBuilder = VehicleRoutingProblem.Builder.newInstance(); new VrpXMLReader(vrpBuilder).read("src/test/resources/simpleProblem_inclShipments_iniRoutes.xml"); @@ -227,6 +257,29 @@ public class InitialRoutesTest { assertTrue(hasActivityIn(solution.getRoutes(),"2")); assertTrue(hasActivityIn(solution.getRoutes(),"3")); assertTrue(hasActivityIn(solution.getRoutes(),"4")); + + assertTrue(hasActivityIn(solution,"veh1", getInitialJob("1",vrp))); + assertTrue(hasActivityIn(solution,"veh2", getInitialJob("3",vrp))); + } + + @Test + public void whenSolvingProblem2WithJsprit_deliverServices_and_allShipmentActs_shouldBeInRoute(){ + + VehicleRoutingProblem.Builder vrpBuilder = VehicleRoutingProblem.Builder.newInstance(); + new VrpXMLReader(vrpBuilder).read("src/test/resources/simpleProblem_inclShipments_iniRoutes.xml"); + VehicleRoutingProblem vrp = vrpBuilder.build(); + + VehicleRoutingAlgorithm vra = Jsprit.createAlgorithm(vrp); + Collection solutions = vra.searchSolutions(); + VehicleRoutingProblemSolution solution = Solutions.bestOf(solutions); + + assertTrue(hasActivityIn(solution.getRoutes(),"1")); + assertTrue(hasActivityIn(solution.getRoutes(),"2")); + assertTrue(hasActivityIn(solution.getRoutes(),"3")); + assertTrue(hasActivityIn(solution.getRoutes(),"4")); + + assertTrue(hasActivityIn(solution,"veh1", getInitialJob("1",vrp))); + assertTrue(hasActivityIn(solution,"veh2", getInitialJob("3",vrp))); } private boolean hasActivityIn(Collection routes, String jobId) { @@ -241,6 +294,19 @@ public class InitialRoutesTest { return isInRoute; } + private boolean hasActivityIn(VehicleRoutingProblemSolution solution, String vehicleId, Job job) { + for(VehicleRoute route : solution.getRoutes()){ + String vehicleId_ = route.getVehicle().getId(); + if(vehicleId_.equals(vehicleId)){ + if(route.getTourActivities().servesJob(job)){ + return true; + } + } + } + return false; + } + + private boolean hasActivityIn(VehicleRoute route, String jobId){ boolean isInRoute = false; for(TourActivity act : route.getActivities()){ diff --git a/jsprit-core/src/test/resources/simpleProblem_iniRoutes_3.xml b/jsprit-core/src/test/resources/simpleProblem_iniRoutes_3.xml new file mode 100644 index 00000000..3489c4e1 --- /dev/null +++ b/jsprit-core/src/test/resources/simpleProblem_iniRoutes_3.xml @@ -0,0 +1,79 @@ + + + + FINITE + HOMOGENEOUS + + + + veh1 + type1 + + [x=5000.0][y=5000.0] + + + + 0.0 + 46800.0 + + true + + + veh2 + type1 + + [x=0.0][y=0.0] + + + + 0.0 + 64800.0 + + true + + + + + type1 + + 0 + + + 0.0 + 1.0 + + + + + + + loc_s2 + + + 0 + + 0.0 + + + loc_s3 + + + 0 + + 0.0 + + + + + noDriver + veh1 + 0. + + 1 + + + + + + diff --git a/jsprit-examples/input/algorithmConfig_noVehicleSwitch.xml b/jsprit-examples/input/algorithmConfig_noVehicleSwitch.xml index 52a06df5..e58e5a6e 100755 --- a/jsprit-examples/input/algorithmConfig_noVehicleSwitch.xml +++ b/jsprit-examples/input/algorithmConfig_noVehicleSwitch.xml @@ -14,7 +14,7 @@ 1 - + @@ -30,7 +30,7 @@ 0.2 - + @@ -46,7 +46,7 @@ 0.2 - + diff --git a/jsprit-examples/src/main/java/jsprit/examples/MultipleDepotWithInitialRoutesExample.java b/jsprit-examples/src/main/java/jsprit/examples/MultipleDepotWithInitialRoutesExample.java index 68e932ad..05b6acbe 100644 --- a/jsprit-examples/src/main/java/jsprit/examples/MultipleDepotWithInitialRoutesExample.java +++ b/jsprit-examples/src/main/java/jsprit/examples/MultipleDepotWithInitialRoutesExample.java @@ -76,6 +76,9 @@ public class MultipleDepotWithInitialRoutesExample { /* * solve the problem */ +// VehicleRoutingAlgorithm vra = Jsprit.Builder.newInstance(vrp) +// .setProperty(Jsprit.Parameter.ITERATIONS,"10000").buildAlgorithm(); + VehicleRoutingAlgorithm vra = VehicleRoutingAlgorithms.readAndCreateAlgorithm(vrp, "input/algorithmConfig_noVehicleSwitch.xml"); Collection solutions = vra.searchSolutions();