mirror of
https://github.com/graphhopper/jsprit.git
synced 2020-01-24 07:45:05 +01:00
add shipment based activities, modify inserter and implement
insertionAlgo for shipments
This commit is contained in:
parent
c31e61a797
commit
2835d15dd3
12 changed files with 570 additions and 51 deletions
|
|
@ -19,19 +19,91 @@ package algorithms;
|
|||
import algorithms.InsertionData.NoInsertionFound;
|
||||
import basics.Job;
|
||||
import basics.Service;
|
||||
import basics.Shipment;
|
||||
import basics.route.DefaultShipmentActivityFactory;
|
||||
import basics.route.DefaultTourActivityFactory;
|
||||
import basics.route.TourActivity;
|
||||
import basics.route.TourActivityFactory;
|
||||
import basics.route.TourShipmentActivityFactory;
|
||||
import basics.route.VehicleRoute;
|
||||
|
||||
class Inserter {
|
||||
|
||||
interface JobInsertionHandler {
|
||||
void handleJobInsertion(Job job, InsertionData iData, VehicleRoute route);
|
||||
|
||||
void setNextHandler(JobInsertionHandler handler);
|
||||
}
|
||||
|
||||
class JobExceptionHandler implements JobInsertionHandler{
|
||||
|
||||
@Override
|
||||
public void handleJobInsertion(Job job, InsertionData iData,VehicleRoute route) {
|
||||
throw new IllegalStateException("job insertion is not supported. Do not know job type.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNextHandler(JobInsertionHandler handler) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ServiceInsertionHandler implements JobInsertionHandler{
|
||||
|
||||
private TourActivityFactory activityFactory = new DefaultTourActivityFactory();
|
||||
|
||||
private JobInsertionHandler delegator = new JobExceptionHandler();
|
||||
|
||||
@Override
|
||||
public void handleJobInsertion(Job job, InsertionData iData, VehicleRoute route) {
|
||||
if(job instanceof Service){
|
||||
route.getTourActivities().addActivity(iData.getDeliveryInsertionIndex(), this.activityFactory.createActivity((Service)job));
|
||||
route.setDepartureTime(iData.getVehicleDepartureTime());
|
||||
}
|
||||
else delegator.handleJobInsertion(job, iData, route);
|
||||
}
|
||||
|
||||
public void setNextHandler(JobInsertionHandler jobInsertionHandler){
|
||||
this.delegator = jobInsertionHandler;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ShipmentInsertionHandler implements JobInsertionHandler {
|
||||
|
||||
private TourShipmentActivityFactory activityFactory = new DefaultShipmentActivityFactory();
|
||||
|
||||
private JobInsertionHandler delegator = new JobExceptionHandler();
|
||||
|
||||
@Override
|
||||
public void handleJobInsertion(Job job, InsertionData iData, VehicleRoute route) {
|
||||
if(job instanceof Shipment){
|
||||
TourActivity pickupShipment = this.activityFactory.createPickup((Shipment)job);
|
||||
TourActivity deliverShipment = this.activityFactory.createDelivery((Shipment)job);
|
||||
route.getTourActivities().addActivity(iData.getDeliveryInsertionIndex(), deliverShipment);
|
||||
route.getTourActivities().addActivity(iData.getPickupInsertionIndex(), pickupShipment);
|
||||
route.setDepartureTime(iData.getVehicleDepartureTime());
|
||||
}
|
||||
else delegator.handleJobInsertion(job, iData, route);
|
||||
}
|
||||
|
||||
public void setNextHandler(JobInsertionHandler jobInsertionHandler){
|
||||
this.delegator = jobInsertionHandler;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private InsertionListeners insertionListeners;
|
||||
|
||||
private TourActivityFactory activityFactory;
|
||||
private JobInsertionHandler jobInsertionHandler;
|
||||
|
||||
public Inserter(InsertionListeners insertionListeners) {
|
||||
this.insertionListeners = insertionListeners;
|
||||
activityFactory = new DefaultTourActivityFactory();
|
||||
new DefaultTourActivityFactory();
|
||||
jobInsertionHandler = new ServiceInsertionHandler();
|
||||
jobInsertionHandler.setNextHandler(new ShipmentInsertionHandler());
|
||||
}
|
||||
|
||||
public void insertJob(Job job, InsertionData insertionData, VehicleRoute vehicleRoute){
|
||||
|
|
@ -43,14 +115,7 @@ class Inserter {
|
|||
insertionListeners.informVehicleSwitched(vehicleRoute, vehicleRoute.getVehicle(), insertionData.getSelectedVehicle());
|
||||
vehicleRoute.setVehicle(insertionData.getSelectedVehicle(), insertionData.getVehicleDepartureTime());
|
||||
}
|
||||
// if(vehicleRoute.getDepartureTime() != vehicleRoute.g)
|
||||
if(job instanceof Service) {
|
||||
vehicleRoute.getTourActivities().addActivity(insertionData.getDeliveryInsertionIndex(), activityFactory.createActivity((Service)job));
|
||||
vehicleRoute.setDepartureTime(insertionData.getVehicleDepartureTime());
|
||||
}
|
||||
else throw new IllegalStateException("neither service nor shipment. this is not supported.");
|
||||
|
||||
jobInsertionHandler.handleJobInsertion(job, insertionData, vehicleRoute);
|
||||
insertionListeners.informJobInserted(job, vehicleRoute, insertionData.getInsertionCost(), insertionData.getAdditionalTime());
|
||||
// updateTour(vehicleRoute);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ class LocalActivityInsertionCostsCalculator implements ActivityInsertionCostsCal
|
|||
private HardActivityLevelConstraint hardConstraint;
|
||||
|
||||
private VehicleRoutingTransportCosts routingCosts;
|
||||
|
||||
private VehicleRoutingActivityCosts activityCosts;
|
||||
|
||||
public LocalActivityInsertionCostsCalculator(VehicleRoutingTransportCosts routingCosts, VehicleRoutingActivityCosts actCosts, HardActivityLevelConstraint hardActivityLevelConstraint) {
|
||||
|
|
@ -66,12 +67,16 @@ class LocalActivityInsertionCostsCalculator implements ActivityInsertionCostsCal
|
|||
double oldCosts;
|
||||
double oldTime;
|
||||
if(iFacts.getRoute().isEmpty()){
|
||||
oldCosts = 0.0;
|
||||
oldTime = 0.0;
|
||||
double tp_costs_prevAct_nextAct = routingCosts.getTransportCost(prevAct.getLocationId(), nextAct.getLocationId(), depTimeAtPrevAct, iFacts.getNewDriver(), iFacts.getNewVehicle());
|
||||
double arrTime_nextAct = routingCosts.getTransportTime(prevAct.getLocationId(), nextAct.getLocationId(), depTimeAtPrevAct, iFacts.getNewDriver(), iFacts.getNewVehicle());
|
||||
|
||||
double actCost_nextAct = activityCosts.getActivityCost(nextAct, arrTime_nextAct, iFacts.getNewDriver(), iFacts.getNewVehicle());
|
||||
oldCosts = tp_costs_prevAct_nextAct + actCost_nextAct;
|
||||
oldTime = (nextAct.getArrTime() - depTimeAtPrevAct);
|
||||
}
|
||||
else{
|
||||
double tp_costs_prevAct_nextAct = routingCosts.getTransportCost(prevAct.getLocationId(), nextAct.getLocationId(), prevAct.getEndTime(), iFacts.getRoute().getDriver(), iFacts.getRoute().getVehicle());
|
||||
double arrTime_nextAct = routingCosts.getTransportTime(prevAct.getLocationId(), nextAct.getLocationId(), prevAct.getEndTime(), iFacts.getNewDriver(), iFacts.getNewVehicle());
|
||||
double arrTime_nextAct = routingCosts.getTransportTime(prevAct.getLocationId(), nextAct.getLocationId(), prevAct.getEndTime(), iFacts.getRoute().getDriver(), iFacts.getRoute().getVehicle());
|
||||
|
||||
double actCost_nextAct = activityCosts.getActivityCost(nextAct, arrTime_nextAct, iFacts.getRoute().getDriver(), iFacts.getRoute().getVehicle());
|
||||
oldCosts = tp_costs_prevAct_nextAct + actCost_nextAct;
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ final class ShipmentInsertionCalculator implements JobInsertionCalculator{
|
|||
if(totalActivityInsertionCosts < bestCost){
|
||||
bestCost = totalActivityInsertionCosts;
|
||||
pickupInsertionIndex = i;
|
||||
deliveryInsertionIndex = activities.size() - 1;
|
||||
deliveryInsertionIndex = activities.size();
|
||||
}
|
||||
}
|
||||
//update prevAct and endTime
|
||||
|
|
@ -166,43 +166,11 @@ final class ShipmentInsertionCalculator implements JobInsertionCalculator{
|
|||
double totalActivityInsertionCosts = pickupAIC.getAdditionalCosts() + deliveryAIC.getAdditionalCosts();
|
||||
if(totalActivityInsertionCosts < bestCost){
|
||||
bestCost = totalActivityInsertionCosts;
|
||||
pickupInsertionIndex = activities.size() - 1;
|
||||
deliveryInsertionIndex = activities.size() - 1;
|
||||
pickupInsertionIndex = activities.size();
|
||||
deliveryInsertionIndex = activities.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// for(TourActivity nextAct : activities){
|
||||
// if(neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), prevAct.getLocationId()) && neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), nextAct.getLocationId())){
|
||||
// ActivityInsertionCosts mc = calculate(insertionContext, prevAct, nextAct, deliveryAct2Insert, prevActEndTime);
|
||||
// if(mc != null){
|
||||
// if(mc.getAdditionalCosts() < bestCost){
|
||||
// bestCost = mc.getAdditionalCosts();
|
||||
// bestMarginals = mc;
|
||||
// insertionIndex = actIndex;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// double nextActArrTime = prevActEndTime + transportCosts.getTransportTime(prevAct.getLocationId(), nextAct.getLocationId(), prevActEndTime, newDriver, newVehicle);
|
||||
// double nextActEndTime = CalcUtils.getActivityEndTime(nextActArrTime, nextAct);
|
||||
//
|
||||
// prevActEndTime = nextActEndTime;
|
||||
//
|
||||
// prevAct = nextAct;
|
||||
// actIndex++;
|
||||
// }
|
||||
// End nextAct = end;
|
||||
// if(neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), prevAct.getLocationId()) && neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), nextAct.getLocationId())){
|
||||
// ActivityInsertionCosts mc = calculate(insertionContext, prevAct, nextAct, deliveryAct2Insert, prevActEndTime);
|
||||
// if(mc != null) {
|
||||
// if(mc.getAdditionalCosts() < bestCost){
|
||||
// bestCost = mc.getAdditionalCosts();
|
||||
// bestMarginals = mc;
|
||||
// insertionIndex = actIndex;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
if(pickupInsertionIndex == InsertionData.NO_INDEX) {
|
||||
return InsertionData.noInsertionFound();
|
||||
}
|
||||
|
|
@ -211,7 +179,7 @@ final class ShipmentInsertionCalculator implements JobInsertionCalculator{
|
|||
return insertionData;
|
||||
}
|
||||
|
||||
public ActivityInsertionCosts calculate(InsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double departureTimeAtPrevAct) {
|
||||
private ActivityInsertionCosts calculate(InsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double departureTimeAtPrevAct) {
|
||||
return activityInsertionCostsCalculator.calculate(iFacts, prevAct, nextAct, newAct, departureTimeAtPrevAct);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -236,14 +236,25 @@ public class VehicleRoutingProblem {
|
|||
if(job instanceof Service) {
|
||||
addService((Service) job);
|
||||
}
|
||||
else if(job instanceof Shipment){
|
||||
addShipment((Shipment)job);
|
||||
}
|
||||
else{
|
||||
if(jobs.containsKey(job.getId())){ logger.warn("job " + job + " already in job list. overrides existing job."); }
|
||||
jobs.put(job.getId(),job);
|
||||
// if(jobs.containsKey(job.getId())){ logger.warn("job " + job + " already in job list. overrides existing job."); }
|
||||
// coordinates.put(job.getLocationId(), job.getCoord());
|
||||
// jobs.put(job.getId(),job);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
private void addShipment(Shipment job) {
|
||||
if(jobs.containsKey(job.getId())){ logger.warn("job " + job + " already in job list. overrides existing job."); }
|
||||
coordinates.put(job.getPickupLocation(), job.getPickupCoord());
|
||||
coordinates.put(job.getDeliveryLocation(), job.getDeliveryCoord());
|
||||
jobs.put(job.getId(),job);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a vehicle.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -80,4 +80,8 @@ public final class DeliverShipment implements DeliveryActivity{
|
|||
return new DeliverShipment(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[act="+getName()+"][loc="+getLocationId()+"]";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,5 +79,10 @@ public final class PickupShipment implements PickupActivity{
|
|||
public TourActivity duplicate() {
|
||||
return new PickupShipment(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[act="+getName()+"][loc="+getLocationId()+"]";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -152,6 +152,7 @@ public class TourActivities {
|
|||
|
||||
public void addActivity(int insertionIndex, TourActivity act) {
|
||||
assert insertionIndex >= 0 : "insertionIndex == 0, this cannot be";
|
||||
if(tourActivities.contains(act)) throw new IllegalStateException("act " + act + " already in tour. cannot add act twice.");
|
||||
/*
|
||||
* if 1 --> between start and act(0) --> act(0)
|
||||
* if 2 && 2 <= acts.size --> between act(0) and act(1) --> act(1)
|
||||
|
|
@ -164,6 +165,12 @@ public class TourActivities {
|
|||
addJob(act);
|
||||
}
|
||||
|
||||
/**
|
||||
* adds activity.
|
||||
*
|
||||
* @throw {@link IllegalStateException} if same activity is added twice.
|
||||
* @param act
|
||||
*/
|
||||
public void addActivity(TourActivity act){
|
||||
if(tourActivities.contains(act)) throw new IllegalStateException("act " + act + " already in tour. cannot add act twice.");
|
||||
tourActivities.add(act);
|
||||
|
|
|
|||
|
|
@ -187,6 +187,11 @@ public class VehicleRoute {
|
|||
public End getEnd() {
|
||||
return end;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[start="+start+"][end=" + end + "][departureTime=" + start.getEndTime() + "][vehicle=" + vehicle + "][driver=" + driver + "][nuOfActs="+tourActivities.getActivities().size()+"]";
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void setVehicleRouteCostCalculator(VehicleRouteCostCalculator costAccumulator){
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue