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

InsertBreaksToNewRoutes (#42)

* InsertBreaksToNewRoutes

* fixes
This commit is contained in:
kandelirina 2018-03-25 09:53:52 +03:00 committed by kobyb
parent e94a76fd1c
commit 8b75937ca8
10 changed files with 132 additions and 7 deletions

View file

@ -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) {

View file

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

View file

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

View file

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

View file

@ -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();

View file

@ -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();

View file

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

View file

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

View file

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

View file

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