From fb78d60a36835fbc0bddedd25b818c2e38624c5a Mon Sep 17 00:00:00 2001 From: Stefan Schroeder <4sschroeder@gmail.com> Date: Wed, 23 Oct 2013 14:06:37 +0200 Subject: [PATCH] modify/extend HardActivityLevelConstraint --- .../java/algorithms/ConstraintManager.java | 2 +- .../HardActivityLevelConstraint.java | 8 +++- .../HardActivityLevelConstraintManager.java | 9 ++-- ...kupAndDeliveryActivityLevelConstraint.java | 8 ++-- ...liveryBackhaulActivityLevelConstraint.java | 16 +++---- ...HardTimeWindowActivityLevelConstraint.java | 18 ++++--- .../ServiceInsertionCalculator.java | 47 ++++++++++--------- ...erviceInsertionOnRouteLevelCalculator.java | 41 +++++++++------- .../BuildCVRPAlgoFromScratchTest.java | 4 +- 9 files changed, 90 insertions(+), 63 deletions(-) diff --git a/jsprit-core/src/main/java/algorithms/ConstraintManager.java b/jsprit-core/src/main/java/algorithms/ConstraintManager.java index 87ad352b..d7713776 100644 --- a/jsprit-core/src/main/java/algorithms/ConstraintManager.java +++ b/jsprit-core/src/main/java/algorithms/ConstraintManager.java @@ -22,7 +22,7 @@ class ConstraintManager implements HardActivityLevelConstraint, HardRouteLevelCo } @Override - public boolean fulfilled(InsertionContext iFacts, TourActivity prevAct,TourActivity newAct, TourActivity nextAct, double prevActDepTime) { + public ConstraintsStatus fulfilled(InsertionContext iFacts, TourActivity prevAct,TourActivity newAct, TourActivity nextAct, double prevActDepTime) { return actLevelConstraintManager.fulfilled(iFacts, prevAct, newAct, nextAct, prevActDepTime); } diff --git a/jsprit-core/src/main/java/algorithms/HardActivityLevelConstraint.java b/jsprit-core/src/main/java/algorithms/HardActivityLevelConstraint.java index b70cdcd1..fc3e878c 100644 --- a/jsprit-core/src/main/java/algorithms/HardActivityLevelConstraint.java +++ b/jsprit-core/src/main/java/algorithms/HardActivityLevelConstraint.java @@ -4,6 +4,12 @@ import basics.route.TourActivity; public interface HardActivityLevelConstraint { - public boolean fulfilled(InsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime); + static enum ConstraintsStatus { + + NOT_FULFILLED_BREAK, NOT_FULFILLED, FULFILLED; + + } + + public ConstraintsStatus fulfilled(InsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime); } \ No newline at end of file diff --git a/jsprit-core/src/main/java/algorithms/HardActivityLevelConstraintManager.java b/jsprit-core/src/main/java/algorithms/HardActivityLevelConstraintManager.java index 2f3bd986..da5dc409 100644 --- a/jsprit-core/src/main/java/algorithms/HardActivityLevelConstraintManager.java +++ b/jsprit-core/src/main/java/algorithms/HardActivityLevelConstraintManager.java @@ -14,13 +14,14 @@ class HardActivityLevelConstraintManager implements HardActivityLevelConstraint } @Override - public boolean fulfilled(InsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime) { + public ConstraintsStatus fulfilled(InsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime) { for(HardActivityLevelConstraint constraint : hardConstraints){ - if(!constraint.fulfilled(iFacts, prevAct, newAct, nextAct, prevActDepTime)){ - return false; + ConstraintsStatus status = constraint.fulfilled(iFacts, prevAct, newAct, nextAct, prevActDepTime); + if(status.equals(ConstraintsStatus.NOT_FULFILLED_BREAK) || status.equals(ConstraintsStatus.NOT_FULFILLED)){ + return status; } } - return true; + return ConstraintsStatus.FULFILLED; } } \ No newline at end of file diff --git a/jsprit-core/src/main/java/algorithms/HardPickupAndDeliveryActivityLevelConstraint.java b/jsprit-core/src/main/java/algorithms/HardPickupAndDeliveryActivityLevelConstraint.java index fc0997b1..f7b9e06c 100644 --- a/jsprit-core/src/main/java/algorithms/HardPickupAndDeliveryActivityLevelConstraint.java +++ b/jsprit-core/src/main/java/algorithms/HardPickupAndDeliveryActivityLevelConstraint.java @@ -16,7 +16,7 @@ class HardPickupAndDeliveryActivityLevelConstraint implements HardActivityLevelC } @Override - public boolean fulfilled(InsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime) { + public ConstraintsStatus fulfilled(InsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime) { int loadAtPrevAct; int futurePicks; int pastDeliveries; @@ -32,16 +32,16 @@ class HardPickupAndDeliveryActivityLevelConstraint implements HardActivityLevelC } if(newAct instanceof PickupActivity || newAct instanceof ServiceActivity){ if(loadAtPrevAct + newAct.getCapacityDemand() + futurePicks > iFacts.getNewVehicle().getCapacity()){ - return false; + return ConstraintsStatus.NOT_FULFILLED; } } if(newAct instanceof DeliveryActivity){ if(loadAtPrevAct + Math.abs(newAct.getCapacityDemand()) + pastDeliveries > iFacts.getNewVehicle().getCapacity()){ - return false; + return ConstraintsStatus.NOT_FULFILLED; } } - return true; + return ConstraintsStatus.FULFILLED; } } \ No newline at end of file diff --git a/jsprit-core/src/main/java/algorithms/HardPickupAndDeliveryBackhaulActivityLevelConstraint.java b/jsprit-core/src/main/java/algorithms/HardPickupAndDeliveryBackhaulActivityLevelConstraint.java index a99b4862..007912f2 100644 --- a/jsprit-core/src/main/java/algorithms/HardPickupAndDeliveryBackhaulActivityLevelConstraint.java +++ b/jsprit-core/src/main/java/algorithms/HardPickupAndDeliveryBackhaulActivityLevelConstraint.java @@ -16,11 +16,11 @@ class HardPickupAndDeliveryBackhaulActivityLevelConstraint implements HardActivi } @Override - public boolean fulfilled(InsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime) { - if(newAct instanceof PickupActivity && nextAct instanceof DeliveryActivity){ return false; } - if(newAct instanceof ServiceActivity && nextAct instanceof DeliveryActivity){ return false; } - if(newAct instanceof DeliveryActivity && prevAct instanceof PickupActivity){ return false; } - if(newAct instanceof DeliveryActivity && prevAct instanceof ServiceActivity){ return false; } + public ConstraintsStatus fulfilled(InsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime) { + if(newAct instanceof PickupActivity && nextAct instanceof DeliveryActivity){ return ConstraintsStatus.NOT_FULFILLED; } + if(newAct instanceof ServiceActivity && nextAct instanceof DeliveryActivity){ return ConstraintsStatus.NOT_FULFILLED; } + if(newAct instanceof DeliveryActivity && prevAct instanceof PickupActivity){ return ConstraintsStatus.NOT_FULFILLED; } + if(newAct instanceof DeliveryActivity && prevAct instanceof ServiceActivity){ return ConstraintsStatus.NOT_FULFILLED; } int loadAtPrevAct; int futurePicks; int pastDeliveries; @@ -36,16 +36,16 @@ class HardPickupAndDeliveryBackhaulActivityLevelConstraint implements HardActivi } if(newAct instanceof PickupActivity || newAct instanceof ServiceActivity){ if(loadAtPrevAct + newAct.getCapacityDemand() + futurePicks > iFacts.getNewVehicle().getCapacity()){ - return false; + return ConstraintsStatus.NOT_FULFILLED; } } if(newAct instanceof DeliveryActivity){ if(loadAtPrevAct + Math.abs(newAct.getCapacityDemand()) + pastDeliveries > iFacts.getNewVehicle().getCapacity()){ - return false; + return ConstraintsStatus.NOT_FULFILLED; } } - return true; + return ConstraintsStatus.FULFILLED; } } \ No newline at end of file diff --git a/jsprit-core/src/main/java/algorithms/HardTimeWindowActivityLevelConstraint.java b/jsprit-core/src/main/java/algorithms/HardTimeWindowActivityLevelConstraint.java index 9393cceb..137b0a81 100644 --- a/jsprit-core/src/main/java/algorithms/HardTimeWindowActivityLevelConstraint.java +++ b/jsprit-core/src/main/java/algorithms/HardTimeWindowActivityLevelConstraint.java @@ -25,21 +25,27 @@ import basics.route.TourActivity; } @Override - public boolean fulfilled(InsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime) { -// log.info("check insertion of " + newAct + " between " + prevAct + " and " + nextAct + ". prevActDepTime=" + prevActDepTime); + public ConstraintsStatus fulfilled(InsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime) { + if(newAct.getTheoreticalLatestOperationStartTime() < prevAct.getTheoreticalEarliestOperationStartTime()){ + return ConstraintsStatus.NOT_FULFILLED_BREAK; + } + if(newAct.getTheoreticalEarliestOperationStartTime() > nextAct.getTheoreticalLatestOperationStartTime()){ + return ConstraintsStatus.NOT_FULFILLED; + } + // log.info("check insertion of " + newAct + " between " + prevAct + " and " + nextAct + ". prevActDepTime=" + prevActDepTime); double arrTimeAtNewAct = prevActDepTime + routingCosts.getTransportTime(prevAct.getLocationId(), newAct.getLocationId(), prevActDepTime, iFacts.getNewDriver(), iFacts.getNewVehicle()); double latestArrTimeAtNewAct = states.getActivityState(newAct, StateFactory.LATEST_OPERATION_START_TIME).toDouble(); + if(arrTimeAtNewAct > latestArrTimeAtNewAct){ - return false; + return ConstraintsStatus.NOT_FULFILLED; } // log.info(newAct + " arrTime=" + arrTimeAtNewAct); double endTimeAtNewAct = CalculationUtils.getActivityEndTime(arrTimeAtNewAct, newAct); double arrTimeAtNextAct = endTimeAtNewAct + routingCosts.getTransportTime(newAct.getLocationId(), nextAct.getLocationId(), endTimeAtNewAct, iFacts.getNewDriver(), iFacts.getNewVehicle()); double latestArrTimeAtNextAct = states.getActivityState(nextAct, StateFactory.LATEST_OPERATION_START_TIME).toDouble(); if(arrTimeAtNextAct > latestArrTimeAtNextAct){ - return false; + return ConstraintsStatus.NOT_FULFILLED; } -// log.info(nextAct + " arrTime=" + arrTimeAtNextAct); - return true; + return ConstraintsStatus.FULFILLED; } } \ No newline at end of file diff --git a/jsprit-core/src/main/java/algorithms/ServiceInsertionCalculator.java b/jsprit-core/src/main/java/algorithms/ServiceInsertionCalculator.java index 8eca3d96..e17ea108 100644 --- a/jsprit-core/src/main/java/algorithms/ServiceInsertionCalculator.java +++ b/jsprit-core/src/main/java/algorithms/ServiceInsertionCalculator.java @@ -20,6 +20,7 @@ import org.apache.log4j.Logger; import util.Neighborhood; import algorithms.ActivityInsertionCostsCalculator.ActivityInsertionCosts; +import algorithms.HardActivityLevelConstraint.ConstraintsStatus; import basics.Job; import basics.Service; import basics.costs.VehicleRoutingTransportCosts; @@ -102,16 +103,38 @@ final class ServiceInsertionCalculator implements JobInsertionCalculator{ Start start = Start.newInstance(newVehicle.getLocationId(), newVehicle.getEarliestDeparture(), newVehicle.getLatestArrival()); start.setEndTime(newVehicleDepartureTime); - End end = End.newInstance(newVehicle.getLocationId(), 0.0, newVehicle.getLatestArrival()); TourActivity prevAct = start; double prevActStartTime = newVehicleDepartureTime; int actIndex = 0; - + boolean loopBroken = false; for(TourActivity nextAct : currentRoute.getTourActivities().getActivities()){ if(neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), prevAct.getLocationId()) && neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), nextAct.getLocationId())){ - if(hardActivityLevelConstraint.fulfilled(insertionContext, prevAct, deliveryAct2Insert, nextAct, prevActStartTime)){ + ConstraintsStatus status = hardActivityLevelConstraint.fulfilled(insertionContext, prevAct, deliveryAct2Insert, nextAct, prevActStartTime); + if(status.equals(ConstraintsStatus.FULFILLED)){ + ActivityInsertionCosts mc = calculate(insertionContext, prevAct, nextAct, deliveryAct2Insert, prevActStartTime); + if(mc.getAdditionalCosts() < bestCost){ + bestCost = mc.getAdditionalCosts(); + bestMarginals = mc; + insertionIndex = actIndex; + } + } + else if(status.equals(ConstraintsStatus.NOT_FULFILLED_BREAK)){ + loopBroken = true; + } + } + double nextActArrTime = prevActStartTime + transportCosts.getTransportTime(prevAct.getLocationId(), nextAct.getLocationId(), prevActStartTime, newDriver, newVehicle); + double nextActEndTime = CalculationUtils.getActivityEndTime(nextActArrTime, nextAct); + prevActStartTime = nextActEndTime; + prevAct = nextAct; + actIndex++; + } + End nextAct = end; + if(!loopBroken){ + if(neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), prevAct.getLocationId()) && neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), nextAct.getLocationId())){ + ConstraintsStatus status = hardActivityLevelConstraint.fulfilled(insertionContext, prevAct, deliveryAct2Insert, nextAct, prevActStartTime); + if(status.equals(ConstraintsStatus.FULFILLED)){ ActivityInsertionCosts mc = calculate(insertionContext, prevAct, nextAct, deliveryAct2Insert, prevActStartTime); if(mc.getAdditionalCosts() < bestCost){ bestCost = mc.getAdditionalCosts(); @@ -120,25 +143,7 @@ final class ServiceInsertionCalculator implements JobInsertionCalculator{ } } } - double nextActArrTime = prevActStartTime + transportCosts.getTransportTime(prevAct.getLocationId(), nextAct.getLocationId(), prevActStartTime, newDriver, newVehicle); - double nextActEndTime = CalculationUtils.getActivityEndTime(nextActArrTime, nextAct); - - prevActStartTime = nextActEndTime; - - prevAct = nextAct; - actIndex++; } - End nextAct = end; - if(neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), prevAct.getLocationId()) && neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), nextAct.getLocationId())){ - if(hardActivityLevelConstraint.fulfilled(insertionContext, prevAct, deliveryAct2Insert, nextAct, prevActStartTime)){ - ActivityInsertionCosts mc = calculate(insertionContext, prevAct, nextAct, deliveryAct2Insert, prevActStartTime); - if(mc.getAdditionalCosts() < bestCost){ - bestCost = mc.getAdditionalCosts(); - bestMarginals = mc; - insertionIndex = actIndex; - } - } - } if(insertionIndex == InsertionData.NO_INDEX) { return InsertionData.noInsertionFound(); diff --git a/jsprit-core/src/main/java/algorithms/ServiceInsertionOnRouteLevelCalculator.java b/jsprit-core/src/main/java/algorithms/ServiceInsertionOnRouteLevelCalculator.java index 7aa36653..e76c56ff 100644 --- a/jsprit-core/src/main/java/algorithms/ServiceInsertionOnRouteLevelCalculator.java +++ b/jsprit-core/src/main/java/algorithms/ServiceInsertionOnRouteLevelCalculator.java @@ -27,6 +27,7 @@ import org.apache.log4j.Logger; import util.Neighborhood; import algorithms.ActivityInsertionCostsCalculator.ActivityInsertionCosts; +import algorithms.HardActivityLevelConstraint.ConstraintsStatus; import basics.Job; import basics.Service; import basics.costs.VehicleRoutingActivityCosts; @@ -167,6 +168,7 @@ final class ServiceInsertionOnRouteLevelCalculator implements JobInsertionCalcul double sumOf_prevCosts_newVehicle = 0.0; double prevActDepTime_newVehicle = start.getEndTime(); + boolean loopBroken = false; /** * inserting serviceAct2Insert in route r={0,1,...,i-1,i,j,j+1,...,n(r),n(r)+1} * i=prevAct @@ -175,7 +177,8 @@ final class ServiceInsertionOnRouteLevelCalculator implements JobInsertionCalcul */ for(TourActivity nextAct : tour.getActivities()){ if(neighborhood.areNeighbors(serviceAct2Insert.getLocationId(), prevAct.getLocationId()) && neighborhood.areNeighbors(serviceAct2Insert.getLocationId(), nextAct.getLocationId())){ - if(hardActivityLevelConstraint.fulfilled(insertionContext, prevAct, serviceAct2Insert, nextAct, prevActDepTime_newVehicle)){ + 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} */ @@ -193,7 +196,10 @@ final class ServiceInsertionOnRouteLevelCalculator implements JobInsertionCalcul bestInsertionsQueue.add(new InsertionData(insertion_cost_approximation, InsertionData.NO_INDEX, actIndex, newVehicle, newDriver)); } } - + else if(status.equals(ConstraintsStatus.NOT_FULFILLED_BREAK)){ + loopBroken = true; + break; + } } /** @@ -223,21 +229,24 @@ final class ServiceInsertionOnRouteLevelCalculator implements JobInsertionCalcul actIndex++; } - End nextAct = end; - if(neighborhood.areNeighbors(serviceAct2Insert.getLocationId(), prevAct.getLocationId()) && neighborhood.areNeighbors(serviceAct2Insert.getLocationId(), nextAct.getLocationId())){ - if(hardActivityLevelConstraint.fulfilled(insertionContext, prevAct, serviceAct2Insert, nextAct, prevActDepTime_newVehicle)){ - ActivityInsertionCosts actInsertionCosts = activityInsertionCostsCalculator.calculate(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(); + 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.calculate(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/algorithms/BuildCVRPAlgoFromScratchTest.java b/jsprit-core/src/test/java/algorithms/BuildCVRPAlgoFromScratchTest.java index cf5d58a0..3524911e 100644 --- a/jsprit-core/src/test/java/algorithms/BuildCVRPAlgoFromScratchTest.java +++ b/jsprit-core/src/test/java/algorithms/BuildCVRPAlgoFromScratchTest.java @@ -53,8 +53,8 @@ public class BuildCVRPAlgoFromScratchTest { HardActivityLevelConstraint hardActLevelConstraint = new HardActivityLevelConstraint() { @Override - public boolean fulfilled(InsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime) { - return true; + public ConstraintsStatus fulfilled(InsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime) { + return ConstraintsStatus.FULFILLED; } };