mirror of
https://github.com/graphhopper/jsprit.git
synced 2020-01-24 07:45:05 +01:00
parent
e94a76fd1c
commit
8b75937ca8
10 changed files with 132 additions and 7 deletions
|
|
@ -28,9 +28,7 @@ import com.graphhopper.jsprit.core.problem.job.Job;
|
|||
import com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolution;
|
||||
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
public class RuinAndRecreateModule implements SearchStrategyModule {
|
||||
|
|
@ -54,6 +52,9 @@ public class RuinAndRecreateModule implements SearchStrategyModule {
|
|||
Set<Job> ruinedJobSet = new HashSet<>();
|
||||
ruinedJobSet.addAll(ruinedJobs);
|
||||
ruinedJobSet.addAll(vrpSolution.getUnassignedJobs());
|
||||
|
||||
removeEmptyRoutes(vrpSolution.getRoutes());
|
||||
|
||||
Collection<Job> unassignedJobs = insertion.insertJobs(vrpSolution.getRoutes(), ruinedJobSet);
|
||||
vrpSolution.getUnassignedJobs().clear();
|
||||
vrpSolution.getUnassignedJobs().addAll(getUnassignedJobs(vrpSolution, unassignedJobs));
|
||||
|
|
@ -61,6 +62,17 @@ public class RuinAndRecreateModule implements SearchStrategyModule {
|
|||
return vrpSolution;
|
||||
}
|
||||
|
||||
static void removeEmptyRoutes(Collection<VehicleRoute> routes) {
|
||||
final Iterator<VehicleRoute> iterator = routes.iterator();
|
||||
List<VehicleRoute> emptyRoutes = new ArrayList<>();
|
||||
while (iterator.hasNext()) {
|
||||
final VehicleRoute route = iterator.next();
|
||||
if (route.isEmpty())
|
||||
emptyRoutes.add(route);
|
||||
}
|
||||
routes.removeAll(emptyRoutes);
|
||||
}
|
||||
|
||||
static Set<Job> getUnassignedJobs(VehicleRoutingProblemSolution vrpSolution, Collection<Job> unassignedJobs) {
|
||||
final Set<Job> unassigned = new HashSet<>();
|
||||
for (Job job : unassignedJobs) {
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import com.graphhopper.jsprit.core.algorithm.recreate.listener.InsertionListener
|
|||
import com.graphhopper.jsprit.core.algorithm.recreate.listener.InsertionListeners;
|
||||
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
|
||||
import com.graphhopper.jsprit.core.problem.driver.Driver;
|
||||
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;
|
||||
import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
|
||||
|
|
@ -132,4 +133,17 @@ public abstract class AbstractInsertionStrategy implements InsertionStrategy {
|
|||
iData.setInsertionCost(iData.getInsertionCost() + iData.getSelectedVehicle().getType().getVehicleCostParams().fix);
|
||||
}
|
||||
|
||||
|
||||
protected void insertBreak(JobInsertionCostsCalculator jobInsertionCostsCalculator, List<Job> badJobs, VehicleRoute route, InsertionData iDataJob) {
|
||||
if (iDataJob.getSelectedVehicle() != null && iDataJob.getSelectedVehicle().getBreak() != null) {
|
||||
final Break aBreak = iDataJob.getSelectedVehicle().getBreak();
|
||||
InsertionData iData = jobInsertionCostsCalculator.getInsertionData(route, aBreak, iDataJob.getSelectedVehicle(), iDataJob.getSelectedVehicle().getEarliestDeparture(), iDataJob.getSelectedDriver(), Double.MAX_VALUE);
|
||||
if (iData instanceof InsertionData.NoInsertionFound) {
|
||||
badJobs.add(aBreak);
|
||||
} else {
|
||||
insertJob(aBreak, iData, route);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,9 +84,12 @@ public final class BestInsertion extends AbstractInsertionStrategy {
|
|||
}
|
||||
VehicleRoute newRoute = VehicleRoute.emptyRoute();
|
||||
InsertionData newIData = bestInsertionCostCalculator.getInsertionData(newRoute, unassignedJob, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, bestInsertionCost);
|
||||
|
||||
boolean isNewRoute = false;
|
||||
if (!(newIData instanceof InsertionData.NoInsertionFound)) {
|
||||
updateNewRouteInsertionData(newIData);
|
||||
if (newIData.getInsertionCost() < bestInsertionCost + noiseMaker.makeNoise()) {
|
||||
isNewRoute = true;
|
||||
bestInsertion = new Insertion(newRoute, newIData);
|
||||
vehicleRoutes.add(newRoute);
|
||||
}
|
||||
|
|
@ -96,8 +99,14 @@ public final class BestInsertion extends AbstractInsertionStrategy {
|
|||
if (bestInsertion == null) {
|
||||
badJobs.add(unassignedJob);
|
||||
markUnassigned(unassignedJob, empty.getFailedConstraintNames());
|
||||
} else {
|
||||
insertJob(unassignedJob, bestInsertion.getInsertionData(), bestInsertion.getRoute());
|
||||
|
||||
if (isNewRoute || !bestInsertion.getRoute().getVehicle().getId().equals(bestInsertion.getInsertionData().getSelectedVehicle().getId())) {
|
||||
insertBreak(bestInsertionCostCalculator, badJobs, bestInsertion.getRoute(), bestInsertion.getInsertionData());
|
||||
}
|
||||
}
|
||||
else insertJob(unassignedJob, bestInsertion.getInsertionData(), bestInsertion.getRoute());
|
||||
|
||||
}
|
||||
return badJobs;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -139,7 +139,9 @@ public final class BestInsertionConcurrent extends AbstractInsertionStrategy {
|
|||
VehicleRoute newRoute = VehicleRoute.emptyRoute();
|
||||
InsertionData newIData = bestInsertionCostCalculator.getInsertionData(newRoute, unassignedJob, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, bestInsertionCost);
|
||||
updateNewRouteInsertionData(newIData);
|
||||
boolean isNewRoute = false;
|
||||
if (newIData.getInsertionCost() < bestInsertionCost) {
|
||||
isNewRoute = true;
|
||||
bestInsertion = new Insertion(newRoute, newIData);
|
||||
vehicleRoutes.add(newRoute);
|
||||
batches.get(random.nextInt(batches.size())).routes.add(newRoute);
|
||||
|
|
@ -148,7 +150,13 @@ public final class BestInsertionConcurrent extends AbstractInsertionStrategy {
|
|||
badJobs.add(unassignedJob);
|
||||
markUnassigned(unassignedJob, failedConstraintNames);
|
||||
}
|
||||
else insertJob(unassignedJob, bestInsertion.getInsertionData(), bestInsertion.getRoute());
|
||||
else {
|
||||
insertJob(unassignedJob, bestInsertion.getInsertionData(), bestInsertion.getRoute());
|
||||
|
||||
if (isNewRoute || !bestInsertion.getRoute().getVehicle().getId().equals(bestInsertion.getInsertionData().getSelectedVehicle().getId())) {
|
||||
insertBreak(bestInsertionCostCalculator, badJobs, bestInsertion.getRoute(), bestInsertion.getInsertionData());
|
||||
}
|
||||
}
|
||||
}
|
||||
return badJobs;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -111,11 +111,16 @@ public class RegretInsertion extends AbstractInsertionStrategy {
|
|||
List<ScoredJob> badJobList = new ArrayList<>();
|
||||
ScoredJob bestScoredJob = nextJob(routes, unassignedJobList, badJobList);
|
||||
if (bestScoredJob != null) {
|
||||
final VehicleRoute route = bestScoredJob.getRoute();
|
||||
if (bestScoredJob.isNewRoute()) {
|
||||
routes.add(bestScoredJob.getRoute());
|
||||
routes.add(route);
|
||||
}
|
||||
insertJob(bestScoredJob.getJob(), bestScoredJob.getInsertionData(), bestScoredJob.getRoute());
|
||||
insertJob(bestScoredJob.getJob(), bestScoredJob.getInsertionData(), route);
|
||||
jobs.remove(bestScoredJob.getJob());
|
||||
|
||||
if (bestScoredJob.isNewRoute() || !route.getVehicle().getId().equals(bestScoredJob.getInsertionData().getSelectedVehicle().getId())) {
|
||||
insertBreak(insertionCostsCalculator, badJobs, route, bestScoredJob.getInsertionData());
|
||||
}
|
||||
}
|
||||
for (ScoredJob bad : badJobList) {
|
||||
Job unassigned = bad.getJob();
|
||||
|
|
|
|||
|
|
@ -120,6 +120,10 @@ public class RegretInsertionConcurrent extends AbstractInsertionStrategy {
|
|||
}
|
||||
insertJob(bestScoredJob.getJob(), bestScoredJob.getInsertionData(), bestScoredJob.getRoute());
|
||||
jobs.remove(bestScoredJob.getJob());
|
||||
|
||||
if (bestScoredJob.isNewRoute() || !bestScoredJob.getRoute().getVehicle().getId().equals(bestScoredJob.getInsertionData().getSelectedVehicle().getId())) {
|
||||
insertBreak(insertionCostsCalculator, badJobs, bestScoredJob.getRoute(), bestScoredJob.getInsertionData());
|
||||
}
|
||||
}
|
||||
for (ScoredJob bad : badJobList) {
|
||||
Job unassigned = bad.getJob();
|
||||
|
|
|
|||
|
|
@ -156,6 +156,10 @@ public class RegretInsertionConcurrentFast extends AbstractInsertionStrategy {
|
|||
}
|
||||
insertJob(bestScoredJob.getJob(), bestScoredJob.getInsertionData(), bestScoredJob.getRoute());
|
||||
jobs.remove(bestScoredJob.getJob());
|
||||
|
||||
if (bestScoredJob.isNewRoute() || !bestScoredJob.getRoute().getVehicle().getId().equals(bestScoredJob.getInsertionData().getSelectedVehicle().getId())) {
|
||||
insertBreak(insertionCostsCalculator, badJobs, bestScoredJob.getRoute(), bestScoredJob.getInsertionData());
|
||||
}
|
||||
lastModified = bestScoredJob.getRoute();
|
||||
}
|
||||
else lastModified = null;
|
||||
|
|
|
|||
|
|
@ -153,6 +153,10 @@ public class RegretInsertionFast extends AbstractInsertionStrategy {
|
|||
}
|
||||
insertJob(bestScoredJob.getJob(), bestScoredJob.getInsertionData(), bestScoredJob.getRoute());
|
||||
jobs.remove(bestScoredJob.getJob());
|
||||
|
||||
if (bestScoredJob.isNewRoute() || !bestScoredJob.getRoute().getVehicle().getId().equals(bestScoredJob.getInsertionData().getSelectedVehicle().getId())) {
|
||||
insertBreak(insertionCostsCalculator, badJobs, bestScoredJob.getRoute(), bestScoredJob.getInsertionData());
|
||||
}
|
||||
lastModified = bestScoredJob.getRoute();
|
||||
}
|
||||
else lastModified = null;
|
||||
|
|
|
|||
|
|
@ -11,7 +11,9 @@ import org.junit.Test;
|
|||
import java.util.*;
|
||||
|
||||
import static com.graphhopper.jsprit.core.algorithm.module.RuinAndRecreateModule.getUnassignedJobs;
|
||||
import static com.graphhopper.jsprit.core.algorithm.module.RuinAndRecreateModule.removeEmptyRoutes;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
|
|
@ -39,4 +41,22 @@ public class RuinAndRecreateModuleTest {
|
|||
when(tourActivities.servesJob(aBreak)).thenReturn(false);
|
||||
assertEquals(1, getUnassignedJobs(new VehicleRoutingProblemSolution(routes, 212), unassigned).size());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testEmptyRoutesRemoved() {
|
||||
List<VehicleRoute> routes = new ArrayList<>();
|
||||
VehicleRoute vehicleRoute1 = mock(VehicleRoute.class);
|
||||
when(vehicleRoute1.isEmpty()).thenReturn(false);
|
||||
VehicleRoute vehicleRoute2 = mock(VehicleRoute.class);
|
||||
when(vehicleRoute2.isEmpty()).thenReturn(true);
|
||||
|
||||
routes.add(vehicleRoute1);
|
||||
routes.add(vehicleRoute2);
|
||||
|
||||
removeEmptyRoutes(routes);
|
||||
|
||||
assertEquals(routes.size(), 1);
|
||||
assertTrue(routes.contains(vehicleRoute1));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ 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.Break;
|
||||
import com.graphhopper.jsprit.core.problem.job.Job;
|
||||
import com.graphhopper.jsprit.core.problem.job.Service;
|
||||
import com.graphhopper.jsprit.core.problem.job.Shipment;
|
||||
|
|
@ -37,6 +38,7 @@ 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.BreakActivity;
|
||||
import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity;
|
||||
import com.graphhopper.jsprit.core.problem.vehicle.*;
|
||||
import com.graphhopper.jsprit.core.util.Coordinate;
|
||||
|
|
@ -46,6 +48,11 @@ import org.junit.Test;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.UUID;
|
||||
|
||||
import static com.graphhopper.jsprit.core.algorithm.box.Jsprit.Parameter.BREAK_SCHEDULING;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class RegretInsertionTest {
|
||||
|
||||
|
|
@ -125,6 +132,44 @@ public class RegretInsertionTest {
|
|||
Assert.assertEquals(2, solution.getRoutes().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void solutionHaveToBeWithBreak() {
|
||||
Service s1 = Service.Builder.newInstance("s1").setLocation(Location.newInstance(0, 10)).addTimeWindow(0, 50).build();
|
||||
Service s2 = Service.Builder.newInstance("s2").setLocation(Location.newInstance(0, -10)).addTimeWindow(0, 50).build();
|
||||
|
||||
VehicleImpl v1 = VehicleImpl.Builder.newInstance("v1").setStartLocation(Location.newInstance(0, 5))
|
||||
.setBreak(Break.Builder.newInstance(UUID.randomUUID().toString()).addTimeWindow(0, 10).build()).build();
|
||||
VehicleImpl v2 = VehicleImpl.Builder.newInstance("v2").setStartLocation(Location.newInstance(0, -5))
|
||||
.setBreak(Break.Builder.newInstance(UUID.randomUUID().toString()).addTimeWindow(0, 10).build()).build();
|
||||
final VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().addJob(s1).addJob(s2)
|
||||
.addVehicle(v1).addVehicle(v2).setFleetSize(VehicleRoutingProblem.FleetSize.FINITE).build();
|
||||
|
||||
optimizeAndValidate(vrp, Jsprit.Parameter.FAST_REGRET);
|
||||
}
|
||||
|
||||
private void optimizeAndValidate(VehicleRoutingProblem vrp, Jsprit.Parameter insertionStrategy) {
|
||||
StateManager stateManager = new StateManager(vrp);
|
||||
ConstraintManager constraintManager = new ConstraintManager(vrp,stateManager);
|
||||
VehicleRoutingAlgorithm vra = Jsprit.Builder.newInstance(vrp)
|
||||
.setProperty(BREAK_SCHEDULING, Boolean.FALSE.toString())
|
||||
.addCoreStateAndConstraintStuff(true)
|
||||
.setProperty(insertionStrategy, Boolean.TRUE.toString())
|
||||
.setStateAndConstraintManager(stateManager, constraintManager).buildAlgorithm();
|
||||
|
||||
VehicleRoutingProblemSolution solution = Solutions.bestOf(vra.searchSolutions());
|
||||
|
||||
Assert.assertEquals(2, solution.getRoutes().size());
|
||||
final Iterator<VehicleRoute> iterator = solution.getRoutes().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
final VehicleRoute route = iterator.next();
|
||||
boolean hasBreak = false;
|
||||
for (TourActivity activity : route.getActivities())
|
||||
if (activity instanceof BreakActivity)
|
||||
hasBreak = true;
|
||||
assertTrue(hasBreak);
|
||||
}
|
||||
}
|
||||
|
||||
static class JobInRouteUpdater implements StateUpdater, ActivityVisitor {
|
||||
|
||||
private StateManager stateManager;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue