1
0
Fork 0
mirror of https://github.com/graphhopper/jsprit.git synced 2020-01-24 07:45:05 +01:00

add a way to use fast regret with custom contraints

This commit is contained in:
oblonski 2016-07-13 13:51:43 +02:00
parent ea1889b15a
commit 82565b4416
7 changed files with 359 additions and 49 deletions

View file

@ -436,6 +436,7 @@ public class Jsprit {
.build(); .build();
scorer = getRegretScorer(vrp); scorer = getRegretScorer(vrp);
regretInsertion.setScoringFunction(scorer); regretInsertion.setScoringFunction(scorer);
regretInsertion.setDependencyTypes(constraintManager.getDependencyTypes());
regret = regretInsertion; regret = regretInsertion;
} }
else { else {
@ -461,6 +462,7 @@ public class Jsprit {
.build(); .build();
scorer = getRegretScorer(vrp); scorer = getRegretScorer(vrp);
regretInsertion.setScoringFunction(scorer); regretInsertion.setScoringFunction(scorer);
regretInsertion.setDependencyTypes(constraintManager.getDependencyTypes());
regret = regretInsertion; regret = regretInsertion;
} }
else{ else{

View file

@ -18,6 +18,7 @@
package com.graphhopper.jsprit.core.algorithm.recreate; package com.graphhopper.jsprit.core.algorithm.recreate;
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem; 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.Break;
import com.graphhopper.jsprit.core.problem.job.Job; import com.graphhopper.jsprit.core.problem.job.Job;
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute; import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
@ -57,6 +58,8 @@ public class RegretInsertionConcurrentFast extends AbstractInsertionStrategy {
private boolean switchAllowed = true; private boolean switchAllowed = true;
private DependencyType[] dependencyTypes = null;
/** /**
* Sets the scoring function. * Sets the scoring function.
@ -97,6 +100,10 @@ public class RegretInsertionConcurrentFast extends AbstractInsertionStrategy {
return ids; return ids;
} }
public void setDependencyTypes(DependencyType[] dependencyTypes){
this.dependencyTypes = dependencyTypes;
}
/** /**
* Runs insertion. * Runs insertion.
@ -139,15 +146,8 @@ public class RegretInsertionConcurrentFast extends AbstractInsertionStrategy {
List<Job> unassignedJobList = new ArrayList<Job>(jobs); List<Job> unassignedJobList = new ArrayList<Job>(jobs);
List<Job> badJobList = new ArrayList<Job>(); List<Job> badJobList = new ArrayList<Job>();
if(!firstRun && lastModified == null) throw new IllegalStateException("ho. this must not be."); if(!firstRun && lastModified == null) throw new IllegalStateException("ho. this must not be.");
if(firstRun){ updateInsertionData(priorityQueues, routes, unassignedJobList, updateRound,firstRun,lastModified,updates);
firstRun = false; 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);
}
updateRound++; updateRound++;
ScoredJob bestScoredJob = InsertionDataUpdater.getBest(switchAllowed,initialVehicleIds,fleetManager, insertionCostsCalculator, scoringFunction, priorityQueues, updates, unassignedJobList, badJobList); ScoredJob bestScoredJob = InsertionDataUpdater.getBest(switchAllowed,initialVehicleIds,fleetManager, insertionCostsCalculator, scoringFunction, priorityQueues, updates, unassignedJobList, badJobList);
if (bestScoredJob != null) { if (bestScoredJob != null) {
@ -167,19 +167,38 @@ public class RegretInsertionConcurrentFast extends AbstractInsertionStrategy {
return badJobs; return badJobs;
} }
private void updateInsertionData(final TreeSet<VersionedInsertionData>[] priorityQueues, final Collection<VehicleRoute> routes, List<Job> unassignedJobList, final int updateRound) { private void updateInsertionData(final TreeSet<VersionedInsertionData>[] priorityQueues, final Collection<VehicleRoute> routes, List<Job> unassignedJobList, final int updateRound, final boolean firstRun, final VehicleRoute lastModified, Map<VehicleRoute, Integer> updates) {
List<Callable<Boolean>> tasks = new ArrayList<Callable<Boolean>>(); List<Callable<Boolean>> tasks = new ArrayList<Callable<Boolean>>();
boolean updatedAllRoutes = false;
for (final Job unassignedJob : unassignedJobList) { for (final Job unassignedJob : unassignedJobList) {
if(priorityQueues[unassignedJob.getIndex()] == null){ if(priorityQueues[unassignedJob.getIndex()] == null){
priorityQueues[unassignedJob.getIndex()] = new TreeSet<VersionedInsertionData>(InsertionDataUpdater.getComparator()); priorityQueues[unassignedJob.getIndex()] = new TreeSet<VersionedInsertionData>(InsertionDataUpdater.getComparator());
} }
final TreeSet<VersionedInsertionData> priorityQueue = priorityQueues[unassignedJob.getIndex()]; final TreeSet<VersionedInsertionData> priorityQueue = priorityQueues[unassignedJob.getIndex()];
tasks.add(new Callable<Boolean>() { if(firstRun) {
@Override makeCallables(tasks, true, priorityQueues[unassignedJob.getIndex()], updateRound, unassignedJob, routes, lastModified);
public Boolean call() throws Exception { updatedAllRoutes = true;
return InsertionDataUpdater.update(switchAllowed,initialVehicleIds,fleetManager, insertionCostsCalculator, priorityQueue, updateRound, unassignedJob, routes); }
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 { try {
List<Future<Boolean>> futures = executor.invokeAll(tasks); List<Future<Boolean>> futures = executor.invokeAll(tasks);
@ -189,8 +208,24 @@ public class RegretInsertionConcurrentFast extends AbstractInsertionStrategy {
} }
} }
private void makeCallables(List<Callable<Boolean>> tasks, boolean updateAll, final TreeSet<VersionedInsertionData> priorityQueue, final int updateRound, final Job unassignedJob, final Collection<VehicleRoute> routes, final VehicleRoute lastModified) {
if(updateAll) {
tasks.add(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
return InsertionDataUpdater.update(switchAllowed, initialVehicleIds, fleetManager, insertionCostsCalculator, priorityQueue, updateRound, unassignedJob, routes);
}
});
}
else {
tasks.add(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
return InsertionDataUpdater.update(switchAllowed, initialVehicleIds, fleetManager, insertionCostsCalculator, priorityQueue, updateRound, unassignedJob, Arrays.asList(lastModified));
}
});
}
}
} }

View file

@ -18,7 +18,7 @@
package com.graphhopper.jsprit.core.algorithm.recreate; package com.graphhopper.jsprit.core.algorithm.recreate;
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem; 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.job.Job;
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute; import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
import com.graphhopper.jsprit.core.problem.vehicle.VehicleFleetManager; import com.graphhopper.jsprit.core.problem.vehicle.VehicleFleetManager;
@ -51,7 +51,7 @@ public class RegretInsertionFast extends AbstractInsertionStrategy {
private boolean switchAllowed = true; private boolean switchAllowed = true;
private DependencyType[] dependencyTypes = null;
public RegretInsertionFast(JobInsertionCostsCalculator jobInsertionCalculator, VehicleRoutingProblem vehicleRoutingProblem, VehicleFleetManager fleetManager) { public RegretInsertionFast(JobInsertionCostsCalculator jobInsertionCalculator, VehicleRoutingProblem vehicleRoutingProblem, VehicleFleetManager fleetManager) {
super(vehicleRoutingProblem); super(vehicleRoutingProblem);
@ -78,6 +78,10 @@ public class RegretInsertionFast extends AbstractInsertionStrategy {
this.switchAllowed = switchAllowed; this.switchAllowed = switchAllowed;
} }
public void setDependencyTypes(DependencyType[] dependencyTypes){
this.dependencyTypes = dependencyTypes;
}
private Set<String> getInitialVehicleIds(VehicleRoutingProblem vehicleRoutingProblem) { private Set<String> getInitialVehicleIds(VehicleRoutingProblem vehicleRoutingProblem) {
Set<String> ids = new HashSet<String>(); Set<String> ids = new HashSet<String>();
for(VehicleRoute r : vehicleRoutingProblem.getInitialVehicleRoutes()){ for(VehicleRoute r : vehicleRoutingProblem.getInitialVehicleRoutes()){
@ -101,25 +105,25 @@ public class RegretInsertionFast extends AbstractInsertionStrategy {
public Collection<Job> insertUnassignedJobs(Collection<VehicleRoute> routes, Collection<Job> unassignedJobs) { public Collection<Job> insertUnassignedJobs(Collection<VehicleRoute> routes, Collection<Job> unassignedJobs) {
List<Job> badJobs = new ArrayList<Job>(unassignedJobs.size()); List<Job> badJobs = new ArrayList<Job>(unassignedJobs.size());
Iterator<Job> jobIterator = unassignedJobs.iterator(); // Iterator<Job> jobIterator = unassignedJobs.iterator();
while (jobIterator.hasNext()){ // while (jobIterator.hasNext()){
Job job = jobIterator.next(); // Job job = jobIterator.next();
if(job instanceof Break){ // if(job instanceof Break){
VehicleRoute route = InsertionDataUpdater.findRoute(routes, job); // VehicleRoute route = InsertionDataUpdater.findRoute(routes, job);
if(route == null){ // if(route == null){
badJobs.add(job); // badJobs.add(job);
} // }
else { // else {
InsertionData iData = insertionCostsCalculator.getInsertionData(route, job, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, Double.MAX_VALUE); // 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) { // if (iData instanceof InsertionData.NoInsertionFound) {
badJobs.add(job); // badJobs.add(job);
} else { // } else {
insertJob(job, iData, route); // insertJob(job, iData, route);
} // }
} // }
jobIterator.remove(); // jobIterator.remove();
} // }
} // }
List<Job> jobs = new ArrayList<Job>(unassignedJobs); List<Job> jobs = new ArrayList<Job>(unassignedJobs);
TreeSet<VersionedInsertionData>[] priorityQueues = new TreeSet[vrp.getJobs().values().size() + 2]; TreeSet<VersionedInsertionData>[] priorityQueues = new TreeSet[vrp.getJobs().values().size() + 2];
@ -130,15 +134,15 @@ public class RegretInsertionFast extends AbstractInsertionStrategy {
while (!jobs.isEmpty()) { while (!jobs.isEmpty()) {
List<Job> unassignedJobList = new ArrayList<Job>(jobs); List<Job> unassignedJobList = new ArrayList<Job>(jobs);
List<Job> badJobList = new ArrayList<Job>(); List<Job> badJobList = new ArrayList<Job>();
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){ if(firstRun){
updateInsertionData(priorityQueues, routes, unassignedJobList, updateRound, firstRun, lastModified, updates);
firstRun = false; firstRun = false;
updateInsertionData(priorityQueues, routes, unassignedJobList, updateRound);
for(VehicleRoute r : routes) updates.put(r,updateRound);
} }
else{ else{
updateInsertionData(priorityQueues, Arrays.asList(lastModified), unassignedJobList, updateRound); //update for all routes || remove history and only update modified route
updates.put(lastModified,updateRound); updateInsertionData(priorityQueues, routes, unassignedJobList, updateRound, firstRun, lastModified, updates);
// updates.put(lastModified,updateRound);
} }
updateRound++; updateRound++;
ScoredJob bestScoredJob = InsertionDataUpdater.getBest(switchAllowed,initialVehicleIds,fleetManager,insertionCostsCalculator,scoringFunction,priorityQueues,updates,unassignedJobList,badJobList); ScoredJob bestScoredJob = InsertionDataUpdater.getBest(switchAllowed,initialVehicleIds,fleetManager,insertionCostsCalculator,scoringFunction,priorityQueues,updates,unassignedJobList,badJobList);
@ -159,12 +163,31 @@ public class RegretInsertionFast extends AbstractInsertionStrategy {
return badJobs; return badJobs;
} }
private void updateInsertionData(TreeSet<VersionedInsertionData>[] priorityQueues, Collection<VehicleRoute> routes, List<Job> unassignedJobList, int updateRound) { private void updateInsertionData(TreeSet<VersionedInsertionData>[] priorityQueues, Collection<VehicleRoute> routes, List<Job> unassignedJobList, int updateRound, boolean firstRun, VehicleRoute lastModified, Map<VehicleRoute, Integer> updates) {
for (Job unassignedJob : unassignedJobList) { for (Job unassignedJob : unassignedJobList) {
if(priorityQueues[unassignedJob.getIndex()] == null){ if(priorityQueues[unassignedJob.getIndex()] == null){
priorityQueues[unassignedJob.getIndex()] = new TreeSet<VersionedInsertionData>(InsertionDataUpdater.getComparator()); priorityQueues[unassignedJob.getIndex()] = new TreeSet<VersionedInsertionData>(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);
}
}
}
} }
} }

View file

@ -17,6 +17,7 @@
package com.graphhopper.jsprit.core.problem.constraint; package com.graphhopper.jsprit.core.problem.constraint;
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem; 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.misc.JobInsertionContext;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity; import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity;
import com.graphhopper.jsprit.core.problem.solution.route.state.RouteAndActivityStateGetter; 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 boolean skillconstraintSet = false;
private final DependencyType[] dependencyTypes;
public ConstraintManager(VehicleRoutingProblem vrp, RouteAndActivityStateGetter stateManager) { public ConstraintManager(VehicleRoutingProblem vrp, RouteAndActivityStateGetter stateManager) {
this.vrp = vrp; this.vrp = vrp;
this.stateManager = stateManager; this.stateManager = stateManager;
dependencyTypes = new DependencyType[vrp.getJobs().size() + 1];
} }
public ConstraintManager(VehicleRoutingProblem vrp, RouteAndActivityStateGetter stateManager, Collection<Constraint> constraints) { public ConstraintManager(VehicleRoutingProblem vrp, RouteAndActivityStateGetter stateManager, Collection<Constraint> constraints) {
this.vrp = vrp; this.vrp = vrp;
this.stateManager = stateManager; this.stateManager = stateManager;
dependencyTypes = new DependencyType[vrp.getJobs().size() + 1];
resolveConstraints(constraints); 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<Constraint> constraints) { private void resolveConstraints(Collection<Constraint> constraints) {
for (Constraint c : constraints) { for (Constraint c : constraints) {
boolean constraintTypeKnown = false; boolean constraintTypeKnown = false;

View file

@ -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
}

View file

@ -17,20 +17,30 @@
package com.graphhopper.jsprit.core.algorithm.recreate; 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.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.Location;
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem; 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.driver.Driver;
import com.graphhopper.jsprit.core.problem.job.Job; import com.graphhopper.jsprit.core.problem.job.Job;
import com.graphhopper.jsprit.core.problem.job.Service; import com.graphhopper.jsprit.core.problem.job.Service;
import com.graphhopper.jsprit.core.problem.job.Shipment; 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.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.solution.route.activity.TourActivity;
import com.graphhopper.jsprit.core.problem.vehicle.FiniteFleetManagerFactory; import com.graphhopper.jsprit.core.problem.vehicle.*;
import com.graphhopper.jsprit.core.problem.vehicle.Vehicle; import com.graphhopper.jsprit.core.reporting.SolutionPrinter;
import com.graphhopper.jsprit.core.problem.vehicle.VehicleFleetManager;
import com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl;
import com.graphhopper.jsprit.core.util.Coordinate; import com.graphhopper.jsprit.core.util.Coordinate;
import com.graphhopper.jsprit.core.util.Solutions;
import junit.framework.Assert; import junit.framework.Assert;
import org.junit.Test; import org.junit.Test;
@ -92,6 +102,197 @@ public class RegretInsertionTest {
Assert.assertTrue(position.isCorrect()); 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 @Test
public void shipment1ShouldBeAddedFirst() { public void shipment1ShouldBeAddedFirst() {
Shipment s1 = Shipment.Builder.newInstance("s1") Shipment s1 = Shipment.Builder.newInstance("s1")

View file

@ -18,6 +18,7 @@
******************************************************************************/ ******************************************************************************/
package com.graphhopper.jsprit.core.problem; package com.graphhopper.jsprit.core.problem;
import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import java.util.Random; import java.util.Random;
@ -369,4 +370,18 @@ public class CapacityTest {
Capacity cap2 = Capacity.Builder.newInstance().build(); Capacity cap2 = Capacity.Builder.newInstance().build();
assertEquals(0.0, Capacity.divide(cap1, cap2), 0.001); 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));
}
} }