mirror of
https://github.com/graphhopper/jsprit.git
synced 2020-01-24 07:45:05 +01:00
internal experiments with serviceInsertion
This commit is contained in:
parent
c60ab8afd0
commit
922f360fe4
12 changed files with 200 additions and 328 deletions
|
|
@ -15,11 +15,9 @@ package algorithms;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
import util.Neighborhood;
|
import util.Neighborhood;
|
||||||
import algorithms.StateManager.State;
|
import algorithms.HardConstraints.HardRouteLevelConstraint;
|
||||||
import basics.Job;
|
import basics.Job;
|
||||||
import basics.Service;
|
import basics.Service;
|
||||||
import basics.costs.VehicleRoutingActivityCosts;
|
|
||||||
import basics.costs.VehicleRoutingTransportCosts;
|
|
||||||
import basics.route.Driver;
|
import basics.route.Driver;
|
||||||
import basics.route.End;
|
import basics.route.End;
|
||||||
import basics.route.ServiceActivity;
|
import basics.route.ServiceActivity;
|
||||||
|
|
@ -34,25 +32,36 @@ import basics.route.VehicleRoute;
|
||||||
|
|
||||||
final class CalculatesServiceInsertion implements JobInsertionCalculator{
|
final class CalculatesServiceInsertion implements JobInsertionCalculator{
|
||||||
|
|
||||||
|
static class Break {
|
||||||
|
private Marginals marginals;
|
||||||
|
private boolean breakLoop;
|
||||||
|
public Break(Marginals marginals, boolean breakLoop) {
|
||||||
|
super();
|
||||||
|
this.marginals = marginals;
|
||||||
|
this.breakLoop = breakLoop;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @return the marginals
|
||||||
|
*/
|
||||||
|
public Marginals getMarginals() {
|
||||||
|
return marginals;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @return the breakLoop
|
||||||
|
*/
|
||||||
|
public boolean isBreakLoop() {
|
||||||
|
return breakLoop;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(CalculatesServiceInsertion.class);
|
private static final Logger logger = Logger.getLogger(CalculatesServiceInsertion.class);
|
||||||
|
|
||||||
private StateManager states;
|
|
||||||
|
|
||||||
private VehicleRoutingTransportCosts routingCosts;
|
|
||||||
|
|
||||||
private VehicleRoutingActivityCosts activityCosts;
|
|
||||||
|
|
||||||
private Start start;
|
private Start start;
|
||||||
|
|
||||||
private End end;
|
private End end;
|
||||||
|
|
||||||
private HardConstraint hardConstraint = new HardConstraint() {
|
private HardRouteLevelConstraint hardRouteLevelConstraint;
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean fulfilled(InsertionScenario iScenario) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private Neighborhood neighborhood = new Neighborhood() {
|
private Neighborhood neighborhood = new Neighborhood() {
|
||||||
|
|
||||||
|
|
@ -62,24 +71,17 @@ final class CalculatesServiceInsertion implements JobInsertionCalculator{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void setHardConstraint(HardConstraint hardConstraint){
|
private MarginalsCalculus marginalCalculus;
|
||||||
this.hardConstraint = hardConstraint;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setNeighborhood(Neighborhood neighborhood) {
|
public void setNeighborhood(Neighborhood neighborhood) {
|
||||||
this.neighborhood = neighborhood;
|
this.neighborhood = neighborhood;
|
||||||
logger.info("initialise neighborhood " + neighborhood);
|
logger.info("initialise neighborhood " + neighborhood);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CalculatesServiceInsertion(MarginalsCalculus marginalsCalculus, HardRouteLevelConstraint hardRouteLevelConstraint) {
|
||||||
public void setStates(StateManager activityStates2){
|
|
||||||
this.states = activityStates2;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CalculatesServiceInsertion(VehicleRoutingTransportCosts vehicleRoutingTransportCosts, VehicleRoutingActivityCosts vehicleRoutingActivityCosts) {
|
|
||||||
super();
|
super();
|
||||||
this.routingCosts = vehicleRoutingTransportCosts;
|
this.marginalCalculus = marginalsCalculus;
|
||||||
this.activityCosts = vehicleRoutingActivityCosts;
|
this.hardRouteLevelConstraint = hardRouteLevelConstraint;
|
||||||
logger.info("initialise " + this);
|
logger.info("initialise " + this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -99,50 +101,48 @@ final class CalculatesServiceInsertion implements JobInsertionCalculator{
|
||||||
if(newVehicle == null || newVehicle instanceof NoVehicle) throw new IllegalStateException("newVehicle is missing.");
|
if(newVehicle == null || newVehicle instanceof NoVehicle) throw new IllegalStateException("newVehicle is missing.");
|
||||||
|
|
||||||
InsertionFacts iFacts = new InsertionFacts(currentRoute, jobToInsert, newVehicle, newDriver, newVehicleDepartureTime);
|
InsertionFacts iFacts = new InsertionFacts(currentRoute, jobToInsert, newVehicle, newDriver, newVehicleDepartureTime);
|
||||||
if(!hardConstraint.fulfilled(new InsertionScenario(iFacts, null))){
|
if(!hardRouteLevelConstraint.fulfilled(new InsertionScenario(iFacts, null))){
|
||||||
return InsertionData.noInsertionFound();
|
return InsertionData.noInsertionFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
TourActivities tour = currentRoute.getTourActivities();
|
TourActivities tour = currentRoute.getTourActivities();
|
||||||
double bestCost = bestKnownCosts;
|
double bestCost = bestKnownCosts;
|
||||||
|
Marginals bestMarginals = null;
|
||||||
Service service = (Service)jobToInsert;
|
Service service = (Service)jobToInsert;
|
||||||
|
|
||||||
int insertionIndex = InsertionData.NO_INDEX;
|
int insertionIndex = InsertionData.NO_INDEX;
|
||||||
|
|
||||||
TourActivity deliveryAct2Insert = ServiceActivity.newInstance(service);
|
TourActivity deliveryAct2Insert = ServiceActivity.newInstance(service);
|
||||||
|
|
||||||
initialiseStartAndEnd(newVehicle, newVehicleDepartureTime);
|
initialiseStartAndEnd(newVehicle, newVehicleDepartureTime);
|
||||||
|
|
||||||
TourActivity prevAct = start;
|
TourActivity prevAct = start;
|
||||||
double prevCostInOriginalTour = 0.0;
|
|
||||||
int actIndex = 0;
|
int actIndex = 0;
|
||||||
// logger.debug(prevAct.toString());
|
|
||||||
for(TourActivity nextAct : tour.getActivities()){
|
for(TourActivity nextAct : tour.getActivities()){
|
||||||
// logger.debug(prevAct.toString() + " arrTime=" + prevAct.getArrTime() + " endTime=" + prevAct.getEndTime());
|
if(deliveryAct2Insert.getTheoreticalLatestOperationStartTime() < prevAct.getTheoreticalEarliestOperationStartTime()){
|
||||||
// logger.debug(deliveryAct2Insert.toString() + " arrTime=" + deliveryAct2Insert.getArrTime() + " endTime=" + deliveryAct2Insert.getEndTime());
|
break;
|
||||||
// logger.debug(nextAct.toString() + " arrTime=" + nextAct.getArrTime() + " endTime=" + nextAct.getEndTime());
|
}
|
||||||
double nextCostInOriginalTour = states.getActivityState(nextAct,StateTypes.COSTS).toDouble();
|
|
||||||
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())){
|
||||||
double mc = calculate(prevAct, nextAct, deliveryAct2Insert, newDriver, newVehicle, bestCost, nextCostInOriginalTour - prevCostInOriginalTour);
|
Marginals mc = calculate(iFacts, prevAct, nextAct, deliveryAct2Insert);
|
||||||
if(mc < bestCost){
|
if(mc != null){
|
||||||
bestCost = mc;
|
if(mc.getAdditionalCosts() < bestCost){
|
||||||
insertionIndex = actIndex;
|
bestCost = mc.getAdditionalCosts();
|
||||||
|
bestMarginals = mc;
|
||||||
|
insertionIndex = actIndex;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
prevCostInOriginalTour = nextCostInOriginalTour;
|
|
||||||
prevAct = nextAct;
|
prevAct = nextAct;
|
||||||
actIndex++;
|
actIndex++;
|
||||||
}
|
}
|
||||||
End nextAct = end;
|
End nextAct = end;
|
||||||
// logger.debug(prevAct.toString() + " arrTime=" + prevAct.getArrTime() + " endTime=" + prevAct.getEndTime());
|
|
||||||
// logger.debug(deliveryAct2Insert.toString() + " arrTime=" + deliveryAct2Insert.getArrTime() + " endTime=" + deliveryAct2Insert.getEndTime());
|
|
||||||
// logger.debug(nextAct.toString() + " arrTime=" + nextAct.getArrTime() + " endTime=" + nextAct.getEndTime());
|
|
||||||
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())){
|
||||||
double oldRouteCosts = states.getRouteState(currentRoute, StateTypes.COSTS).toDouble();
|
Marginals mc = calculate(iFacts, prevAct, nextAct, deliveryAct2Insert);
|
||||||
double mc = calculate(prevAct, nextAct, deliveryAct2Insert, newDriver, newVehicle, bestCost, oldRouteCosts - prevCostInOriginalTour);
|
if(mc != null) {
|
||||||
if(mc < bestCost){
|
if(mc.getAdditionalCosts() < bestCost){
|
||||||
bestCost = mc;
|
bestCost = mc.getAdditionalCosts();
|
||||||
insertionIndex = actIndex;
|
bestMarginals = mc;
|
||||||
|
insertionIndex = actIndex;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -151,6 +151,7 @@ final class CalculatesServiceInsertion implements JobInsertionCalculator{
|
||||||
}
|
}
|
||||||
InsertionData insertionData = new InsertionData(bestCost, InsertionData.NO_INDEX, insertionIndex, newVehicle, newDriver);
|
InsertionData insertionData = new InsertionData(bestCost, InsertionData.NO_INDEX, insertionIndex, newVehicle, newDriver);
|
||||||
insertionData.setVehicleDepartureTime(newVehicleDepartureTime);
|
insertionData.setVehicleDepartureTime(newVehicleDepartureTime);
|
||||||
|
insertionData.setAdditionalTime(bestMarginals.getAdditionalTime());
|
||||||
return insertionData;
|
return insertionData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -177,47 +178,8 @@ final class CalculatesServiceInsertion implements JobInsertionCalculator{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public double calculate(TourActivity prevAct, TourActivity nextAct, TourActivity newAct, Driver driver, Vehicle vehicle, double bestKnownCosts, double costWithoutNewJob) {
|
public Marginals calculate(InsertionFacts iFacts, TourActivity prevAct, TourActivity nextAct, TourActivity newAct) {
|
||||||
|
return marginalCalculus.calculate(iFacts, prevAct, nextAct, newAct);
|
||||||
double tp_costs_prevAct_newAct = routingCosts.getTransportCost(prevAct.getLocationId(), newAct.getLocationId(), prevAct.getEndTime(), driver, vehicle);
|
|
||||||
double tp_time_prevAct_newAct = routingCosts.getTransportTime(prevAct.getLocationId(), newAct.getLocationId(), prevAct.getEndTime(), driver, vehicle);
|
|
||||||
|
|
||||||
double newAct_arrTime = prevAct.getEndTime() + tp_time_prevAct_newAct;
|
|
||||||
double newAct_operationStartTime = Math.max(newAct_arrTime, newAct.getTheoreticalEarliestOperationStartTime());
|
|
||||||
|
|
||||||
double newAct_endTime = newAct_operationStartTime + newAct.getOperationTime();
|
|
||||||
|
|
||||||
double act_costs_newAct = activityCosts.getActivityCost(newAct, newAct_arrTime, driver, vehicle);
|
|
||||||
|
|
||||||
// if((tp_costs_prevAct_newAct + act_costs_newAct - costWithoutNewJob) > bestKnownCosts){
|
|
||||||
// return Double.MAX_VALUE;
|
|
||||||
// }
|
|
||||||
|
|
||||||
double tp_costs_newAct_nextAct = routingCosts.getTransportCost(newAct.getLocationId(), nextAct.getLocationId(), newAct_endTime, driver, vehicle);
|
|
||||||
double tp_time_newAct_nextAct = routingCosts.getTransportTime(newAct.getLocationId(), nextAct.getLocationId(), newAct_endTime, driver, vehicle);
|
|
||||||
|
|
||||||
double nextAct_arrTime = newAct_endTime + tp_time_newAct_nextAct;
|
|
||||||
double act_costs_nextAct = activityCosts.getActivityCost(nextAct, nextAct_arrTime, driver, vehicle);
|
|
||||||
|
|
||||||
// logger.debug("nextActArrTime="+nextAct_arrTime);
|
|
||||||
|
|
||||||
double totalCosts = tp_costs_prevAct_newAct + tp_costs_newAct_nextAct + act_costs_newAct + act_costs_nextAct;
|
|
||||||
|
|
||||||
if(totalCosts - costWithoutNewJob > bestKnownCosts){
|
|
||||||
return Double.MAX_VALUE;
|
|
||||||
}
|
|
||||||
if(nextAct_arrTime > getLatestOperationStart(nextAct)){
|
|
||||||
return Double.MAX_VALUE;
|
|
||||||
}
|
|
||||||
return totalCosts - costWithoutNewJob;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private double getLatestOperationStart(TourActivity act) {
|
|
||||||
if(act instanceof End) {
|
|
||||||
return end.getTheoreticalLatestOperationStartTime();
|
|
||||||
}
|
|
||||||
return states.getActivityState(act, StateTypes.LATEST_OPERATION_START_TIME).toDouble();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,208 +0,0 @@
|
||||||
/*******************************************************************************
|
|
||||||
* Copyright (c) 2011 Stefan Schroeder.
|
|
||||||
* eMail: stefan.schroeder@kit.edu
|
|
||||||
*
|
|
||||||
* All rights reserved. This program and the accompanying materials
|
|
||||||
* are made available under the terms of the GNU Public License v2.0
|
|
||||||
* which accompanies this distribution, and is available at
|
|
||||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|
||||||
*
|
|
||||||
* Contributors:
|
|
||||||
* Stefan Schroeder - initial API and implementation
|
|
||||||
******************************************************************************/
|
|
||||||
package algorithms;
|
|
||||||
|
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
|
|
||||||
import util.Neighborhood;
|
|
||||||
|
|
||||||
import algorithms.RouteStates.ActivityState;
|
|
||||||
import algorithms.StateManager.State;
|
|
||||||
import algorithms.StateManager.States;
|
|
||||||
import basics.Job;
|
|
||||||
import basics.Service;
|
|
||||||
import basics.costs.VehicleRoutingActivityCosts;
|
|
||||||
import basics.costs.VehicleRoutingTransportCosts;
|
|
||||||
import basics.route.Driver;
|
|
||||||
import basics.route.End;
|
|
||||||
import basics.route.ServiceActivity;
|
|
||||||
import basics.route.Start;
|
|
||||||
import basics.route.TourActivities;
|
|
||||||
import basics.route.TourActivity;
|
|
||||||
import basics.route.Vehicle;
|
|
||||||
import basics.route.VehicleRoute;
|
|
||||||
import basics.route.VehicleImpl.NoVehicle;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
final class CalculatesServiceInsertionWithTriangleInequality implements JobInsertionCalculator{
|
|
||||||
|
|
||||||
class Marginals {
|
|
||||||
private double marginalCosts;
|
|
||||||
private double marginalTime;
|
|
||||||
public Marginals(double marginalCosts, double marginalTime) {
|
|
||||||
super();
|
|
||||||
this.marginalCosts = marginalCosts;
|
|
||||||
this.marginalTime = marginalTime;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @return the marginalCosts
|
|
||||||
*/
|
|
||||||
public double getMarginalCosts() {
|
|
||||||
return marginalCosts;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @return the marginalTime
|
|
||||||
*/
|
|
||||||
public double getMarginalTime() {
|
|
||||||
return marginalTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(CalculatesServiceInsertionWithTriangleInequality.class);
|
|
||||||
|
|
||||||
private StateManager routeStates;
|
|
||||||
|
|
||||||
private VehicleRoutingTransportCosts routingCosts;
|
|
||||||
|
|
||||||
private Start start;
|
|
||||||
|
|
||||||
private End end;
|
|
||||||
|
|
||||||
private HardConstraint hardConstraint = new HardConstraint() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean fulfilled(InsertionScenario iScenario) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public void setHardConstraint(HardConstraint hardConstraint){
|
|
||||||
this.hardConstraint = hardConstraint;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Neighborhood neighborhood = new Neighborhood() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean areNeighbors(String location1, String location2) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void setNeighborhood(Neighborhood neighborhood) {
|
|
||||||
this.neighborhood = neighborhood;
|
|
||||||
logger.info("initialise neighborhood " + neighborhood);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setActivityStates(StateManager activityStates2){
|
|
||||||
this.routeStates = activityStates2;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CalculatesServiceInsertionWithTriangleInequality(VehicleRoutingTransportCosts vehicleRoutingTransportCosts, VehicleRoutingActivityCosts vehicleRoutingActivityCosts) {
|
|
||||||
super();
|
|
||||||
this.routingCosts = vehicleRoutingTransportCosts;
|
|
||||||
logger.info("initialise " + this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "[name=calculatesServiceInsertion]";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates the marginal cost of inserting job i locally. This is based on the
|
|
||||||
* assumption that cost changes can entirely covered by only looking at the predecessor i-1 and its successor i+1.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public InsertionData calculate(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.");
|
|
||||||
|
|
||||||
TourActivities tour = currentRoute.getTourActivities();
|
|
||||||
Marginals bestMarginals = new Marginals(bestKnownCosts,Double.MAX_VALUE);
|
|
||||||
Service service = (Service)jobToInsert;
|
|
||||||
|
|
||||||
if(getCurrentLoad(currentRoute) + service.getCapacityDemand() > newVehicle.getCapacity()){
|
|
||||||
return InsertionData.noInsertionFound();
|
|
||||||
}
|
|
||||||
int insertionIndex = InsertionData.NO_INDEX;
|
|
||||||
|
|
||||||
TourActivity deliveryAct2Insert = ServiceActivity.newInstance(service);
|
|
||||||
|
|
||||||
initialiseStartAndEnd(newVehicle, newVehicleDepartureTime);
|
|
||||||
|
|
||||||
TourActivity prevAct = start;
|
|
||||||
int actIndex = 0;
|
|
||||||
for(TourActivity nextAct : tour.getActivities()){
|
|
||||||
if(neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), prevAct.getLocationId()) && neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), nextAct.getLocationId())){
|
|
||||||
Marginals mc = calculate(prevAct, nextAct, deliveryAct2Insert, newDriver, newVehicle);
|
|
||||||
if(mc.getMarginalCosts() < bestMarginals.getMarginalCosts()){
|
|
||||||
bestMarginals = mc;
|
|
||||||
insertionIndex = actIndex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
prevAct = nextAct;
|
|
||||||
actIndex++;
|
|
||||||
}
|
|
||||||
End nextAct = end;
|
|
||||||
if(neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), prevAct.getLocationId()) && neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), nextAct.getLocationId())){
|
|
||||||
Marginals mc = calculate(prevAct, nextAct, deliveryAct2Insert, newDriver, newVehicle);
|
|
||||||
if(mc.getMarginalCosts() < bestMarginals.getMarginalCosts()){
|
|
||||||
bestMarginals = mc;
|
|
||||||
insertionIndex = actIndex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(insertionIndex == InsertionData.NO_INDEX) {
|
|
||||||
return InsertionData.noInsertionFound();
|
|
||||||
}
|
|
||||||
InsertionData insertionData = new InsertionData(bestMarginals.getMarginalCosts(), InsertionData.NO_INDEX, insertionIndex, newVehicle, newDriver);
|
|
||||||
insertionData.setVehicleDepartureTime(newVehicleDepartureTime);
|
|
||||||
insertionData.setAdditionalTime(bestMarginals.getMarginalTime());
|
|
||||||
return insertionData;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getCurrentLoad(VehicleRoute currentRoute) {
|
|
||||||
return (int) routeStates.getRouteState(currentRoute, StateTypes.LOAD).toDouble();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initialiseStartAndEnd(final Vehicle newVehicle, double newVehicleDepartureTime) {
|
|
||||||
if(start == null){
|
|
||||||
start = Start.newInstance(newVehicle.getLocationId(), newVehicle.getEarliestDeparture(), newVehicle.getLatestArrival());
|
|
||||||
start.setEndTime(newVehicleDepartureTime);
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
start.setLocationId(newVehicle.getLocationId());
|
|
||||||
start.setTheoreticalEarliestOperationStartTime(newVehicle.getEarliestDeparture());
|
|
||||||
start.setTheoreticalLatestOperationStartTime(newVehicle.getLatestArrival());
|
|
||||||
start.setEndTime(newVehicleDepartureTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(end == null){
|
|
||||||
end = End.newInstance(newVehicle.getLocationId(), 0.0, newVehicle.getLatestArrival());
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
end.setLocationId(newVehicle.getLocationId());
|
|
||||||
end.setTheoreticalEarliestOperationStartTime(newVehicleDepartureTime);
|
|
||||||
end.setTheoreticalLatestOperationStartTime(newVehicle.getLatestArrival());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Marginals calculate(TourActivity prevAct, TourActivity nextAct, TourActivity newAct, Driver driver, Vehicle vehicle) {
|
|
||||||
|
|
||||||
double tp_costs_prevAct_newAct = routingCosts.getTransportCost(prevAct.getLocationId(), newAct.getLocationId(), prevAct.getEndTime(), driver, vehicle);
|
|
||||||
double tp_time_prevAct_newAct = routingCosts.getTransportTime(prevAct.getLocationId(), newAct.getLocationId(), prevAct.getEndTime(), driver, vehicle);
|
|
||||||
|
|
||||||
double tp_costs_newAct_nextAct = routingCosts.getTransportCost(newAct.getLocationId(), nextAct.getLocationId(), 0.0, driver, vehicle);
|
|
||||||
double tp_time_newAct_nextAct = routingCosts.getTransportTime(newAct.getLocationId(), nextAct.getLocationId(), 0.0, driver, vehicle);
|
|
||||||
|
|
||||||
double tp_costs_prevAct_nextAct = routingCosts.getTransportCost(prevAct.getLocationId(), nextAct.getLocationId(), 0.0, driver, vehicle);
|
|
||||||
double tp_time_prevAct_nextAct = routingCosts.getTransportTime(prevAct.getLocationId(), nextAct.getLocationId(), 0.0, driver, vehicle);
|
|
||||||
|
|
||||||
return new Marginals(tp_costs_prevAct_newAct + tp_costs_newAct_nextAct - tp_costs_prevAct_nextAct, tp_time_prevAct_newAct + tp_time_newAct_nextAct - tp_time_prevAct_nextAct);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -22,18 +22,10 @@ package algorithms;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.apache.commons.configuration.XMLConfiguration;
|
|
||||||
|
|
||||||
import util.NeighborhoodImpl;
|
|
||||||
|
|
||||||
import basics.VehicleRoutingProblem;
|
import basics.VehicleRoutingProblem;
|
||||||
import basics.VehicleRoutingProblem.FleetComposition;
|
|
||||||
import basics.algo.InsertionListener;
|
import basics.algo.InsertionListener;
|
||||||
import basics.algo.VehicleRoutingAlgorithmListeners.PrioritizedVRAListener;
|
import basics.algo.VehicleRoutingAlgorithmListeners.PrioritizedVRAListener;
|
||||||
import basics.algo.VehicleRoutingAlgorithmListeners.Priority;
|
|
||||||
import basics.costs.VehicleRoutingActivityCosts;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -222,11 +214,10 @@ class CalculatorBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
private CalculatorPlusListeners createStandardLocal(VehicleRoutingProblem vrp, StateManager activityStates2){
|
private CalculatorPlusListeners createStandardLocal(VehicleRoutingProblem vrp, StateManager activityStates2){
|
||||||
JobInsertionCalculator standardServiceInsertion = new CalculatesServiceInsertion(vrp.getTransportCosts(), vrp.getActivityCosts());
|
MarginalsCalculus defaultCalc = new MarginalsCalculusDefault(vrp.getTransportCosts(), vrp.getActivityCosts(), new HardConstraints.HardTimeWindowConstraint(activityStates2) );
|
||||||
|
JobInsertionCalculator standardServiceInsertion = new CalculatesServiceInsertion(defaultCalc, new HardConstraints.HardLoadConstraint(activityStates2));
|
||||||
|
|
||||||
((CalculatesServiceInsertion) standardServiceInsertion).setStates(activityStates2);
|
|
||||||
((CalculatesServiceInsertion) standardServiceInsertion).setNeighborhood(vrp.getNeighborhood());
|
((CalculatesServiceInsertion) standardServiceInsertion).setNeighborhood(vrp.getNeighborhood());
|
||||||
((CalculatesServiceInsertion) standardServiceInsertion).setHardConstraint(new HardConstraints.HardLoadConstraint(activityStates2));
|
|
||||||
CalculatorPlusListeners calcPlusListeners = new CalculatorPlusListeners(standardServiceInsertion);
|
CalculatorPlusListeners calcPlusListeners = new CalculatorPlusListeners(standardServiceInsertion);
|
||||||
|
|
||||||
return calcPlusListeners;
|
return calcPlusListeners;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
package algorithms;
|
|
||||||
|
|
||||||
interface HardConstraint {
|
|
||||||
|
|
||||||
public boolean fulfilled(InsertionScenario iScenario);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,10 +1,23 @@
|
||||||
package algorithms;
|
package algorithms;
|
||||||
|
|
||||||
import basics.Service;
|
import basics.Service;
|
||||||
|
import basics.route.TourActivity;
|
||||||
|
|
||||||
class HardConstraints {
|
class HardConstraints {
|
||||||
|
|
||||||
static class HardLoadConstraint implements HardConstraint{
|
interface HardRouteLevelConstraint {
|
||||||
|
|
||||||
|
public boolean fulfilled(InsertionScenario iScenario);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
interface HardActivityLevelConstraint {
|
||||||
|
|
||||||
|
public boolean fulfilled(InsertionFacts iFacts, TourActivity act, double arrTime);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static class HardLoadConstraint implements HardRouteLevelConstraint{
|
||||||
|
|
||||||
private StateManager states;
|
private StateManager states;
|
||||||
|
|
||||||
|
|
@ -22,6 +35,24 @@ class HardConstraints {
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class HardTimeWindowConstraint implements HardActivityLevelConstraint {
|
||||||
|
|
||||||
|
private StateManager states;
|
||||||
|
|
||||||
|
public HardTimeWindowConstraint(StateManager states) {
|
||||||
|
super();
|
||||||
|
this.states = states;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean fulfilled(InsertionFacts iFacts, TourActivity act, double arrTime) {
|
||||||
|
if(arrTime > states.getActivityState(act, StateTypes.LATEST_OPERATION_START_TIME).toDouble()){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
27
jsprit-core/src/main/java/algorithms/Marginals.java
Normal file
27
jsprit-core/src/main/java/algorithms/Marginals.java
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
class Marginals {
|
||||||
|
|
||||||
|
private double additionalCosts;
|
||||||
|
private double additionalTime;
|
||||||
|
public Marginals(double additionalCosts, double additionalTime) {
|
||||||
|
super();
|
||||||
|
this.additionalCosts = additionalCosts;
|
||||||
|
this.additionalTime = additionalTime;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @return the additionalCosts
|
||||||
|
*/
|
||||||
|
public double getAdditionalCosts() {
|
||||||
|
return additionalCosts;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @return the additionalTime
|
||||||
|
*/
|
||||||
|
public double getAdditionalTime() {
|
||||||
|
return additionalTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import basics.route.TourActivity;
|
||||||
|
|
||||||
|
interface MarginalsCalculus {
|
||||||
|
|
||||||
|
Marginals calculate(InsertionFacts iFacts, TourActivity prevAct, TourActivity nextAct, TourActivity newAct);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import algorithms.HardConstraints.HardActivityLevelConstraint;
|
||||||
|
import basics.costs.VehicleRoutingActivityCosts;
|
||||||
|
import basics.costs.VehicleRoutingTransportCosts;
|
||||||
|
import basics.route.TourActivity;
|
||||||
|
|
||||||
|
class MarginalsCalculusDefault implements MarginalsCalculus{
|
||||||
|
|
||||||
|
private HardActivityLevelConstraint hardConstraint;
|
||||||
|
|
||||||
|
private VehicleRoutingTransportCosts routingCosts;
|
||||||
|
private VehicleRoutingActivityCosts activityCosts;
|
||||||
|
|
||||||
|
public MarginalsCalculusDefault(VehicleRoutingTransportCosts routingCosts, VehicleRoutingActivityCosts actCosts, HardActivityLevelConstraint hardActivityLevelConstraint) {
|
||||||
|
super();
|
||||||
|
this.routingCosts = routingCosts;
|
||||||
|
this.activityCosts = actCosts;
|
||||||
|
this.hardConstraint = hardActivityLevelConstraint;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Marginals calculate(InsertionFacts iFacts, TourActivity prevAct, TourActivity nextAct, TourActivity newAct) {
|
||||||
|
double tp_costs_prevAct_newAct = routingCosts.getTransportCost(prevAct.getLocationId(), newAct.getLocationId(), prevAct.getEndTime(), iFacts.getNewDriver(), iFacts.getNewVehicle());
|
||||||
|
double tp_time_prevAct_newAct = routingCosts.getTransportTime(prevAct.getLocationId(), newAct.getLocationId(), prevAct.getEndTime(), iFacts.getNewDriver(), iFacts.getNewVehicle());
|
||||||
|
|
||||||
|
double newAct_arrTime = prevAct.getEndTime() + tp_time_prevAct_newAct;
|
||||||
|
|
||||||
|
if(!hardConstraint.fulfilled(iFacts, newAct, newAct_arrTime)){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
double newAct_operationStartTime = Math.max(newAct_arrTime, newAct.getTheoreticalEarliestOperationStartTime());
|
||||||
|
|
||||||
|
double newAct_endTime = newAct_operationStartTime + newAct.getOperationTime();
|
||||||
|
|
||||||
|
double act_costs_newAct = activityCosts.getActivityCost(newAct, newAct_arrTime, iFacts.getNewDriver(), iFacts.getNewVehicle());
|
||||||
|
|
||||||
|
double tp_costs_newAct_nextAct = routingCosts.getTransportCost(newAct.getLocationId(), nextAct.getLocationId(), newAct_endTime, iFacts.getNewDriver(), iFacts.getNewVehicle());
|
||||||
|
double tp_time_newAct_nextAct = routingCosts.getTransportTime(newAct.getLocationId(), nextAct.getLocationId(), newAct_endTime, iFacts.getNewDriver(), iFacts.getNewVehicle());
|
||||||
|
|
||||||
|
double nextAct_arrTime = newAct_endTime + tp_time_newAct_nextAct;
|
||||||
|
|
||||||
|
if(!hardConstraint.fulfilled(iFacts, nextAct, nextAct_arrTime)){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
double act_costs_nextAct = activityCosts.getActivityCost(nextAct, nextAct_arrTime, iFacts.getNewDriver(), iFacts.getNewVehicle());
|
||||||
|
|
||||||
|
double totalCosts = tp_costs_prevAct_newAct + tp_costs_newAct_nextAct + act_costs_newAct + act_costs_nextAct;
|
||||||
|
|
||||||
|
double oldCosts;
|
||||||
|
if(iFacts.getRoute().isEmpty()){
|
||||||
|
oldCosts = 0.0;
|
||||||
|
}
|
||||||
|
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 actCost_nextAct = activityCosts.getActivityCost(nextAct, arrTime_nextAct, iFacts.getRoute().getDriver(), iFacts.getRoute().getVehicle());
|
||||||
|
oldCosts = tp_costs_prevAct_nextAct + actCost_nextAct;
|
||||||
|
}
|
||||||
|
|
||||||
|
double additionalCosts = totalCosts - oldCosts;
|
||||||
|
double additionalTime = nextAct_arrTime - nextAct.getArrTime();
|
||||||
|
|
||||||
|
return new Marginals(additionalCosts,additionalTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -151,8 +151,8 @@ public class GendreauPostOptTest {
|
||||||
|
|
||||||
activityCosts = new ExampleActivityCostFunction();
|
activityCosts = new ExampleActivityCostFunction();
|
||||||
|
|
||||||
CalculatesServiceInsertion standardServiceInsertion = new CalculatesServiceInsertion(cost, activityCosts);
|
CalculatesServiceInsertion standardServiceInsertion = new CalculatesServiceInsertion(new MarginalsCalculusDefault(cost, activityCosts, new HardConstraints.HardTimeWindowConstraint(states)), new HardConstraints.HardLoadConstraint(states));
|
||||||
standardServiceInsertion.setStates(states);
|
|
||||||
CalculatesServiceInsertionConsideringFixCost withFixCost = new CalculatesServiceInsertionConsideringFixCost(standardServiceInsertion, states);
|
CalculatesServiceInsertionConsideringFixCost withFixCost = new CalculatesServiceInsertionConsideringFixCost(standardServiceInsertion, states);
|
||||||
withFixCost.setWeightOfFixCost(1.2);
|
withFixCost.setWeightOfFixCost(1.2);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -156,8 +156,7 @@ public class TestCalculatesServiceInsertion {
|
||||||
|
|
||||||
ExampleActivityCostFunction activityCosts = new ExampleActivityCostFunction();
|
ExampleActivityCostFunction activityCosts = new ExampleActivityCostFunction();
|
||||||
|
|
||||||
serviceInsertion = new CalculatesServiceInsertion(costs, activityCosts);
|
serviceInsertion = new CalculatesServiceInsertion(new MarginalsCalculusDefault(costs, activityCosts, new HardConstraints.HardTimeWindowConstraint(states)), new HardConstraints.HardLoadConstraint(states));
|
||||||
serviceInsertion.setStates(states);
|
|
||||||
|
|
||||||
stateUpdater = new UpdateStates(states, costs, activityCosts);
|
stateUpdater = new UpdateStates(states, costs, activityCosts);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
<construction>
|
<construction>
|
||||||
<insertion name="bestInsertion">
|
<insertion name="bestInsertion">
|
||||||
|
|
||||||
</insertion>
|
</insertion>
|
||||||
</construction>
|
</construction>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,19 +24,15 @@ import java.io.File;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
import readers.SolomonReader;
|
import readers.SolomonReader;
|
||||||
import algorithms.GreedySchrimpfFactory;
|
|
||||||
import algorithms.SchrimpfFactory;
|
|
||||||
import algorithms.VehicleRoutingAlgorithms;
|
import algorithms.VehicleRoutingAlgorithms;
|
||||||
import algorithms.selectors.SelectBest;
|
import algorithms.selectors.SelectBest;
|
||||||
import analysis.AlgorithmSearchProgressChartListener;
|
import analysis.AlgorithmSearchProgressChartListener;
|
||||||
import analysis.SolutionPlotter;
|
import analysis.SolutionPlotter;
|
||||||
import analysis.SolutionPrinter;
|
import analysis.SolutionPrinter;
|
||||||
import analysis.SolutionPrinter.Print;
|
import analysis.SolutionPrinter.Print;
|
||||||
import analysis.StopWatch;
|
|
||||||
import basics.VehicleRoutingAlgorithm;
|
import basics.VehicleRoutingAlgorithm;
|
||||||
import basics.VehicleRoutingProblem;
|
import basics.VehicleRoutingProblem;
|
||||||
import basics.VehicleRoutingProblemSolution;
|
import basics.VehicleRoutingProblemSolution;
|
||||||
import basics.algo.VehicleRoutingAlgorithmListeners.Priority;
|
|
||||||
|
|
||||||
public class SolomonExample {
|
public class SolomonExample {
|
||||||
|
|
||||||
|
|
@ -76,9 +72,10 @@ public class SolomonExample {
|
||||||
*
|
*
|
||||||
* The algorithm can be defined and configured in an xml-file.
|
* The algorithm can be defined and configured in an xml-file.
|
||||||
*/
|
*/
|
||||||
VehicleRoutingAlgorithm vra = new SchrimpfFactory().createAlgorithm(vrp);
|
// VehicleRoutingAlgorithm vra = new SchrimpfFactory().createAlgorithm(vrp);
|
||||||
// VehicleRoutingAlgorithm vra = VehicleRoutingAlgorithms.readAndCreateAlgorithm(vrp, "input/algorithmConfig_solomon.xml");
|
VehicleRoutingAlgorithm vra = VehicleRoutingAlgorithms.readAndCreateAlgorithm(vrp, "input/algorithmConfig_solomon.xml");
|
||||||
vra.getAlgorithmListeners().addListener(new AlgorithmSearchProgressChartListener("output/sol_progress.png"));
|
vra.setPrematureBreak(100);
|
||||||
|
// vra.getAlgorithmListeners().addListener(new AlgorithmSearchProgressChartListener("output/sol_progress.png"));
|
||||||
/*
|
/*
|
||||||
* Solve the problem.
|
* Solve the problem.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue