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

modify/extend HardActivityLevelConstraint

This commit is contained in:
Stefan Schroeder 2013-10-23 14:06:37 +02:00
parent f37e599973
commit fb78d60a36
9 changed files with 90 additions and 63 deletions

View file

@ -22,7 +22,7 @@ class ConstraintManager implements HardActivityLevelConstraint, HardRouteLevelCo
} }
@Override @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); return actLevelConstraintManager.fulfilled(iFacts, prevAct, newAct, nextAct, prevActDepTime);
} }

View file

@ -4,6 +4,12 @@ import basics.route.TourActivity;
public interface HardActivityLevelConstraint { 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);
} }

View file

@ -14,13 +14,14 @@ class HardActivityLevelConstraintManager implements HardActivityLevelConstraint
} }
@Override @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){ for(HardActivityLevelConstraint constraint : hardConstraints){
if(!constraint.fulfilled(iFacts, prevAct, newAct, nextAct, prevActDepTime)){ ConstraintsStatus status = constraint.fulfilled(iFacts, prevAct, newAct, nextAct, prevActDepTime);
return false; if(status.equals(ConstraintsStatus.NOT_FULFILLED_BREAK) || status.equals(ConstraintsStatus.NOT_FULFILLED)){
return status;
} }
} }
return true; return ConstraintsStatus.FULFILLED;
} }
} }

View file

@ -16,7 +16,7 @@ class HardPickupAndDeliveryActivityLevelConstraint implements HardActivityLevelC
} }
@Override @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 loadAtPrevAct;
int futurePicks; int futurePicks;
int pastDeliveries; int pastDeliveries;
@ -32,16 +32,16 @@ class HardPickupAndDeliveryActivityLevelConstraint implements HardActivityLevelC
} }
if(newAct instanceof PickupActivity || newAct instanceof ServiceActivity){ if(newAct instanceof PickupActivity || newAct instanceof ServiceActivity){
if(loadAtPrevAct + newAct.getCapacityDemand() + futurePicks > iFacts.getNewVehicle().getCapacity()){ if(loadAtPrevAct + newAct.getCapacityDemand() + futurePicks > iFacts.getNewVehicle().getCapacity()){
return false; return ConstraintsStatus.NOT_FULFILLED;
} }
} }
if(newAct instanceof DeliveryActivity){ if(newAct instanceof DeliveryActivity){
if(loadAtPrevAct + Math.abs(newAct.getCapacityDemand()) + pastDeliveries > iFacts.getNewVehicle().getCapacity()){ if(loadAtPrevAct + Math.abs(newAct.getCapacityDemand()) + pastDeliveries > iFacts.getNewVehicle().getCapacity()){
return false; return ConstraintsStatus.NOT_FULFILLED;
} }
} }
return true; return ConstraintsStatus.FULFILLED;
} }
} }

View file

@ -16,11 +16,11 @@ class HardPickupAndDeliveryBackhaulActivityLevelConstraint implements HardActivi
} }
@Override @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) {
if(newAct instanceof PickupActivity && nextAct instanceof DeliveryActivity){ return false; } if(newAct instanceof PickupActivity && nextAct instanceof DeliveryActivity){ return ConstraintsStatus.NOT_FULFILLED; }
if(newAct instanceof ServiceActivity && nextAct instanceof DeliveryActivity){ return false; } if(newAct instanceof ServiceActivity && nextAct instanceof DeliveryActivity){ return ConstraintsStatus.NOT_FULFILLED; }
if(newAct instanceof DeliveryActivity && prevAct instanceof PickupActivity){ return false; } if(newAct instanceof DeliveryActivity && prevAct instanceof PickupActivity){ return ConstraintsStatus.NOT_FULFILLED; }
if(newAct instanceof DeliveryActivity && prevAct instanceof ServiceActivity){ return false; } if(newAct instanceof DeliveryActivity && prevAct instanceof ServiceActivity){ return ConstraintsStatus.NOT_FULFILLED; }
int loadAtPrevAct; int loadAtPrevAct;
int futurePicks; int futurePicks;
int pastDeliveries; int pastDeliveries;
@ -36,16 +36,16 @@ class HardPickupAndDeliveryBackhaulActivityLevelConstraint implements HardActivi
} }
if(newAct instanceof PickupActivity || newAct instanceof ServiceActivity){ if(newAct instanceof PickupActivity || newAct instanceof ServiceActivity){
if(loadAtPrevAct + newAct.getCapacityDemand() + futurePicks > iFacts.getNewVehicle().getCapacity()){ if(loadAtPrevAct + newAct.getCapacityDemand() + futurePicks > iFacts.getNewVehicle().getCapacity()){
return false; return ConstraintsStatus.NOT_FULFILLED;
} }
} }
if(newAct instanceof DeliveryActivity){ if(newAct instanceof DeliveryActivity){
if(loadAtPrevAct + Math.abs(newAct.getCapacityDemand()) + pastDeliveries > iFacts.getNewVehicle().getCapacity()){ if(loadAtPrevAct + Math.abs(newAct.getCapacityDemand()) + pastDeliveries > iFacts.getNewVehicle().getCapacity()){
return false; return ConstraintsStatus.NOT_FULFILLED;
} }
} }
return true; return ConstraintsStatus.FULFILLED;
} }
} }

View file

@ -25,21 +25,27 @@ import basics.route.TourActivity;
} }
@Override @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) {
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); // 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 arrTimeAtNewAct = prevActDepTime + routingCosts.getTransportTime(prevAct.getLocationId(), newAct.getLocationId(), prevActDepTime, iFacts.getNewDriver(), iFacts.getNewVehicle());
double latestArrTimeAtNewAct = states.getActivityState(newAct, StateFactory.LATEST_OPERATION_START_TIME).toDouble(); double latestArrTimeAtNewAct = states.getActivityState(newAct, StateFactory.LATEST_OPERATION_START_TIME).toDouble();
if(arrTimeAtNewAct > latestArrTimeAtNewAct){ if(arrTimeAtNewAct > latestArrTimeAtNewAct){
return false; return ConstraintsStatus.NOT_FULFILLED;
} }
// log.info(newAct + " arrTime=" + arrTimeAtNewAct); // log.info(newAct + " arrTime=" + arrTimeAtNewAct);
double endTimeAtNewAct = CalculationUtils.getActivityEndTime(arrTimeAtNewAct, newAct); double endTimeAtNewAct = CalculationUtils.getActivityEndTime(arrTimeAtNewAct, newAct);
double arrTimeAtNextAct = endTimeAtNewAct + routingCosts.getTransportTime(newAct.getLocationId(), nextAct.getLocationId(), endTimeAtNewAct, iFacts.getNewDriver(), iFacts.getNewVehicle()); 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(); double latestArrTimeAtNextAct = states.getActivityState(nextAct, StateFactory.LATEST_OPERATION_START_TIME).toDouble();
if(arrTimeAtNextAct > latestArrTimeAtNextAct){ if(arrTimeAtNextAct > latestArrTimeAtNextAct){
return false; return ConstraintsStatus.NOT_FULFILLED;
} }
// log.info(nextAct + " arrTime=" + arrTimeAtNextAct); return ConstraintsStatus.FULFILLED;
return true;
} }
} }

View file

