diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/AuxilliaryCostCalculator.java b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/AuxilliaryCostCalculator.java index 0010f9f5..5a777506 100644 --- a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/AuxilliaryCostCalculator.java +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/AuxilliaryCostCalculator.java @@ -39,15 +39,15 @@ final class AuxilliaryCostCalculator { this.routingCosts = routingCosts; this.activityCosts = actCosts; } - - /** - * - * @param path - * @param depTime - * @param driver - * @param vehicle - * @return - */ + + /** + * + * @param path activity path to get the costs for + * @param depTime departure time at first activity in path + * @param driver driver of vehicle + * @param vehicle vehicle running the path + * @return cost of path + */ public double costOfPath(final List path, final double depTime, final Driver driver, final Vehicle vehicle){ if(path.isEmpty()){ return 0.0; @@ -69,9 +69,7 @@ final class AuxilliaryCostCalculator { double transportTime = routingCosts.getTransportTime(prevAct.getLocationId(), act.getLocationId(), departureTimePrevAct, driver, vehicle); cost += transportCost; double actStartTime = departureTimePrevAct + transportTime; - double earliestOperationStartTime = Math.max(actStartTime, act.getTheoreticalEarliestOperationStartTime()); - double actEndTime = earliestOperationStartTime + act.getOperationTime(); - departureTimePrevAct = actEndTime; + departureTimePrevAct = Math.max(actStartTime, act.getTheoreticalEarliestOperationStartTime()) + act.getOperationTime(); cost += activityCosts.getActivityCost(act, actStartTime, driver, vehicle); prevAct = act; } diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/CalculatorBuilder.java b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/CalculatorBuilder.java index c87c2834..b1d4ec8d 100644 --- a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/CalculatorBuilder.java +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/CalculatorBuilder.java @@ -296,10 +296,11 @@ class CalculatorBuilder { } private CalculatorPlusListeners createStandardRoute(VehicleRoutingProblem vrp, RouteAndActivityStateGetter activityStates2, int forwardLooking, int solutionMemory){ - int after = forwardLooking; ActivityInsertionCostsCalculator routeLevelCostEstimator; if(activityInsertionCostCalculator == null && addDefaultCostCalc){ - routeLevelCostEstimator = new RouteLevelActivityInsertionCostsEstimator(vrp.getTransportCosts(), vrp.getActivityCosts(), activityStates2); + RouteLevelActivityInsertionCostsEstimator routeLevelActivityInsertionCostsEstimator = new RouteLevelActivityInsertionCostsEstimator(vrp.getTransportCosts(), vrp.getActivityCosts(), activityStates2); + routeLevelActivityInsertionCostsEstimator.setForwardLooking(forwardLooking); + routeLevelCostEstimator = routeLevelActivityInsertionCostsEstimator; } else if(activityInsertionCostCalculator == null && !addDefaultCostCalc){ routeLevelCostEstimator = new ActivityInsertionCostsCalculator(){ @@ -318,7 +319,7 @@ class CalculatorBuilder { routeLevelCostEstimator = activityInsertionCostCalculator; } JobInsertionCostsCalculator jobInsertionCalculator = new ServiceInsertionOnRouteLevelCalculator(vrp.getTransportCosts(), vrp.getActivityCosts(), routeLevelCostEstimator, constraintManager, constraintManager); - ((ServiceInsertionOnRouteLevelCalculator)jobInsertionCalculator).setNuOfActsForwardLooking(after); + ((ServiceInsertionOnRouteLevelCalculator)jobInsertionCalculator).setNuOfActsForwardLooking(forwardLooking); ((ServiceInsertionOnRouteLevelCalculator)jobInsertionCalculator).setMemorySize(solutionMemory); ((ServiceInsertionOnRouteLevelCalculator) jobInsertionCalculator).setStates(activityStates2); diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/RouteLevelActivityInsertionCostsEstimator.java b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/RouteLevelActivityInsertionCostsEstimator.java index d15d8d85..95f09735 100644 --- a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/RouteLevelActivityInsertionCostsEstimator.java +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/RouteLevelActivityInsertionCostsEstimator.java @@ -57,14 +57,13 @@ class RouteLevelActivityInsertionCostsEstimator implements ActivityInsertionCost path.add(prevAct); path.add(newAct); path.add(nextAct); int actIndex; if(prevAct instanceof Start) actIndex = 0; - else actIndex = iFacts.getRoute().getTourActivities().getActivities().indexOf(prevAct); + else actIndex = iFacts.getRoute().getTourActivities().getActivities().indexOf(nextAct); if(nuOfActivities2LookForward > 0){ path.addAll(getForwardLookingPath(iFacts.getRoute(),actIndex)); } - /** + /* * calculates the path costs with new vehicle, c(forwardPath,newVehicle). */ - double forwardPathCost_newVehicle = auxilliaryPathCostCalculator.costOfPath(path, depTimeAtPrevAct, iFacts.getNewDriver(), iFacts.getNewVehicle()); - + double forwardPathCost_newVehicle = auxilliaryPathCostCalculator.costOfPath(path, depTimeAtPrevAct, iFacts.getNewDriver(), iFacts.getNewVehicle()); double additionalCosts = forwardPathCost_newVehicle - (actCostsOld(iFacts.getRoute(), path.get(path.size()-1)) - actCostsOld(iFacts.getRoute(), prevAct)); return new ActivityInsertionCosts(additionalCosts, 0.0); @@ -93,4 +92,7 @@ class RouteLevelActivityInsertionCostsEstimator implements ActivityInsertionCost return forwardLookingPath; } + public void setForwardLooking(int nActivities) { + this.nuOfActivities2LookForward = nActivities; + } } diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/ServiceInsertionOnRouteLevelCalculator.java b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/ServiceInsertionOnRouteLevelCalculator.java index e943e7f9..18e55a53 100644 --- a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/ServiceInsertionOnRouteLevelCalculator.java +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/ServiceInsertionOnRouteLevelCalculator.java @@ -72,31 +72,17 @@ final class ServiceInsertionOnRouteLevelCalculator implements JobInsertionCostsC private ActivityInsertionCostsCalculator activityInsertionCostsCalculator; private int nuOfActsForwardLooking = 0; - +// private int memorySize = 2; private Start start; private End end; - - private Neighborhood neighborhood = new Neighborhood() { - - @Override - public boolean areNeighbors(String location1, String location2) { - return true; - } - - }; - + public void setTourActivityFactory(TourActivityFactory tourActivityFactory){ this.tourActivityFactory=tourActivityFactory; } - - public void setNeighborhood(Neighborhood neighborhood) { - this.neighborhood = neighborhood; - logger.info("initialise neighborhood " + neighborhood); - } - + public void setMemorySize(int memorySize) { this.memorySize = memorySize; logger.info("set [solutionMemory="+memorySize+"]"); @@ -182,35 +168,34 @@ final class ServiceInsertionOnRouteLevelCalculator implements JobInsertionCostsC * k=serviceAct2Insert */ for(TourActivity nextAct : tour.getActivities()){ - if(neighborhood.areNeighbors(serviceAct2Insert.getLocationId(), prevAct.getLocationId()) && neighborhood.areNeighbors(serviceAct2Insert.getLocationId(), nextAct.getLocationId())){ - ConstraintsStatus status = hardActivityLevelConstraint.fulfilled(insertionContext, prevAct, serviceAct2Insert, nextAct, prevActDepTime_newVehicle); - if(status.equals(ConstraintsStatus.FULFILLED)){ - /** - * builds a path on this route forwardPath={i,k,j,j+1,j+2,...,j+nuOfActsForwardLooking} - */ - ActivityInsertionCosts actInsertionCosts = activityInsertionCostsCalculator.getCosts(insertionContext, prevAct, nextAct, serviceAct2Insert, prevActDepTime_newVehicle); + ConstraintsStatus hardActivityConstraintsStatus = hardActivityLevelConstraint.fulfilled(insertionContext, prevAct, serviceAct2Insert, nextAct, prevActDepTime_newVehicle); + if(hardActivityConstraintsStatus.equals(ConstraintsStatus.FULFILLED)){ + /** + * builds a path on this route forwardPath={i,k,j,j+1,j+2,...,j+nuOfActsForwardLooking} + */ + ActivityInsertionCosts actInsertionCosts = activityInsertionCostsCalculator.getCosts(insertionContext, prevAct, nextAct, serviceAct2Insert, prevActDepTime_newVehicle); - /** - * insertion_cost_approximation = c({0,1,...,i},newVehicle) + c({i,k,j,j+1,j+2,...,j+nuOfActsForwardLooking},newVehicle) - c({0,1,...,i,j,j+1,...,j+nuOfActsForwardLooking},oldVehicle) - */ - double insertion_cost_approximation = sumOf_prevCosts_newVehicle - sumOf_prevCosts_oldVehicle(currentRoute,prevAct) + actInsertionCosts.getAdditionalCosts(); + /** + * insertion_cost_approximation = c({0,1,...,i},newVehicle) + c({i,k,j,j+1,j+2,...,j+nuOfActsForwardLooking},newVehicle) - c({0,1,...,i,j,j+1,...,j+nuOfActsForwardLooking},oldVehicle) + */ + double insertion_cost_approximation = sumOf_prevCosts_newVehicle - sumOf_prevCosts_oldVehicle(currentRoute,prevAct) + actInsertionCosts.getAdditionalCosts(); - /** - * memorize it in insertion-queue - */ - if(insertion_cost_approximation < best_known_insertion_costs){ - bestInsertionsQueue.add(new InsertionData(insertion_cost_approximation, InsertionData.NO_INDEX, actIndex, newVehicle, newDriver)); - } - } - else if(status.equals(ConstraintsStatus.NOT_FULFILLED_BREAK)){ - loopBroken = true; - break; - } - } + /** + * memorize it in insertion-queue + */ + if(insertion_cost_approximation < best_known_insertion_costs){ + bestInsertionsQueue.add(new InsertionData(insertion_cost_approximation, InsertionData.NO_INDEX, actIndex, newVehicle, newDriver)); + } + } + else if(hardActivityConstraintsStatus.equals(ConstraintsStatus.NOT_FULFILLED_BREAK)){ + loopBroken = true; + break; + } - /** - * calculate transport and activity costs with new vehicle (without inserting k) - */ + + /** + * calculate transport and activity costs with new vehicle (without inserting k) + */ double transportCost_prevAct_nextAct_newVehicle = transportCosts.getTransportCost(prevAct.getLocationId(), nextAct.getLocationId(), prevActDepTime_newVehicle, newDriver, newVehicle); double transportTime_prevAct_nextAct_newVehicle = transportCosts.getTransportTime(prevAct.getLocationId(), nextAct.getLocationId(), prevActDepTime_newVehicle, newDriver, newVehicle); double arrTime_nextAct_newVehicle = prevActDepTime_newVehicle + transportTime_prevAct_nextAct_newVehicle; @@ -237,26 +222,24 @@ final class ServiceInsertionOnRouteLevelCalculator implements JobInsertionCostsC } if(!loopBroken){ End nextAct = end; - if(neighborhood.areNeighbors(serviceAct2Insert.getLocationId(), prevAct.getLocationId()) && neighborhood.areNeighbors(serviceAct2Insert.getLocationId(), nextAct.getLocationId())){ - ConstraintsStatus status = hardActivityLevelConstraint.fulfilled(insertionContext, prevAct, serviceAct2Insert, nextAct, prevActDepTime_newVehicle); - if(status.equals(ConstraintsStatus.FULFILLED)){ - ActivityInsertionCosts actInsertionCosts = activityInsertionCostsCalculator.getCosts(insertionContext, prevAct, nextAct, serviceAct2Insert, prevActDepTime_newVehicle); - if(actInsertionCosts != null){ - /** - * insertion_cost_approximation = c({0,1,...,i},newVehicle) + c({i,k,j,j+1,j+2,...,j+nuOfActsForwardLooking},newVehicle) - c({0,1,...,i,j,j+1,...,j+nuOfActsForwardLooking},oldVehicle) - */ - double insertion_cost_approximation = sumOf_prevCosts_newVehicle - sumOf_prevCosts_oldVehicle(currentRoute,prevAct) + actInsertionCosts.getAdditionalCosts(); + ConstraintsStatus hardActivityConstraintsStatus = hardActivityLevelConstraint.fulfilled(insertionContext, prevAct, serviceAct2Insert, nextAct, prevActDepTime_newVehicle); + if(hardActivityConstraintsStatus.equals(ConstraintsStatus.FULFILLED)){ + ActivityInsertionCosts actInsertionCosts = activityInsertionCostsCalculator.getCosts(insertionContext, prevAct, nextAct, serviceAct2Insert, prevActDepTime_newVehicle); + if(actInsertionCosts != null){ + /** + * insertion_cost_approximation = c({0,1,...,i},newVehicle) + c({i,k,j,j+1,j+2,...,j+nuOfActsForwardLooking},newVehicle) - c({0,1,...,i,j,j+1,...,j+nuOfActsForwardLooking},oldVehicle) + */ + double insertion_cost_approximation = sumOf_prevCosts_newVehicle - sumOf_prevCosts_oldVehicle(currentRoute,prevAct) + actInsertionCosts.getAdditionalCosts(); - /** - * memorize it in insertion-queue - */ - if(insertion_cost_approximation < best_known_insertion_costs){ - bestInsertionsQueue.add(new InsertionData(insertion_cost_approximation, InsertionData.NO_INDEX, actIndex, newVehicle, newDriver)); - } - } - } - } - } + /** + * memorize it in insertion-queue + */ + if(insertion_cost_approximation < best_known_insertion_costs){ + bestInsertionsQueue.add(new InsertionData(insertion_cost_approximation, InsertionData.NO_INDEX, actIndex, newVehicle, newDriver)); + } + } + } + } /** diff --git a/jsprit-core/src/test/java/jsprit/core/algorithm/recreate/TestRouteLevelActivityInsertionCostEstimator.java b/jsprit-core/src/test/java/jsprit/core/algorithm/recreate/TestRouteLevelActivityInsertionCostEstimator.java new file mode 100644 index 00000000..30916e6d --- /dev/null +++ b/jsprit-core/src/test/java/jsprit/core/algorithm/recreate/TestRouteLevelActivityInsertionCostEstimator.java @@ -0,0 +1,158 @@ +package jsprit.core.algorithm.recreate; + +import jsprit.core.algorithm.state.StateManager; +import jsprit.core.algorithm.state.UpdateVariableCosts; +import jsprit.core.problem.cost.VehicleRoutingActivityCosts; +import jsprit.core.problem.cost.VehicleRoutingTransportCosts; +import jsprit.core.problem.driver.Driver; +import jsprit.core.problem.job.Job; +import jsprit.core.problem.job.Service; +import jsprit.core.problem.misc.JobInsertionContext; +import jsprit.core.problem.solution.route.VehicleRoute; +import jsprit.core.problem.solution.route.activity.PickupActivity; +import jsprit.core.problem.solution.route.activity.PickupService; +import jsprit.core.problem.solution.route.activity.TimeWindow; +import jsprit.core.problem.solution.route.activity.TourActivity; +import jsprit.core.problem.vehicle.Vehicle; +import jsprit.core.problem.vehicle.VehicleImpl; +import jsprit.core.problem.vehicle.VehicleType; +import jsprit.core.problem.vehicle.VehicleTypeImpl; +import jsprit.core.util.CostFactory; +import org.junit.Before; +import org.junit.Test; + +import java.util.Arrays; +import java.util.Collections; + +import static org.junit.Assert.assertEquals; + +/** + * Created by schroeder on 02.07.14. + */ +public class TestRouteLevelActivityInsertionCostEstimator { + + private VehicleRoute route; + + private VehicleRoutingTransportCosts routingCosts; + + private VehicleRoutingActivityCosts activityCosts; + + private StateManager stateManager; + + @Before + public void doBefore(){ + routingCosts = CostFactory.createEuclideanCosts(); + + activityCosts = new VehicleRoutingActivityCosts() { + + @Override + public double getActivityCost(TourActivity tourAct, double arrivalTime, Driver driver, Vehicle vehicle) { + return Math.max(0.,arrivalTime - tourAct.getTheoreticalLatestOperationStartTime()); + } + + }; + Service s1 = Service.Builder.newInstance("s1").setLocationId("10,0").setTimeWindow(TimeWindow.newInstance(10.,10.)).build(); + Service s2 = Service.Builder.newInstance("s2").setLocationId("20,0").setTimeWindow(TimeWindow.newInstance(20.,20.)).build(); + Service s3 = Service.Builder.newInstance("s3").setLocationId("30,0").setTimeWindow(TimeWindow.newInstance(30.,30.)).build(); + + VehicleType type = VehicleTypeImpl.Builder.newInstance("type").build(); + Vehicle vehicle = VehicleImpl.Builder.newInstance("vehicle").setStartLocationId("0,0").setType(type).build(); + + route = VehicleRoute.Builder.newInstance(vehicle).addService(s1).addService(s2).addService(s3).build(); + + stateManager = new StateManager(routingCosts); + stateManager.addStateUpdater(new UpdateVariableCosts(activityCosts,routingCosts,stateManager)); + stateManager.informInsertionStarts(Arrays.asList(route), Collections.emptyList()); + } + + @Test + public void whenNewActInBetweenFirstAndSecond_and_forwardLookingIs0_itShouldReturnCorrectCosts(){ + Service s4 = Service.Builder.newInstance("s4").setLocationId("5,0").build(); + PickupActivity pickupService = new PickupService(s4); + JobInsertionContext context = new JobInsertionContext(route,s4,route.getVehicle(),route.getDriver(),0.); + RouteLevelActivityInsertionCostsEstimator estimator = new RouteLevelActivityInsertionCostsEstimator(routingCosts,activityCosts,stateManager); + estimator.setForwardLooking(0); + ActivityInsertionCostsCalculator.ActivityInsertionCosts iCosts = estimator.getCosts(context, route.getStart(), route.getActivities().get(0), pickupService, 0.); + assertEquals(0.,iCosts.getAdditionalCosts(),0.01); + } + + @Test + public void whenNewActWithTWInBetweenFirstAndSecond_and_forwardLookingIs0_itShouldReturnCorrectCosts(){ + Service s4 = Service.Builder.newInstance("s4").setLocationId("5,0").setTimeWindow(TimeWindow.newInstance(5.,5.)).build(); + PickupActivity pickupService = new PickupService(s4); + JobInsertionContext context = new JobInsertionContext(route,s4,route.getVehicle(),route.getDriver(),0.); + RouteLevelActivityInsertionCostsEstimator estimator = new RouteLevelActivityInsertionCostsEstimator(routingCosts,activityCosts,stateManager); + estimator.setForwardLooking(0); + ActivityInsertionCostsCalculator.ActivityInsertionCosts iCosts = estimator.getCosts(context, route.getStart(), route.getActivities().get(0), pickupService, 0.); + assertEquals(0.,iCosts.getAdditionalCosts(),0.01); + } + + @Test + public void whenNewActWithTWAndServiceTimeInBetweenFirstAndSecond_and_forwardLookingIs0_itShouldReturnCorrectCosts(){ + Service s4 = Service.Builder.newInstance("s4").setLocationId("5,0").setServiceTime(10.).setTimeWindow(TimeWindow.newInstance(5.,5.)).build(); + PickupActivity pickupService = new PickupService(s4); + JobInsertionContext context = new JobInsertionContext(route,s4,route.getVehicle(),route.getDriver(),0.); + RouteLevelActivityInsertionCostsEstimator estimator = new RouteLevelActivityInsertionCostsEstimator(routingCosts,activityCosts,stateManager); + estimator.setForwardLooking(0); + ActivityInsertionCostsCalculator.ActivityInsertionCosts iCosts = estimator.getCosts(context, route.getStart(), route.getActivities().get(0), pickupService, 0.); + double expectedTransportCosts = 0.; + double expectedActivityCosts = 10.; + assertEquals(expectedActivityCosts+expectedTransportCosts,iCosts.getAdditionalCosts(),0.01); + } + + @Test + public void whenNewActWithTWAndServiceTimeInBetweenFirstAndSecond_and_forwardLookingIs3_itShouldReturnCorrectCosts(){ + Service s4 = Service.Builder.newInstance("s4").setLocationId("5,0").setServiceTime(10.).setTimeWindow(TimeWindow.newInstance(5.,5.)).build(); + PickupActivity pickupService = new PickupService(s4); + JobInsertionContext context = new JobInsertionContext(route,s4,route.getVehicle(),route.getDriver(),0.); + RouteLevelActivityInsertionCostsEstimator estimator = new RouteLevelActivityInsertionCostsEstimator(routingCosts,activityCosts,stateManager); + estimator.setForwardLooking(3); + ActivityInsertionCostsCalculator.ActivityInsertionCosts iCosts = estimator.getCosts(context, route.getStart(), route.getActivities().get(0), pickupService, 0.); + double expectedTransportCosts = 0.; + double expectedActivityCosts = 30.; + assertEquals(expectedActivityCosts+expectedTransportCosts,iCosts.getAdditionalCosts(),0.01); + } + + @Test + public void whenNewActInBetweenSecondAndThird_and_forwardLookingIs0_itShouldReturnCorrectCosts(){ + Service s4 = Service.Builder.newInstance("s4").setLocationId("5,0").build(); + PickupActivity pickupService = new PickupService(s4); + JobInsertionContext context = new JobInsertionContext(route,s4,route.getVehicle(),route.getDriver(),0.); + RouteLevelActivityInsertionCostsEstimator estimator = new RouteLevelActivityInsertionCostsEstimator(routingCosts,activityCosts,stateManager); + estimator.setForwardLooking(0); + ActivityInsertionCostsCalculator.ActivityInsertionCosts iCosts = + estimator.getCosts(context, route.getActivities().get(0), route.getActivities().get(1), pickupService, 10.); + double expectedTransportCosts = 10.; + double expectedActivityCosts = 10.; + assertEquals(expectedTransportCosts+expectedActivityCosts,iCosts.getAdditionalCosts(),0.01); + } + + @Test + public void whenNewActInBetweenSecondAndThird_and_forwardLookingIs3_itShouldReturnCorrectCosts(){ + Service s4 = Service.Builder.newInstance("s4").setLocationId("5,0").build(); + PickupActivity pickupService = new PickupService(s4); + JobInsertionContext context = new JobInsertionContext(route,s4,route.getVehicle(),route.getDriver(),0.); + RouteLevelActivityInsertionCostsEstimator estimator = new RouteLevelActivityInsertionCostsEstimator(routingCosts,activityCosts,stateManager); + estimator.setForwardLooking(3); + ActivityInsertionCostsCalculator.ActivityInsertionCosts iCosts = + estimator.getCosts(context, route.getActivities().get(0), route.getActivities().get(1), pickupService, 10.); + double expectedTransportCosts = 10.; + double expectedActivityCosts = 10.+10.; + assertEquals(expectedTransportCosts+expectedActivityCosts,iCosts.getAdditionalCosts(),0.01); + } + + @Test + public void whenNewActWithTWInBetweenSecondAndThird_and_forwardLookingIs3_itShouldReturnCorrectCosts(){ + Service s4 = Service.Builder.newInstance("s4").setLocationId("5,0").setTimeWindow(TimeWindow.newInstance(5.,5.)).build(); + PickupActivity pickupService = new PickupService(s4); + JobInsertionContext context = new JobInsertionContext(route,s4,route.getVehicle(),route.getDriver(),0.); + RouteLevelActivityInsertionCostsEstimator estimator = new RouteLevelActivityInsertionCostsEstimator(routingCosts,activityCosts,stateManager); + estimator.setForwardLooking(3); + ActivityInsertionCostsCalculator.ActivityInsertionCosts iCosts = + estimator.getCosts(context, route.getActivities().get(0), route.getActivities().get(1), pickupService, 10.); + double expectedTransportCosts = 10.; + double expectedActivityCosts = 10.+10.+10.; + assertEquals(expectedTransportCosts+expectedActivityCosts,iCosts.getAdditionalCosts(),0.01); + } + +} diff --git a/jsprit-core/src/test/java/jsprit/core/algorithm/recreate/TestRouteLevelServiceInsertionCostEstimator.java b/jsprit-core/src/test/java/jsprit/core/algorithm/recreate/TestRouteLevelServiceInsertionCostEstimator.java new file mode 100644 index 00000000..78507052 --- /dev/null +++ b/jsprit-core/src/test/java/jsprit/core/algorithm/recreate/TestRouteLevelServiceInsertionCostEstimator.java @@ -0,0 +1,155 @@ +package jsprit.core.algorithm.recreate; + +import jsprit.core.algorithm.state.StateManager; +import jsprit.core.algorithm.state.UpdateVariableCosts; +import jsprit.core.problem.VehicleRoutingProblem; +import jsprit.core.problem.constraint.ConstraintManager; +import jsprit.core.problem.cost.VehicleRoutingActivityCosts; +import jsprit.core.problem.cost.VehicleRoutingTransportCosts; +import jsprit.core.problem.driver.Driver; +import jsprit.core.problem.job.Job; +import jsprit.core.problem.job.Service; +import jsprit.core.problem.misc.JobInsertionContext; +import jsprit.core.problem.solution.route.VehicleRoute; +import jsprit.core.problem.solution.route.activity.PickupActivity; +import jsprit.core.problem.solution.route.activity.PickupService; +import jsprit.core.problem.solution.route.activity.TimeWindow; +import jsprit.core.problem.solution.route.activity.TourActivity; +import jsprit.core.problem.vehicle.Vehicle; +import jsprit.core.problem.vehicle.VehicleImpl; +import jsprit.core.problem.vehicle.VehicleType; +import jsprit.core.problem.vehicle.VehicleTypeImpl; +import jsprit.core.util.CostFactory; +import org.junit.Before; +import org.junit.Test; + +import java.util.Arrays; +import java.util.Collections; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * Created by schroeder on 02.07.14. + */ +public class TestRouteLevelServiceInsertionCostEstimator { + + private VehicleRoute route; + + private VehicleRoutingTransportCosts routingCosts; + + private VehicleRoutingActivityCosts activityCosts; + + private StateManager stateManager; + + private ConstraintManager constraintManager; + + @Before + public void doBefore(){ + routingCosts = CostFactory.createEuclideanCosts(); + + activityCosts = new VehicleRoutingActivityCosts() { + + @Override + public double getActivityCost(TourActivity tourAct, double arrivalTime, Driver driver, Vehicle vehicle) { + return Math.max(0.,arrivalTime - tourAct.getTheoreticalLatestOperationStartTime()); + } + + }; + Service s1 = Service.Builder.newInstance("s1").setLocationId("10,0").setTimeWindow(TimeWindow.newInstance(10.,10.)).build(); + Service s2 = Service.Builder.newInstance("s2").setLocationId("20,0").setTimeWindow(TimeWindow.newInstance(20.,20.)).build(); + Service s3 = Service.Builder.newInstance("s3").setLocationId("30,0").setTimeWindow(TimeWindow.newInstance(30.,30.)).build(); + + VehicleType type = VehicleTypeImpl.Builder.newInstance("type").build(); + Vehicle vehicle = VehicleImpl.Builder.newInstance("vehicle").setStartLocationId("0,0").setType(type).build(); + + route = VehicleRoute.Builder.newInstance(vehicle).addService(s1).addService(s2).addService(s3).build(); + + stateManager = new StateManager(routingCosts); + stateManager.addStateUpdater(new UpdateVariableCosts(activityCosts,routingCosts,stateManager)); + stateManager.informInsertionStarts(Arrays.asList(route), Collections.emptyList()); + + VehicleRoutingProblem vrp = mock(VehicleRoutingProblem.class); + when(vrp.getTransportCosts()).thenReturn(routingCosts); + + constraintManager = new ConstraintManager(vrp,stateManager); + } + + @Test + public void whenNewServiceNeedToBeInserted_itShouldReturnCorrectInsertionCosts(){ + Service s4 = Service.Builder.newInstance("s4").setLocationId("5,0").setTimeWindow(TimeWindow.newInstance(5.,5.)).build(); +// PickupActivity pickupService = new PickupService(s4); + JobInsertionContext context = new JobInsertionContext(route,s4,route.getVehicle(),route.getDriver(),0.); + RouteLevelActivityInsertionCostsEstimator estimator = new RouteLevelActivityInsertionCostsEstimator(routingCosts,activityCosts,stateManager); + estimator.setForwardLooking(0); + ServiceInsertionOnRouteLevelCalculator routeInserter = new ServiceInsertionOnRouteLevelCalculator(routingCosts, + activityCosts,estimator,constraintManager,constraintManager); + routeInserter.setStates(stateManager); + InsertionData iData = routeInserter.getInsertionData(route,s4,route.getVehicle(),route.getDepartureTime(),route.getDriver(),Double.MAX_VALUE); + assertEquals(0.,iData.getInsertionCost(),0.01); + } + + @Test + public void whenNewServiceNeedToBeInserted_itShouldReturnCorrectInsertionIndex(){ + Service s4 = Service.Builder.newInstance("s4").setLocationId("5,0").setTimeWindow(TimeWindow.newInstance(5.,5.)).build(); +// PickupActivity pickupService = new PickupService(s4); + JobInsertionContext context = new JobInsertionContext(route,s4,route.getVehicle(),route.getDriver(),0.); + RouteLevelActivityInsertionCostsEstimator estimator = new RouteLevelActivityInsertionCostsEstimator(routingCosts,activityCosts,stateManager); + estimator.setForwardLooking(0); + ServiceInsertionOnRouteLevelCalculator routeInserter = new ServiceInsertionOnRouteLevelCalculator(routingCosts, + activityCosts,estimator,constraintManager,constraintManager); + routeInserter.setStates(stateManager); + InsertionData iData = routeInserter.getInsertionData(route,s4,route.getVehicle(),route.getDepartureTime(),route.getDriver(),Double.MAX_VALUE); + assertEquals(0,iData.getDeliveryInsertionIndex(),0.01); + } + + @Test + public void whenNewServiceWithServiceTimeNeedToBeInserted_itShouldReturnCorrectInsertionData(){ + Service s4 = Service.Builder.newInstance("s4").setServiceTime(10.).setLocationId("5,0").setTimeWindow(TimeWindow.newInstance(5.,5.)).build(); +// PickupActivity pickupService = new PickupService(s4); + JobInsertionContext context = new JobInsertionContext(route,s4,route.getVehicle(),route.getDriver(),0.); + RouteLevelActivityInsertionCostsEstimator estimator = new RouteLevelActivityInsertionCostsEstimator(routingCosts,activityCosts,stateManager); + estimator.setForwardLooking(0); + ServiceInsertionOnRouteLevelCalculator routeInserter = new ServiceInsertionOnRouteLevelCalculator(routingCosts, + activityCosts,estimator,constraintManager,constraintManager); + routeInserter.setStates(stateManager); + InsertionData iData = routeInserter.getInsertionData(route,s4,route.getVehicle(),route.getDepartureTime(),route.getDriver(),Double.MAX_VALUE); + assertEquals(0,iData.getDeliveryInsertionIndex(),0.01); + assertEquals(30.,iData.getInsertionCost(),0.01); + } + + + @Test + public void whenNewServiceWithServiceTimeNeedToBeInsertedAndRouteIsEmpty_itShouldReturnCorrectInsertionData(){ + Service s4 = Service.Builder.newInstance("s4").setServiceTime(10.).setLocationId("5,0").setTimeWindow(TimeWindow.newInstance(5.,5.)).build(); +// PickupActivity pickupService = new PickupService(s4); + VehicleRoute emptyroute = VehicleRoute.emptyRoute(); + JobInsertionContext context = new JobInsertionContext(emptyroute,s4,route.getVehicle(),route.getDriver(),0.); + RouteLevelActivityInsertionCostsEstimator estimator = new RouteLevelActivityInsertionCostsEstimator(routingCosts,activityCosts,stateManager); + estimator.setForwardLooking(0); + ServiceInsertionOnRouteLevelCalculator routeInserter = new ServiceInsertionOnRouteLevelCalculator(routingCosts, + activityCosts,estimator,constraintManager,constraintManager); + routeInserter.setStates(stateManager); + InsertionData iData = routeInserter.getInsertionData(emptyroute,s4,route.getVehicle(),route.getDepartureTime(),route.getDriver(),Double.MAX_VALUE); + assertEquals(0,iData.getDeliveryInsertionIndex(),0.01); + assertEquals(10.,iData.getInsertionCost(),0.01); + } + + @Test + public void whenNewServiceWithServiceTimeAndTWNeedToBeInsertedAndRouteIsEmpty_itShouldReturnCorrectInsertionData(){ + Service s4 = Service.Builder.newInstance("s4").setServiceTime(10.).setLocationId("5,0").setTimeWindow(TimeWindow.newInstance(3.,3.)).build(); +// PickupActivity pickupService = new PickupService(s4); + VehicleRoute emptyroute = VehicleRoute.emptyRoute(); + JobInsertionContext context = new JobInsertionContext(emptyroute,s4,route.getVehicle(),route.getDriver(),0.); + RouteLevelActivityInsertionCostsEstimator estimator = new RouteLevelActivityInsertionCostsEstimator(routingCosts,activityCosts,stateManager); + estimator.setForwardLooking(0); + ServiceInsertionOnRouteLevelCalculator routeInserter = new ServiceInsertionOnRouteLevelCalculator(routingCosts, + activityCosts,estimator,constraintManager,constraintManager); + routeInserter.setStates(stateManager); + InsertionData iData = routeInserter.getInsertionData(emptyroute,s4,route.getVehicle(),route.getDepartureTime(),route.getDriver(),Double.MAX_VALUE); + assertEquals(0,iData.getDeliveryInsertionIndex(),0.01); + assertEquals(10.+2.,iData.getInsertionCost(),0.01); + } + +} diff --git a/jsprit-core/src/test/java/jsprit/core/util/CostFactory.java b/jsprit-core/src/test/java/jsprit/core/util/CostFactory.java index f63c91a0..e3c550ec 100644 --- a/jsprit-core/src/test/java/jsprit/core/util/CostFactory.java +++ b/jsprit-core/src/test/java/jsprit/core/util/CostFactory.java @@ -3,7 +3,15 @@ package jsprit.core.util; import jsprit.core.problem.cost.VehicleRoutingTransportCosts; public class CostFactory { - + + /** + * Return manhattanCosts. + *

+ * This retrieves coordinates from locationIds. LocationId has to be locId="{x},{y}". For example, + * locId="10,10" is interpreted such that x=10 and y=10. + * + * @return manhattanCosts + */ public static VehicleRoutingTransportCosts createManhattanCosts(){ Locations locations = new Locations(){ @@ -18,7 +26,15 @@ public class CostFactory { }; return new ManhattanCosts(locations); } - + + /** + * Return euclideanCosts. + *

+ * This retrieves coordinates from locationIds. LocationId has to be locId="{x},{y}". For example, + * locId="10,10" is interpreted such that x=10 and y=10. + * + * @return euclidean + */ public static VehicleRoutingTransportCosts createEuclideanCosts(){ Locations locations = new Locations(){