From 82565b4416ad6cceb3f19fff80ccbe7cada4fef0 Mon Sep 17 00:00:00 2001 From: oblonski Date: Wed, 13 Jul 2016 13:51:43 +0200 Subject: [PATCH] add a way to use fast regret with custom contraints --- .../jsprit/core/algorithm/box/Jsprit.java | 2 + .../RegretInsertionConcurrentFast.java | 69 ++++-- .../recreate/RegretInsertionFast.java | 79 ++++--- .../problem/constraint/ConstraintManager.java | 24 ++ .../problem/constraint/DependencyType.java | 10 + .../recreate/RegretInsertionTest.java | 209 +++++++++++++++++- .../jsprit/core/problem/CapacityTest.java | 15 ++ 7 files changed, 359 insertions(+), 49 deletions(-) create mode 100644 jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/DependencyType.java diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java index 82594641..2f49d5c9 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java @@ -436,6 +436,7 @@ public class Jsprit { .build(); scorer = getRegretScorer(vrp); regretInsertion.setScoringFunction(scorer); + regretInsertion.setDependencyTypes(constraintManager.getDependencyTypes()); regret = regretInsertion; } else { @@ -461,6 +462,7 @@ public class Jsprit { .build(); scorer = getRegretScorer(vrp); regretInsertion.setScoringFunction(scorer); + regretInsertion.setDependencyTypes(constraintManager.getDependencyTypes()); regret = regretInsertion; } else{ diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertionConcurrentFast.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertionConcurrentFast.java index d246176e..5b575fa2 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertionConcurrentFast.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertionConcurrentFast.java @@ -18,6 +18,7 @@ package com.graphhopper.jsprit.core.algorithm.recreate; import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem; +import com.graphhopper.jsprit.core.problem.constraint.DependencyType; import com.graphhopper.jsprit.core.problem.job.Break; import com.graphhopper.jsprit.core.problem.job.Job; import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute; @@ -57,6 +58,8 @@ public class RegretInsertionConcurrentFast extends AbstractInsertionStrategy { private boolean switchAllowed = true; + private DependencyType[] dependencyTypes = null; + /** * Sets the scoring function. @@ -97,6 +100,10 @@ public class RegretInsertionConcurrentFast extends AbstractInsertionStrategy { return ids; } + public void setDependencyTypes(DependencyType[] dependencyTypes){ + this.dependencyTypes = dependencyTypes; + } + /** * Runs insertion. @@ -139,15 +146,8 @@ public class RegretInsertionConcurrentFast extends AbstractInsertionStrategy { List unassignedJobList = new ArrayList(jobs); List badJobList = new ArrayList(); if(!firstRun && lastModified == null) throw new IllegalStateException("ho. this must not be."); - if(firstRun){ - firstRun = false; - updateInsertionData(priorityQueues, routes, unassignedJobList, updateRound); - for(VehicleRoute r : routes) updates.put(r,updateRound); - } - else{ - updateInsertionData(priorityQueues, Arrays.asList(lastModified), unassignedJobList, updateRound); - updates.put(lastModified,updateRound); - } + updateInsertionData(priorityQueues, routes, unassignedJobList, updateRound,firstRun,lastModified,updates); + if(firstRun) firstRun = false; updateRound++; ScoredJob bestScoredJob = InsertionDataUpdater.getBest(switchAllowed,initialVehicleIds,fleetManager, insertionCostsCalculator, scoringFunction, priorityQueues, updates, unassignedJobList, badJobList); if (bestScoredJob != null) { @@ -167,19 +167,38 @@ public class RegretInsertionConcurrentFast extends AbstractInsertionStrategy { return badJobs; } - private void updateInsertionData(final TreeSet[] priorityQueues, final Collection routes, List unassignedJobList, final int updateRound) { + private void updateInsertionData(final TreeSet[] priorityQueues, final Collection routes, List unassignedJobList, final int updateRound, final boolean firstRun, final VehicleRoute lastModified, Map updates) { List> tasks = new ArrayList>(); + boolean updatedAllRoutes = false; for (final Job unassignedJob : unassignedJobList) { if(priorityQueues[unassignedJob.getIndex()] == null){ priorityQueues[unassignedJob.getIndex()] = new TreeSet(InsertionDataUpdater.getComparator()); } final TreeSet priorityQueue = priorityQueues[unassignedJob.getIndex()]; - tasks.add(new Callable() { - @Override - public Boolean call() throws Exception { - return InsertionDataUpdater.update(switchAllowed,initialVehicleIds,fleetManager, insertionCostsCalculator, priorityQueue, updateRound, unassignedJob, routes); + if(firstRun) { + makeCallables(tasks, true, priorityQueues[unassignedJob.getIndex()], updateRound, unassignedJob, routes, lastModified); + updatedAllRoutes = true; + } + else{ + if(dependencyTypes == null || dependencyTypes[unassignedJob.getIndex()] == null){ + makeCallables(tasks, false, priorityQueues[unassignedJob.getIndex()], updateRound, unassignedJob, routes, lastModified); } - }); + else { + DependencyType dependencyType = dependencyTypes[unassignedJob.getIndex()]; + if (dependencyType.equals(DependencyType.INTER_ROUTE) || dependencyType.equals(DependencyType.INTRA_ROUTE)) { + makeCallables(tasks, false, priorityQueues[unassignedJob.getIndex()], updateRound, unassignedJob, routes, lastModified); + updatedAllRoutes = true; + } else { + makeCallables(tasks, true, priorityQueues[unassignedJob.getIndex()], updateRound, unassignedJob, routes, lastModified); + } + } + } + } + if(updatedAllRoutes){ + for(VehicleRoute r : routes) updates.put(r,updateRound); + } + else{ + updates.put(lastModified,updateRound); } try { List> futures = executor.invokeAll(tasks); @@ -189,8 +208,24 @@ public class RegretInsertionConcurrentFast extends AbstractInsertionStrategy { } } - - + private void makeCallables(List> tasks, boolean updateAll, final TreeSet priorityQueue, final int updateRound, final Job unassignedJob, final Collection routes, final VehicleRoute lastModified) { + if(updateAll) { + tasks.add(new Callable() { + @Override + public Boolean call() throws Exception { + return InsertionDataUpdater.update(switchAllowed, initialVehicleIds, fleetManager, insertionCostsCalculator, priorityQueue, updateRound, unassignedJob, routes); + } + }); + } + else { + tasks.add(new Callable() { + @Override + public Boolean call() throws Exception { + return InsertionDataUpdater.update(switchAllowed, initialVehicleIds, fleetManager, insertionCostsCalculator, priorityQueue, updateRound, unassignedJob, Arrays.asList(lastModified)); + } + }); + } + } } diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertionFast.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertionFast.java index eacfbbe4..ce184be4 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertionFast.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertionFast.java @@ -18,7 +18,7 @@ package com.graphhopper.jsprit.core.algorithm.recreate; import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem; -import com.graphhopper.jsprit.core.problem.job.Break; +import com.graphhopper.jsprit.core.problem.constraint.DependencyType; import com.graphhopper.jsprit.core.problem.job.Job; import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute; import com.graphhopper.jsprit.core.problem.vehicle.VehicleFleetManager; @@ -51,7 +51,7 @@ public class RegretInsertionFast extends AbstractInsertionStrategy { private boolean switchAllowed = true; - + private DependencyType[] dependencyTypes = null; public RegretInsertionFast(JobInsertionCostsCalculator jobInsertionCalculator, VehicleRoutingProblem vehicleRoutingProblem, VehicleFleetManager fleetManager) { super(vehicleRoutingProblem); @@ -78,6 +78,10 @@ public class RegretInsertionFast extends AbstractInsertionStrategy { this.switchAllowed = switchAllowed; } + public void setDependencyTypes(DependencyType[] dependencyTypes){ + this.dependencyTypes = dependencyTypes; + } + private Set getInitialVehicleIds(VehicleRoutingProblem vehicleRoutingProblem) { Set ids = new HashSet(); for(VehicleRoute r : vehicleRoutingProblem.getInitialVehicleRoutes()){ @@ -101,25 +105,25 @@ public class RegretInsertionFast extends AbstractInsertionStrategy { public Collection insertUnassignedJobs(Collection routes, Collection unassignedJobs) { List badJobs = new ArrayList(unassignedJobs.size()); - Iterator jobIterator = unassignedJobs.iterator(); - while (jobIterator.hasNext()){ - Job job = jobIterator.next(); - if(job instanceof Break){ - VehicleRoute route = InsertionDataUpdater.findRoute(routes, job); - if(route == null){ - badJobs.add(job); - } - else { - InsertionData iData = insertionCostsCalculator.getInsertionData(route, job, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, Double.MAX_VALUE); - if (iData instanceof InsertionData.NoInsertionFound) { - badJobs.add(job); - } else { - insertJob(job, iData, route); - } - } - jobIterator.remove(); - } - } +// Iterator jobIterator = unassignedJobs.iterator(); +// while (jobIterator.hasNext()){ +// Job job = jobIterator.next(); +// if(job instanceof Break){ +// VehicleRoute route = InsertionDataUpdater.findRoute(routes, job); +// if(route == null){ +// badJobs.add(job); +// } +// else { +// InsertionData iData = insertionCostsCalculator.getInsertionData(route, job, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, Double.MAX_VALUE); +// if (iData instanceof InsertionData.NoInsertionFound) { +// badJobs.add(job); +// } else { +// insertJob(job, iData, route); +// } +// } +// jobIterator.remove(); +// } +// } List jobs = new ArrayList(unassignedJobs); TreeSet[] priorityQueues = new TreeSet[vrp.getJobs().values().size() + 2]; @@ -130,15 +134,15 @@ public class RegretInsertionFast extends AbstractInsertionStrategy { while (!jobs.isEmpty()) { List unassignedJobList = new ArrayList(jobs); List badJobList = new ArrayList(); - if(!firstRun && lastModified == null) throw new IllegalStateException("fooo"); + if(!firstRun && lastModified == null) throw new IllegalStateException("last modified route is null. this should not be."); if(firstRun){ + updateInsertionData(priorityQueues, routes, unassignedJobList, updateRound, firstRun, lastModified, updates); firstRun = false; - updateInsertionData(priorityQueues, routes, unassignedJobList, updateRound); - for(VehicleRoute r : routes) updates.put(r,updateRound); } else{ - updateInsertionData(priorityQueues, Arrays.asList(lastModified), unassignedJobList, updateRound); - updates.put(lastModified,updateRound); + //update for all routes || remove history and only update modified route + updateInsertionData(priorityQueues, routes, unassignedJobList, updateRound, firstRun, lastModified, updates); +// updates.put(lastModified,updateRound); } updateRound++; ScoredJob bestScoredJob = InsertionDataUpdater.getBest(switchAllowed,initialVehicleIds,fleetManager,insertionCostsCalculator,scoringFunction,priorityQueues,updates,unassignedJobList,badJobList); @@ -159,12 +163,31 @@ public class RegretInsertionFast extends AbstractInsertionStrategy { return badJobs; } - private void updateInsertionData(TreeSet[] priorityQueues, Collection routes, List unassignedJobList, int updateRound) { + private void updateInsertionData(TreeSet[] priorityQueues, Collection routes, List unassignedJobList, int updateRound, boolean firstRun, VehicleRoute lastModified, Map updates) { for (Job unassignedJob : unassignedJobList) { if(priorityQueues[unassignedJob.getIndex()] == null){ priorityQueues[unassignedJob.getIndex()] = new TreeSet(InsertionDataUpdater.getComparator()); } - InsertionDataUpdater.update(switchAllowed, initialVehicleIds,fleetManager,insertionCostsCalculator, priorityQueues[unassignedJob.getIndex()], updateRound, unassignedJob, routes); + if(firstRun) { + InsertionDataUpdater.update(switchAllowed, initialVehicleIds, fleetManager, insertionCostsCalculator, priorityQueues[unassignedJob.getIndex()], updateRound, unassignedJob, routes); + for(VehicleRoute r : routes) updates.put(r,updateRound); + } + else{ + if(dependencyTypes == null || dependencyTypes[unassignedJob.getIndex()] == null){ + InsertionDataUpdater.update(switchAllowed, initialVehicleIds, fleetManager, insertionCostsCalculator, priorityQueues[unassignedJob.getIndex()], updateRound, unassignedJob, Arrays.asList(lastModified)); + for(VehicleRoute r : routes) updates.put(r,updateRound); + } + else { + DependencyType dependencyType = dependencyTypes[unassignedJob.getIndex()]; + if (dependencyType.equals(DependencyType.INTER_ROUTE) || dependencyType.equals(DependencyType.INTRA_ROUTE)) { + InsertionDataUpdater.update(switchAllowed, initialVehicleIds, fleetManager, insertionCostsCalculator, priorityQueues[unassignedJob.getIndex()], updateRound, unassignedJob, routes); + for(VehicleRoute r : routes) updates.put(r,updateRound); + } else { + InsertionDataUpdater.update(switchAllowed, initialVehicleIds, fleetManager, insertionCostsCalculator, priorityQueues[unassignedJob.getIndex()], updateRound, unassignedJob, Arrays.asList(lastModified)); + updates.put(lastModified,updateRound); + } + } + } } } diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/ConstraintManager.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/ConstraintManager.java index 6ac536dd..cbeec577 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/ConstraintManager.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/ConstraintManager.java @@ -17,6 +17,7 @@ package com.graphhopper.jsprit.core.problem.constraint; import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem; +import com.graphhopper.jsprit.core.problem.job.Job; import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext; import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity; import com.graphhopper.jsprit.core.problem.solution.route.state.RouteAndActivityStateGetter; @@ -59,17 +60,40 @@ public class ConstraintManager implements HardActivityConstraint, HardRouteConst private boolean skillconstraintSet = false; + private final DependencyType[] dependencyTypes; + public ConstraintManager(VehicleRoutingProblem vrp, RouteAndActivityStateGetter stateManager) { this.vrp = vrp; this.stateManager = stateManager; + dependencyTypes = new DependencyType[vrp.getJobs().size() + 1]; } public ConstraintManager(VehicleRoutingProblem vrp, RouteAndActivityStateGetter stateManager, Collection constraints) { this.vrp = vrp; this.stateManager = stateManager; + dependencyTypes = new DependencyType[vrp.getJobs().size() + 1]; resolveConstraints(constraints); } + public DependencyType[] getDependencyTypes() { + return dependencyTypes; + } + + public void setDependencyType(String jobId, DependencyType dependencyType){ + Job job = vrp.getJobs().get(jobId); + if(job != null) { + dependencyTypes[job.getIndex()] = dependencyType; + } + } + + public DependencyType getDependencyType(String jobId){ + Job job = vrp.getJobs().get(jobId); + if(job != null){ + return dependencyTypes[job.getIndex()]; + } + return DependencyType.NO_TYPE; + } + private void resolveConstraints(Collection constraints) { for (Constraint c : constraints) { boolean constraintTypeKnown = false; diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/DependencyType.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/DependencyType.java new file mode 100644 index 00000000..07471c27 --- /dev/null +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/DependencyType.java @@ -0,0 +1,10 @@ +package com.graphhopper.jsprit.core.problem.constraint; + +/** + * Created by schroeder on 12/07/16. + */ +public enum DependencyType { + + INTER_ROUTE, INTRA_ROUTE, NO_TYPE + +} diff --git a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertionTest.java b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertionTest.java index e192e9fe..61b901ca 100644 --- a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertionTest.java +++ b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertionTest.java @@ -17,20 +17,30 @@ package com.graphhopper.jsprit.core.algorithm.recreate; +import com.graphhopper.jsprit.core.algorithm.VehicleRoutingAlgorithm; +import com.graphhopper.jsprit.core.algorithm.box.Jsprit; import com.graphhopper.jsprit.core.algorithm.recreate.listener.BeforeJobInsertionListener; +import com.graphhopper.jsprit.core.algorithm.state.StateId; +import com.graphhopper.jsprit.core.algorithm.state.StateManager; +import com.graphhopper.jsprit.core.algorithm.state.StateUpdater; import com.graphhopper.jsprit.core.problem.Location; import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem; +import com.graphhopper.jsprit.core.problem.constraint.ConstraintManager; +import com.graphhopper.jsprit.core.problem.constraint.DependencyType; +import com.graphhopper.jsprit.core.problem.constraint.HardRouteConstraint; import com.graphhopper.jsprit.core.problem.driver.Driver; import com.graphhopper.jsprit.core.problem.job.Job; import com.graphhopper.jsprit.core.problem.job.Service; import com.graphhopper.jsprit.core.problem.job.Shipment; +import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext; +import com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolution; import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute; +import com.graphhopper.jsprit.core.problem.solution.route.activity.ActivityVisitor; import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity; -import com.graphhopper.jsprit.core.problem.vehicle.FiniteFleetManagerFactory; -import com.graphhopper.jsprit.core.problem.vehicle.Vehicle; -import com.graphhopper.jsprit.core.problem.vehicle.VehicleFleetManager; -import com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl; +import com.graphhopper.jsprit.core.problem.vehicle.*; +import com.graphhopper.jsprit.core.reporting.SolutionPrinter; import com.graphhopper.jsprit.core.util.Coordinate; +import com.graphhopper.jsprit.core.util.Solutions; import junit.framework.Assert; import org.junit.Test; @@ -92,6 +102,197 @@ public class RegretInsertionTest { Assert.assertTrue(position.isCorrect()); } + @Test + public void solutionWithFastRegretMustBeCorrect() { + Service s1 = Service.Builder.newInstance("s1").setLocation(Location.newInstance(0, 10)).build(); + Service s2 = Service.Builder.newInstance("s2").setLocation(Location.newInstance(0, -10)).build(); + + VehicleImpl v1 = VehicleImpl.Builder.newInstance("v1").setStartLocation(Location.newInstance(0, 5)).build(); + VehicleImpl v2 = VehicleImpl.Builder.newInstance("v2").setStartLocation(Location.newInstance(0, -5)).build(); + final VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().addJob(s1).addJob(s2) + .addVehicle(v1).addVehicle(v2).setFleetSize(VehicleRoutingProblem.FleetSize.FINITE).build(); + + StateManager stateManager = new StateManager(vrp); + ConstraintManager constraintManager = new ConstraintManager(vrp,stateManager); + + VehicleRoutingAlgorithm vra = Jsprit.Builder.newInstance(vrp) + .addCoreStateAndConstraintStuff(true) + .setProperty(Jsprit.Parameter.FAST_REGRET,"true") + .setStateAndConstraintManager(stateManager, constraintManager).buildAlgorithm(); + + VehicleRoutingProblemSolution solution = Solutions.bestOf(vra.searchSolutions()); + + Assert.assertEquals(2, solution.getRoutes().size()); + } + + static class JobInRouteUpdater implements StateUpdater, ActivityVisitor { + + private StateManager stateManager; + + private StateId job1AssignedId; + + private StateId job2AssignedId; + + private VehicleRoute route; + + public JobInRouteUpdater(StateManager stateManager, StateId job1AssignedId, StateId job2AssignedId) { + this.stateManager = stateManager; + this.job1AssignedId = job1AssignedId; + this.job2AssignedId = job2AssignedId; + } + + @Override + public void begin(VehicleRoute route) { + this.route = route; + } + + @Override + public void visit(TourActivity activity) { + if(((TourActivity.JobActivity)activity).getJob().getId().equals("s1")){ + stateManager.putProblemState(job1AssignedId,Boolean.class,true); + } + if(((TourActivity.JobActivity)activity).getJob().getId().equals("s2")){ + stateManager.putProblemState(job2AssignedId,Boolean.class,true); + } + + } + + @Override + public void finish() { + + } + } + + static class RouteConstraint implements HardRouteConstraint{ + + private final StateId job1AssignedId; + + private final StateId job2AssignedId; + + private StateManager stateManager; + + public RouteConstraint(StateId job1Assigned, StateId job2Assigned, StateManager stateManager) { + this.job1AssignedId = job1Assigned; + this.job2AssignedId = job2Assigned; + this.stateManager = stateManager; + } + + @Override + public boolean fulfilled(JobInsertionContext insertionContext) { + if(insertionContext.getJob().getId().equals("s1")){ + Boolean job2Assigned = stateManager.getProblemState(job2AssignedId,Boolean.class); + if(job2Assigned == null || job2Assigned == false) return true; + else { + for(Job j : insertionContext.getRoute().getTourActivities().getJobs()){ + if(j.getId().equals("s2")) return true; + } + } + return false; + } + if(insertionContext.getJob().getId().equals("s2")){ + Boolean job1Assigned = stateManager.getProblemState(job1AssignedId,Boolean.class); + if(job1Assigned == null || job1Assigned == false) return true; + else { + for(Job j : insertionContext.getRoute().getTourActivities().getJobs()){ + if(j.getId().equals("s1")) return true; + } + } + return false; + } + return true; + } + } + + @Test + public void solutionWithConstraintAndWithFastRegretMustBeCorrect() { + Service s1 = Service.Builder.newInstance("s1").addSizeDimension(0,1).setLocation(Location.newInstance(0, 10)).build(); + Service s2 = Service.Builder.newInstance("s2").addSizeDimension(0,1).setLocation(Location.newInstance(0, -10)).build(); + Service s3 = Service.Builder.newInstance("s3").addSizeDimension(0,1).setLocation(Location.newInstance(0, -11)).build(); + Service s4 = Service.Builder.newInstance("s4").addSizeDimension(0,1).setLocation(Location.newInstance(0, 11)).build(); + + VehicleType type = VehicleTypeImpl.Builder.newInstance("type").addCapacityDimension(0,2).build(); + VehicleImpl v1 = VehicleImpl.Builder.newInstance("v1").setType(type).setStartLocation(Location.newInstance(0, 10)).build(); + VehicleImpl v2 = VehicleImpl.Builder.newInstance("v2").setType(type).setStartLocation(Location.newInstance(0, -10)).build(); + final VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().addJob(s1).addJob(s2).addJob(s3).addJob(s4) + .addVehicle(v1).addVehicle(v2).setFleetSize(VehicleRoutingProblem.FleetSize.FINITE).build(); + + final StateManager stateManager = new StateManager(vrp); + StateId job1Assigned = stateManager.createStateId("job1-assigned"); + StateId job2Assigned = stateManager.createStateId("job2-assigned"); + stateManager.addStateUpdater(new JobInRouteUpdater(stateManager,job1Assigned,job2Assigned)); + ConstraintManager constraintManager = new ConstraintManager(vrp,stateManager); + constraintManager.addConstraint(new RouteConstraint(job1Assigned,job2Assigned,stateManager)); + constraintManager.setDependencyType("s1", DependencyType.INTRA_ROUTE); + constraintManager.setDependencyType("s2", DependencyType.INTRA_ROUTE); + + VehicleRoutingAlgorithm vra = Jsprit.Builder.newInstance(vrp) + .addCoreStateAndConstraintStuff(true) + .setProperty(Jsprit.Parameter.FAST_REGRET, "true") + .setStateAndConstraintManager(stateManager, constraintManager) +// .setProperty(Jsprit.Strategy.CLUSTER_REGRET, "0.") +// .setProperty(Jsprit.Strategy.CLUSTER_BEST, "0.") +// .setProperty(Jsprit.Strategy.RADIAL_REGRET, "0.") +// .setProperty(Jsprit.Strategy.RADIAL_BEST, "0.") +// .setProperty(Jsprit.Strategy.RANDOM_REGRET, "1.") +// .setProperty(Jsprit.Strategy.RANDOM_BEST, "0.") +// .setProperty(Jsprit.Strategy.WORST_REGRET, "0.") +// .setProperty(Jsprit.Strategy.WORST_BEST, "0.") + .buildAlgorithm(); + + VehicleRoutingProblemSolution solution = Solutions.bestOf(vra.searchSolutions()); + SolutionPrinter.print(vrp,solution, SolutionPrinter.Print.VERBOSE); + for(VehicleRoute route : solution.getRoutes()){ + if(route.getTourActivities().servesJob(s1)){ + if(!route.getTourActivities().servesJob(s2)){ + Assert.assertFalse(true); + } + else Assert.assertTrue(true); + } + } +// Assert.assertEquals(1, solution.getRoutes().size()); + } + + @Test + public void solutionWithConstraintAndWithFastRegretConcurrentMustBeCorrect() { + Service s1 = Service.Builder.newInstance("s1").addSizeDimension(0,1).setLocation(Location.newInstance(0, 10)).build(); + Service s2 = Service.Builder.newInstance("s2").addSizeDimension(0,1).setLocation(Location.newInstance(0, -10)).build(); + Service s3 = Service.Builder.newInstance("s3").addSizeDimension(0,1).setLocation(Location.newInstance(0, -11)).build(); + Service s4 = Service.Builder.newInstance("s4").addSizeDimension(0,1).setLocation(Location.newInstance(0, 11)).build(); + + VehicleType type = VehicleTypeImpl.Builder.newInstance("type").addCapacityDimension(0,2).build(); + VehicleImpl v1 = VehicleImpl.Builder.newInstance("v1").setType(type).setStartLocation(Location.newInstance(0, 10)).build(); + VehicleImpl v2 = VehicleImpl.Builder.newInstance("v2").setType(type).setStartLocation(Location.newInstance(0, -10)).build(); + final VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().addJob(s1).addJob(s2).addJob(s3).addJob(s4) + .addVehicle(v1).addVehicle(v2).setFleetSize(VehicleRoutingProblem.FleetSize.FINITE).build(); + + final StateManager stateManager = new StateManager(vrp); + StateId job1Assigned = stateManager.createStateId("job1-assigned"); + StateId job2Assigned = stateManager.createStateId("job2-assigned"); + stateManager.addStateUpdater(new JobInRouteUpdater(stateManager,job1Assigned,job2Assigned)); + ConstraintManager constraintManager = new ConstraintManager(vrp,stateManager); + constraintManager.addConstraint(new RouteConstraint(job1Assigned,job2Assigned,stateManager)); + constraintManager.setDependencyType("s1", DependencyType.INTRA_ROUTE); + constraintManager.setDependencyType("s2", DependencyType.INTRA_ROUTE); + + VehicleRoutingAlgorithm vra = Jsprit.Builder.newInstance(vrp) + .addCoreStateAndConstraintStuff(true) + .setProperty(Jsprit.Parameter.FAST_REGRET, "true") + .setProperty(Jsprit.Parameter.THREADS,"4") + .setStateAndConstraintManager(stateManager, constraintManager) + .buildAlgorithm(); + + VehicleRoutingProblemSolution solution = Solutions.bestOf(vra.searchSolutions()); + SolutionPrinter.print(vrp,solution, SolutionPrinter.Print.VERBOSE); + for(VehicleRoute route : solution.getRoutes()){ + if(route.getTourActivities().servesJob(s1)){ + if(!route.getTourActivities().servesJob(s2)){ + Assert.assertFalse(true); + } + else Assert.assertTrue(true); + } + } + } + @Test public void shipment1ShouldBeAddedFirst() { Shipment s1 = Shipment.Builder.newInstance("s1") diff --git a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/CapacityTest.java b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/CapacityTest.java index 3a1212b6..de9bba96 100644 --- a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/CapacityTest.java +++ b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/CapacityTest.java @@ -18,6 +18,7 @@ ******************************************************************************/ package com.graphhopper.jsprit.core.problem; +import org.junit.Assert; import org.junit.Test; import java.util.Random; @@ -369,4 +370,18 @@ public class CapacityTest { Capacity cap2 = Capacity.Builder.newInstance().build(); assertEquals(0.0, Capacity.divide(cap1, cap2), 0.001); } + + @Test + public void shouldBeEqual(){ + Capacity cap1 = Capacity.Builder.newInstance().build(); + Capacity cap2 = Capacity.Builder.newInstance().build(); + Assert.assertTrue(cap1.equals(cap2)); + } + + @Test + public void shouldBeEqual2(){ + Capacity cap1 = Capacity.Builder.newInstance().addDimension(0,10).addDimension(1,100).addDimension(2,1000).build(); + Capacity cap2 = Capacity.Builder.newInstance().addDimension(0,10).addDimension(2, 1000).addDimension(1,100).build(); + Assert.assertTrue(cap1.equals(cap2)); + } }