@ -20,6 +20,7 @@ import org.apache.log4j.Logger;
import util.Neighborhood; import util.Neighborhood;
import algorithms.ActivityInsertionCostsCalculator.ActivityInsertionCosts; import algorithms.ActivityInsertionCostsCalculator.ActivityInsertionCosts;
import algorithms.HardActivityLevelConstraint.ConstraintsStatus;
import basics.Job; import basics.Job;
import basics.Service; import basics.Service;
import basics.costs.VehicleRoutingTransportCosts; import basics.costs.VehicleRoutingTransportCosts;
@ -102,16 +103,16 @@ final class ServiceInsertionCalculator implements JobInsertionCalculator{
Start start = Start.newInstance(newVehicle.getLocationId(), newVehicle.getEarliestDeparture(), newVehicle.getLatestArrival()); Start start = Start.newInstance(newVehicle.getLocationId(), newVehicle.getEarliestDeparture(), newVehicle.getLatestArrival());
start.setEndTime(newVehicleDepartureTime); start.setEndTime(newVehicleDepartureTime);
End end = End.newInstance(newVehicle.getLocationId(), 0.0, newVehicle.getLatestArrival()); End end = End.newInstance(newVehicle.getLocationId(), 0.0, newVehicle.getLatestArrival());
TourActivity prevAct = start; TourActivity prevAct = start;
double prevActStartTime = newVehicleDepartureTime; double prevActStartTime = newVehicleDepartureTime;
int actIndex = 0; int actIndex = 0;
boolean loopBroken = false;
for(TourActivity nextAct : currentRoute.getTourActivities().getActivities()){ for(TourActivity nextAct : currentRoute.getTourActivities().getActivities()){
if(neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), prevAct.getLocationId()) && neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), nextAct.getLocationId())){ 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); ActivityInsertionCosts mc = calculate(insertionContext, prevAct, nextAct, deliveryAct2Insert, prevActStartTime);
if(mc.getAdditionalCosts() < bestCost){ if(mc.getAdditionalCosts() < bestCost){
bestCost = mc.getAdditionalCosts(); bestCost = mc.getAdditionalCosts();
@ -119,18 +120,21 @@ final class ServiceInsertionCalculator implements JobInsertionCalculator{
insertionIndex = actIndex; 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 nextActArrTime = prevActStartTime + transportCosts.getTransportTime(prevAct.getLocationId(), nextAct.getLocationId(), prevActStartTime, newDriver, newVehicle);
double nextActEndTime = CalculationUtils.getActivityEndTime(nextActArrTime, nextAct); double nextActEndTime = CalculationUtils.getActivityEndTime(nextActArrTime, nextAct);
prevActStartTime = nextActEndTime; prevActStartTime = nextActEndTime;
prevAct = nextAct; prevAct = nextAct;
actIndex++; actIndex++;
} }
End nextAct = end; End nextAct = end;
if(!loopBroken){
if(neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), prevAct.getLocationId()) && neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), nextAct.getLocationId())){ 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); ActivityInsertionCosts mc = calculate(insertionContext, prevAct, nextAct, deliveryAct2Insert, prevActStartTime);
if(mc.getAdditionalCosts() < bestCost){ if(mc.getAdditionalCosts() < bestCost){
bestCost = mc.getAdditionalCosts(); bestCost = mc.getAdditionalCosts();
@ -139,6 +143,7 @@ final class ServiceInsertionCalculator implements JobInsertionCalculator{
} }
} }
} }
}
if(insertionIndex == InsertionData.NO_INDEX) { if(insertionIndex == InsertionData.NO_INDEX) {
return InsertionData.noInsertionFound(); return InsertionData.noInsertionFound();

View file

@ -27,6 +27,7 @@ import org.apache.log4j.Logger;
import util.Neighborhood; import util.Neighborhood;
import algorithms.ActivityInsertionCostsCalculator.ActivityInsertionCosts; import algorithms.ActivityInsertionCostsCalculator.ActivityInsertionCosts;
import algorithms.HardActivityLevelConstraint.ConstraintsStatus;
import basics.Job; import basics.Job;
import basics.Service; import basics.Service;
import basics.costs.VehicleRoutingActivityCosts; import basics.costs.VehicleRoutingActivityCosts;
@ -167,6 +168,7 @@ final class ServiceInsertionOnRouteLevelCalculator implements JobInsertionCalcul
double sumOf_prevCosts_newVehicle = 0.0; double sumOf_prevCosts_newVehicle = 0.0;
double prevActDepTime_newVehicle = start.getEndTime(); 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} * inserting serviceAct2Insert in route r={0,1,...,i-1,i,j,j+1,...,n(r),n(r)+1}
* i=prevAct * i=prevAct
@ -175,7 +177,8 @@ final class ServiceInsertionOnRouteLevelCalculator implements JobInsertionCalcul
*/ */
for(TourActivity nextAct : tour.getActivities()){ for(TourActivity nextAct : tour.getActivities()){
if(neighborhood.areNeighbors(serviceAct2Insert.getLocationId(), prevAct.getLocationId()) && neighborhood.areNeighbors(serviceAct2Insert.getLocationId(), nextAct.getLocationId())){ 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} * 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)); 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,9 +229,11 @@ final class ServiceInsertionOnRouteLevelCalculator implements JobInsertionCalcul
actIndex++; actIndex++;
} }
if(!loopBroken){
End nextAct = end; End nextAct = end;
if(neighborhood.areNeighbors(serviceAct2Insert.getLocationId(), prevAct.getLocationId()) && neighborhood.areNeighbors(serviceAct2Insert.getLocationId(), nextAct.getLocationId())){ 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)){
ActivityInsertionCosts actInsertionCosts = activityInsertionCostsCalculator.calculate(insertionContext, prevAct, nextAct, serviceAct2Insert, prevActDepTime_newVehicle); ActivityInsertionCosts actInsertionCosts = activityInsertionCostsCalculator.calculate(insertionContext, prevAct, nextAct, serviceAct2Insert, prevActDepTime_newVehicle);
if(actInsertionCosts != null){ if(actInsertionCosts != null){
/** /**
@ -242,6 +250,7 @@ final class ServiceInsertionOnRouteLevelCalculator implements JobInsertionCalcul
} }
} }
} }
}
/** /**

View file

@ -53,8 +53,8 @@ public class BuildCVRPAlgoFromScratchTest {
HardActivityLevelConstraint hardActLevelConstraint = new HardActivityLevelConstraint() { HardActivityLevelConstraint hardActLevelConstraint = new HardActivityLevelConstraint() {
@Override @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 true; return ConstraintsStatus.FULFILLED;
} }
}; };