diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/ServiceInsertionCalculator.java b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/ServiceInsertionCalculator.java index ed09fb5c..db42247c 100644 --- a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/ServiceInsertionCalculator.java +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/ServiceInsertionCalculator.java @@ -1,16 +1,16 @@ /******************************************************************************* - * Copyright (C) 2013 Stefan Schroeder - * + * Copyright (C) 2014 Stefan Schroeder + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either + * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . ******************************************************************************/ @@ -88,20 +88,29 @@ final class ServiceInsertionCalculator implements JobInsertionCostsCalculator{ @Override public InsertionData getInsertionData(final VehicleRoute currentRoute, final Job jobToInsert, final Vehicle newVehicle, double newVehicleDepartureTime, final Driver newDriver, final double bestKnownCosts) { JobInsertionContext insertionContext = new JobInsertionContext(currentRoute, jobToInsert, newVehicle, newDriver, newVehicleDepartureTime); - if(!hardRouteLevelConstraint.fulfilled(insertionContext)){ + Service service = (Service)jobToInsert; + int insertionIndex = InsertionData.NO_INDEX; + TourActivity deliveryAct2Insert = activityFactory.createActivities(service).get(0); + insertionContext.getAssociatedActivities().add(deliveryAct2Insert); + + /* + check hard constraints at route level + */ + if(!hardRouteLevelConstraint.fulfilled(insertionContext)){ return InsertionData.createEmptyInsertionData(); } + + /* + check soft constraints at route level + */ + double additionalICostsAtRouteLevel = softRouteConstraint.getCosts(insertionContext); + double bestCost = bestKnownCosts; - - //from job2insert induced costs at route level - double additionalICostsAtRouteLevel = softRouteConstraint.getCosts(insertionContext); - additionalICostsAtRouteLevel += additionalAccessEgressCalculator.getCosts(insertionContext); - - Service service = (Service)jobToInsert; - int insertionIndex = InsertionData.NO_INDEX; - - TourActivity deliveryAct2Insert = activityFactory.createActivities(service).get(0); - + additionalICostsAtRouteLevel += additionalAccessEgressCalculator.getCosts(insertionContext); + + /* + generate new start and end for new vehicle + */ Start start = Start.newInstance(newVehicle.getStartLocationId(), newVehicle.getEarliestDeparture(), Double.MAX_VALUE); start.setEndTime(newVehicleDepartureTime); End end = End.newInstance(newVehicle.getEndLocationId(), 0.0, newVehicle.getLatestArrival()); diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/ShipmentInsertionCalculator.java b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/ShipmentInsertionCalculator.java index 80cc6a9c..33d8fa8e 100644 --- a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/ShipmentInsertionCalculator.java +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/ShipmentInsertionCalculator.java @@ -1,16 +1,16 @@ /******************************************************************************* - * Copyright (C) 2013 Stefan Schroeder - * + * Copyright (C) 2014 Stefan Schroeder + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either + * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . ******************************************************************************/ @@ -29,7 +29,6 @@ import jsprit.core.problem.solution.route.activity.End; import jsprit.core.problem.solution.route.activity.Start; import jsprit.core.problem.solution.route.activity.TourActivity; import jsprit.core.problem.vehicle.Vehicle; -import jsprit.core.problem.vehicle.VehicleImpl.NoVehicle; import jsprit.core.util.CalculationUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -87,32 +86,37 @@ final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator{ */ @Override public InsertionData getInsertionData(final VehicleRoute currentRoute, final Job jobToInsert, final Vehicle newVehicle, double newVehicleDepartureTime, final Driver newDriver, final double bestKnownCosts) { - if(jobToInsert == null) throw new IllegalStateException("jobToInsert is missing."); - if(newVehicle == null || newVehicle instanceof NoVehicle) throw new IllegalStateException("newVehicle is missing."); - if(!(jobToInsert instanceof Shipment)) throw new IllegalStateException("jobToInsert should be of type Shipment!"); - - JobInsertionContext insertionContext = new JobInsertionContext(currentRoute, jobToInsert, newVehicle, newDriver, newVehicleDepartureTime); - if(!hardRouteLevelConstraint.fulfilled(insertionContext)){ + JobInsertionContext insertionContext = new JobInsertionContext(currentRoute, jobToInsert, newVehicle, newDriver, newVehicleDepartureTime); + Shipment shipment = (Shipment)jobToInsert; + TourActivity pickupShipment = activityFactory.createActivities(shipment).get(0); + TourActivity deliverShipment = activityFactory.createActivities(shipment).get(1); + insertionContext.getAssociatedActivities().add(pickupShipment); + insertionContext.getAssociatedActivities().add(deliverShipment); + + /* + check hard route constraints + */ + if(!hardRouteLevelConstraint.fulfilled(insertionContext)){ return InsertionData.createEmptyInsertionData(); } - - double bestCost = bestKnownCosts; - - double additionalICostsAtRouteLevel = softRouteConstraint.getCosts(insertionContext); - additionalICostsAtRouteLevel += additionalAccessEgressCalculator.getCosts(insertionContext); - - Shipment shipment = (Shipment)jobToInsert; - TourActivity pickupShipment = activityFactory.createActivities(shipment).get(0); - TourActivity deliverShipment = activityFactory.createActivities(shipment).get(1); - - int pickupInsertionIndex = InsertionData.NO_INDEX; + /* + check soft route constraints + */ + double additionalICostsAtRouteLevel = softRouteConstraint.getCosts(insertionContext); + + double bestCost = bestKnownCosts; + additionalICostsAtRouteLevel += additionalAccessEgressCalculator.getCosts(insertionContext); + + int pickupInsertionIndex = InsertionData.NO_INDEX; int deliveryInsertionIndex = InsertionData.NO_INDEX; Start start = Start.newInstance(newVehicle.getStartLocationId(), newVehicle.getEarliestDeparture(), newVehicle.getLatestArrival()); start.setEndTime(newVehicleDepartureTime); End end = End.newInstance(newVehicle.getEndLocationId(), 0.0, newVehicle.getLatestArrival()); - + + JobInsertionContext.ActivityContext pickupContext = new JobInsertionContext.ActivityContext(); + TourActivity prevAct = start; double prevActEndTime = newVehicleDepartureTime; boolean pickupShipmentLoopBroken = false; @@ -135,7 +139,13 @@ final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator{ TourActivity prevAct_deliveryLoop = pickupShipment; double shipmentPickupArrTime = prevActEndTime + transportCosts.getTransportTime(prevAct.getLocationId(), pickupShipment.getLocationId(), prevActEndTime, newDriver, newVehicle); double shipmentPickupEndTime = CalculationUtils.getActivityEndTime(shipmentPickupArrTime, pickupShipment); - double prevActEndTime_deliveryLoop = shipmentPickupEndTime; + + pickupContext.setArrivalTime(shipmentPickupArrTime); + pickupContext.setEndTime(shipmentPickupEndTime); + pickupContext.setInsertionIndex(i); + insertionContext.setRelatedActivityContext(pickupContext); + + double prevActEndTime_deliveryLoop = shipmentPickupEndTime; boolean deliverShipmentLoopBroken = false; //deliverShipmentLoop for(int j=i;j. ******************************************************************************/ @@ -19,17 +19,68 @@ package jsprit.core.problem.misc; import jsprit.core.problem.driver.Driver; import jsprit.core.problem.job.Job; import jsprit.core.problem.solution.route.VehicleRoute; +import jsprit.core.problem.solution.route.activity.TourActivity; import jsprit.core.problem.vehicle.Vehicle; +import java.util.ArrayList; +import java.util.List; + +/** + * Provides context information about a particular job insertion. + * + */ public class JobInsertionContext { + + public static class ActivityContext { + + private double arrivalTime; + + private double endTime; + + private int insertionIndex; + + public double getArrivalTime() { + return arrivalTime; + } + + public double getEndTime() { + return endTime; + } + + public int getInsertionIndex() { + return insertionIndex; + } + + public void setArrivalTime(double arrivalTime) { + this.arrivalTime = arrivalTime; + } + + public void setEndTime(double endTime) { + this.endTime = endTime; + } + + public void setInsertionIndex(int insertionIndex) { + this.insertionIndex = insertionIndex; + } + } private VehicleRoute route; + private Job job; + private Vehicle newVehicle; + private Driver newDriver; + private double newDepTime; + + private List associatedActivities = new ArrayList(); + + private ActivityContext pickupContext; /** + * Returns the existing route where the .getJob() needs to be inserted in. + * * @return the route */ public VehicleRoute getRoute() { @@ -37,6 +88,8 @@ public class JobInsertionContext { } /** + * Returns the job that needs to be inserted. + * * @return the job */ public Job getJob() { @@ -44,6 +97,8 @@ public class JobInsertionContext { } /** + * Returns the vehicle that should operate the new route, i.e. route this.getRoute() + new job this.getJob(). + * * @return the newVehicle */ public Vehicle getNewVehicle() { @@ -51,6 +106,10 @@ public class JobInsertionContext { } /** + * Returns the driver that should operate the new route, i.e. route this.getRoute() + new job this.getJob(). + * + *

Currently the driver is just a mock, it has no functions

+ * * @return the newDriver */ public Driver getNewDriver() { @@ -58,14 +117,24 @@ public class JobInsertionContext { } /** + * Returns the new departure time at the new vehicle's start location. + * * @return the newDepTime */ public double getNewDepTime() { return newDepTime; } - public JobInsertionContext(VehicleRoute route, Job job, Vehicle newVehicle, - Driver newDriver, double newDepTime) { + /** + * Constructs the context. + * + * @param route the existing route where the job needs to be inserted in + * @param job the job to be inserted + * @param newVehicle the new vehicle that should operate the new route + * @param newDriver the new driver that should operate the new route + * @param newDepTime the new departure time at the new vehicle's start location + */ + public JobInsertionContext(VehicleRoute route, Job job, Vehicle newVehicle, Driver newDriver, double newDepTime) { super(); this.route = route; this.job = job; @@ -73,7 +142,26 @@ public class JobInsertionContext { this.newDriver = newDriver; this.newDepTime = newDepTime; } - - + public List getAssociatedActivities() { + return associatedActivities; + } + + /** + * Sets pickup context. + * + * @param pickupContext pickup context + */ + public void setRelatedActivityContext(ActivityContext pickupContext){ + this.pickupContext = pickupContext; + } + + /** + * Returns pickup context. If no context available, returns null. + * + * @return pickup context + */ + public ActivityContext getRelatedActivityContext(){ + return this.pickupContext; + } } diff --git a/jsprit-core/src/test/java/jsprit/core/problem/misc/JobInsertionContextTest.java b/jsprit-core/src/test/java/jsprit/core/problem/misc/JobInsertionContextTest.java new file mode 100644 index 00000000..91b04b6e --- /dev/null +++ b/jsprit-core/src/test/java/jsprit/core/problem/misc/JobInsertionContextTest.java @@ -0,0 +1,95 @@ +/******************************************************************************* + * Copyright (C) 2014 Stefan Schroeder + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + ******************************************************************************/ + +package jsprit.core.problem.misc; + + +import jsprit.core.problem.driver.Driver; +import jsprit.core.problem.job.Job; +import jsprit.core.problem.solution.route.VehicleRoute; +import jsprit.core.problem.solution.route.activity.TourActivity; +import jsprit.core.problem.vehicle.Vehicle; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.mockito.Mockito.mock; + +public class JobInsertionContextTest { + + VehicleRoute route; + + Job job; + + Vehicle vehicle; + + Driver driver; + + double depTime; + + JobInsertionContext context; + + @Before + public void doBefore(){ + route = mock(VehicleRoute.class); + job = mock(Job.class); + vehicle = mock(Vehicle.class); + driver = mock(Driver.class); + depTime = 0.; + context = new JobInsertionContext(route,job,vehicle,driver,depTime); + } + + @Test + public void routeShouldBeAssigned(){ + assertEquals(route,context.getRoute()); + } + + @Test + public void jobShouldBeAssigned(){ + assertEquals(job,context.getJob()); + } + + @Test + public void vehicleShouldBeAssigned(){ + assertEquals(vehicle,context.getNewVehicle()); + } + + @Test + public void driverShouldBeAssigned(){ + assertEquals(driver,context.getNewDriver()); + } + + @Test + public void depTimeShouldBeAssigned(){ + assertEquals(0.,context.getNewDepTime(),0.001); + } + + @Test + public void relatedActivitiesShouldBeAssigned(){ + context.getAssociatedActivities().add(mock(TourActivity.class)); + context.getAssociatedActivities().add(mock(TourActivity.class)); + assertEquals(2,context.getAssociatedActivities().size()); + } + + @Test + public void relatedActivityContextShouldBeAssigned(){ + context.setRelatedActivityContext(mock(JobInsertionContext.ActivityContext.class)); + assertNotNull(context.getRelatedActivityContext()); + } + +}