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

introduce new stateContainer for route and activityStates

This commit is contained in:
Stefan Schroeder 2013-08-19 15:08:34 +02:00
parent 3f7d6b8b01
commit 50ca0971a5
11 changed files with 114 additions and 378 deletions

View file

@ -1,107 +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 algorithms.RouteStates.ActivityState;
import basics.costs.VehicleRoutingActivityCosts;
import basics.costs.VehicleRoutingTransportCosts;
import basics.route.Driver;
import basics.route.End;
import basics.route.Start;
import basics.route.TourActivity;
import basics.route.Vehicle;
import basics.route.VehicleRoute;
final class CalculatesActivityInsertionWithHardTimeWindows {
private static Logger logger = Logger.getLogger(CalculatesActivityInsertionWithHardTimeWindows.class);
private RouteStates routeStates;
private VehicleRoutingTransportCosts routingCosts;
private VehicleRoutingActivityCosts activityCosts;
public CalculatesActivityInsertionWithHardTimeWindows(RouteStates activityStates, VehicleRoutingTransportCosts routingCosts, VehicleRoutingActivityCosts activityCosts){
this.routeStates = activityStates;
this.routingCosts = routingCosts;
this.activityCosts = activityCosts;
logger.info("initialise " + this);
}
public double calculate(VehicleRoute vehicleRoute, TourActivity prevAct, TourActivity nextAct, TourActivity newAct, Driver driver, Vehicle vehicle) {
boolean prevIsStart = false;
if(prevAct instanceof Start){
prevIsStart = true;
}
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);
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);
double activityInsertionCosts;
double totalCosts = tp_costs_prevAct_newAct + tp_costs_newAct_nextAct + act_costs_newAct + act_costs_nextAct;
if(nextAct_arrTime > getLatestOperationStart(nextAct)){
activityInsertionCosts = Double.MAX_VALUE;
}
else if(vehicleRoute.isEmpty()){
activityInsertionCosts = totalCosts;
}
else{
double oldCostOfPrevAct;
if(prevIsStart) oldCostOfPrevAct = 0.0;
else oldCostOfPrevAct = state(prevAct).getCurrentCost();
double oldCostOfNextAct;
if(nextAct instanceof End) oldCostOfNextAct = routeStates.getRouteState(vehicleRoute).getCosts();
else oldCostOfNextAct = state(nextAct).getCurrentCost();
activityInsertionCosts = (totalCosts) - (oldCostOfNextAct-oldCostOfPrevAct);
}
return activityInsertionCosts;
}
private ActivityState state(TourActivity act) {
return routeStates.getState(act);
}
private double getLatestOperationStart(TourActivity act) {
if(state(act) != null){
return state(act).getLatestOperationStart();
}
return act.getTheoreticalLatestOperationStartTime();
}
@Override
public String toString() {
return "[name=calculatesHardTimeWindowActivityInsertion]";
}
}

View file

@ -112,7 +112,7 @@ final class CalculatesServiceInsertion implements JobInsertionCalculator{
for(TourActivity nextAct : tour.getActivities()){
double nextCostInOriginalTour = state(nextAct).getCurrentCost();
if(neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), prevAct.getLocationId()) && neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), nextAct.getLocationId())){
double mc = calculate(tour, prevAct, nextAct, deliveryAct2Insert, newDriver, newVehicle, bestCost, nextCostInOriginalTour - prevCostInOriginalTour);
double mc = calculate(prevAct, nextAct, deliveryAct2Insert, newDriver, newVehicle, bestCost, nextCostInOriginalTour - prevCostInOriginalTour);
if(mc < bestCost){
bestCost = mc;
insertionIndex = actIndex;
@ -124,7 +124,7 @@ final class CalculatesServiceInsertion implements JobInsertionCalculator{
}
End nextAct = end;
if(neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), prevAct.getLocationId()) && neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), nextAct.getLocationId())){
double mc = calculate(tour, prevAct, nextAct, deliveryAct2Insert, newDriver, newVehicle, bestCost, routeStates.getRouteState(currentRoute).getCosts() - prevCostInOriginalTour);
double mc = calculate(prevAct, nextAct, deliveryAct2Insert, newDriver, newVehicle, bestCost, routeStates.getRouteState(currentRoute).getCosts() - prevCostInOriginalTour);
if(mc < bestCost){
bestCost = mc;
insertionIndex = actIndex;
@ -162,7 +162,7 @@ final class CalculatesServiceInsertion implements JobInsertionCalculator{
}
}
public double calculate(TourActivities tour, TourActivity prevAct, TourActivity nextAct, TourActivity newAct, Driver driver, Vehicle vehicle, double bestKnownCosts, double costWithoutNewJob) {
public double calculate(TourActivity prevAct, TourActivity nextAct, TourActivity newAct, Driver driver, Vehicle vehicle, double bestKnownCosts, double costWithoutNewJob) {
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);

View file

@ -97,7 +97,7 @@ class InsertionFactory {
TourStateUpdater tourStateCalculator = new TourStateUpdater(activityStates, vrp.getTransportCosts(), vrp.getActivityCosts());
RouteAlgorithm routeAlgorithm = RouteAlgorithmImpl.newInstance(jic, tourStateCalculator);
// routeAlgorithm.getListeners().add(new VehicleSwitched(vehicleFleetManager));
((RouteAlgorithmImpl) routeAlgorithm).setActivityStates(activityStates);
((RouteAlgorithmImpl) routeAlgorithm).setStates(activityStates);
if(insertionName.equals("bestInsertion")){
if(concurrentInsertion){

View file

@ -1,92 +0,0 @@
/*******************************************************************************
* Copyright (C) 2013 Stefan Schroeder
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contributors:
* Stefan Schroeder - initial API and implementation
******************************************************************************/
package algorithms;
import java.util.Collection;
import basics.Job;
import basics.route.Vehicle;
import basics.route.VehicleRoute;
interface RouteAlgorithm {
interface RouteAlgorithmListener {
}
interface JobRemovedListener extends RouteAlgorithmListener{
public void removed(VehicleRoute route, Job job);
}
interface JobInsertedListener extends RouteAlgorithmListener{
public void inserted(VehicleRoute route, Job job);
}
interface VehicleSwitchedListener extends RouteAlgorithmListener{
public void vehicleSwitched(Vehicle oldVehicle, Vehicle newVehicle);
}
/**
* Calculates the best insertion position and the corresponding marginal costs of inserting the job (according to the insertionCostCalculator).
* This does not affect any input parameter, thus the vehicleRoute and its data will not be changed/affected.
*
* @param VehicleRoute, Job, double
* @return InsertionData
*/
public InsertionData calculateBestInsertion(VehicleRoute vehicleRoute, Job job, double bestKnownPrice);
/**
* Removes job from vehicleRoute and does not update the resulting tour. Thus the tour state might not be valid anymore.
* Note that this changes vehicleRoute!
*
* @return true if job removed successfully, otherwise false
*/
public boolean removeJobWithoutTourUpdate(Job job, VehicleRoute vehicleRoute);
/**
* Removes job from input parameter vehicleRoute AND updates the state of the resulting tour with tourStateCalc.
* Note that this changes para vehicleRoute!
*/
public boolean removeJob(Job job, VehicleRoute vehicleRoute);
/**
* Inserts job into vehicleRoute.getTour().
* Please note, that this changes the parameter vehicleRoute!
*/
public void insertJobWithoutTourUpdate(VehicleRoute vehicleRoute, Job job, InsertionData insertionData);
/**
* Inserts job into vehicleRoute.getTour().
* Please note, that this changes the parameter vehicleRoute!
*/
public void insertJob(Job job, InsertionData insertionData, VehicleRoute vehicleRoute);
/**
* Updates vehicleRoute, i.e. uses the tourStateCalculator to update for example timeWindows and loads on vehicleRoute.getTour()
* Note that this changes the parameter vehicleRoute!
*/
public void updateTour(VehicleRoute vehicleRoute);
public Collection<RouteAlgorithmListener> getListeners();
}

View file

@ -1,171 +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 java.util.ArrayList;
import java.util.Collection;
import org.apache.log4j.Logger;
import algorithms.RouteStates.ActivityState;
import algorithms.InsertionData.NoInsertionFound;
import basics.Job;
import basics.Service;
import basics.route.ServiceActivity;
import basics.route.TourActivity;
import basics.route.Vehicle;
import basics.route.VehicleRoute;
/**
*
* @author stefan schroeder
*
*/
final class RouteAlgorithmImpl implements RouteAlgorithm {
private static Logger logger = Logger.getLogger(RouteAlgorithmImpl.class);
static double NO_DEPARTURE_TIME = -12345.12345;
private String algoDescription = "algorithm to remove and insert jobs from vehicleRoutes. it also calculates marginal costs of the best insertion of a " +
"job into the given vehicle route";
public static RouteAlgorithmImpl newInstance(JobInsertionCalculator jobInsertionCalculator, VehicleRouteUpdater tourStateCalculator){
return new RouteAlgorithmImpl(jobInsertionCalculator, tourStateCalculator);
}
private Collection<RouteAlgorithmListener> listeners = new ArrayList<RouteAlgorithmListener>();
private VehicleRouteUpdater tourCalculator;
private JobInsertionCalculator insertionCostCalculator;
private RouteStates actStates;
public void setActivityStates(RouteStates actStates){
this.actStates = actStates;
}
public ActivityState state(TourActivity act){
return actStates.getState(act);
}
private RouteAlgorithmImpl(JobInsertionCalculator insertionCostCalculator, VehicleRouteUpdater tourCalculator){
this.tourCalculator = tourCalculator;
this.insertionCostCalculator = insertionCostCalculator;
}
public InsertionData calculateBestInsertion(VehicleRoute vehicleRoute, Job job, double bestKnownCost) {
return insertionCostCalculator.calculate(vehicleRoute, job, null, NO_DEPARTURE_TIME, null, bestKnownCost);
}
public boolean removeJobWithoutTourUpdate(Job job, VehicleRoute vehicleRoute) {
boolean removed = vehicleRoute.getTourActivities().removeJob(job);
if(removed){
jobRemoved(vehicleRoute,job);
}
return removed;
}
private void jobRemoved(VehicleRoute vehicleRoute, Job job) {
for(RouteAlgorithmListener l : listeners){
if(l instanceof JobRemovedListener){
((JobRemovedListener) l).removed(vehicleRoute, job);
}
}
}
public boolean removeJob(Job job, VehicleRoute vehicleRoute){
boolean removed = removeJobWithoutTourUpdate(job, vehicleRoute);
if(removed) updateTour(vehicleRoute);
return removed;
}
public void updateTour(VehicleRoute vehicleRoute){
boolean tourIsFeasible = tourCalculator.updateRoute(vehicleRoute);
if(!tourIsFeasible){
throw new IllegalStateException("At this point tour should be feasible. but it is not. \n currentTour=" + vehicleRoute.getTourActivities() +
"\n error sources: check jobInsertionCostCalculators and actInsertionCalculators. somehow an insertion is made, althought a hard constraint is broken. Here, hard constraints refer to \n" +
"hard time-window constraints. If you want to deal with such constraints, make sure a violation is penalized properly (such that it can never be the best insertion position). \n" +
"If you use CalculatesServiceInsertion and CalculatesActivityInsertion, the only hard constraint is the vehicle-capacity constraints. A violation of time-windows must be penalized in \n" +
"the vehicleRouteCostFunction. For example: in handleActivity(....) one can check whether the act start-time is higher than the latestOperationStartTime. If so penalize it with a very high value. \n" +
"For example: \n" +
"public void handleActivity(TourActivity tourAct, double startTime, double endTime) {\n" +
"\tif(startTime > tourAct.getLatestOperationStartTime()){\n" +
"\t\tcost += Double.MAX_VALUE;\n" +
"\t}\n" +
"});");
}
}
@Override
public void insertJobWithoutTourUpdate(VehicleRoute vehicleRoute, Job job, InsertionData insertionData) {
if(insertionData == null || (insertionData instanceof NoInsertionFound)) throw new IllegalStateException("insertionData null. cannot insert job.");
if(job == null) throw new IllegalStateException("cannot insert null-job");
if(!(vehicleRoute.getVehicle().getId().toString().equals(insertionData.getSelectedVehicle().getId().toString()))){
vehicleSwitched(vehicleRoute.getVehicle(),insertionData.getSelectedVehicle());
vehicleRoute.setVehicle(insertionData.getSelectedVehicle(), insertionData.getVehicleDepartureTime());
}
if(job instanceof Service) {
vehicleRoute.getTourActivities().addActivity(insertionData.getDeliveryInsertionIndex(), ServiceActivity.newInstance((Service)job));
vehicleRoute.setDepartureTime(insertionData.getVehicleDepartureTime());
}
else throw new IllegalStateException("neither service nor shipment. this is not supported.");
jobInserted(vehicleRoute,job);
}
private void vehicleSwitched(Vehicle oldVehicle, Vehicle newVehicle) {
for(RouteAlgorithmListener l : listeners){
if(l instanceof VehicleSwitchedListener){
((VehicleSwitchedListener) l).vehicleSwitched(oldVehicle,newVehicle);
}
}
}
private void jobInserted(VehicleRoute vehicleRoute, Job job) {
for(RouteAlgorithmListener l : listeners){
if(l instanceof JobInsertedListener){
((JobInsertedListener) l).inserted(vehicleRoute, job);
}
}
}
public void insertJob(Job job, InsertionData insertionData, VehicleRoute vehicleRoute){
insertJobWithoutTourUpdate(vehicleRoute, job, insertionData);
updateTour(vehicleRoute);
}
@Override
public String toString() {
return algoDescription;
}
public Collection<RouteAlgorithmListener> getListeners() {
return listeners;
}
public void setAlgoDescription(String algoDescription) {
this.algoDescription = algoDescription;
}
}

View file

@ -0,0 +1,7 @@
package algorithms;
class StateTypes {
final static String LOAD = "load";
final static String DURATION = "duration";
}

View file

@ -0,0 +1,50 @@
package algorithms;
import java.util.Map;
import basics.route.TourActivity;
import basics.route.VehicleRoute;
interface StatesContainer {
interface State {
double getState();
}
class StateImpl implements State{
double state;
public StateImpl(double state) {
super();
this.state = state;
}
@Override
public double getState() {
return state;
}
// public void setState(double val){
// state=val;
// }
}
interface States {
// void putState(String key, State state);
State getState(String key);
}
Map<VehicleRoute, States> getRouteStates();
// void put(VehicleRoute route, States states);
Map<TourActivity, States> getActivityStates();
// void put(TourActivity act, States states);
}

View file

@ -0,0 +1,49 @@
package algorithms;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import basics.route.TourActivity;
import basics.route.VehicleRoute;
public class StatesContainerImpl implements StatesContainer{
class StatesImpl implements States{
private Map<String,State> states = new HashMap<String, State>();
public void putState(String key, State state) {
states.put(key, state);
}
@Override
public State getState(String key) {
return states.get(key);
}
}
private Map<VehicleRoute,States> vehicleRoutes = new HashMap<VehicleRoute, StatesContainer.States>();
private Map<TourActivity,States> tourActivities = new HashMap<TourActivity, StatesContainer.States>();
@Override
public Map<VehicleRoute, States> getRouteStates() {
return Collections.unmodifiableMap(vehicleRoutes);
}
public void put(VehicleRoute route, States states) {
vehicleRoutes.put(route, states);
}
@Override
public Map<TourActivity, States> getActivityStates() {
return Collections.unmodifiableMap(tourActivities);
}
public void put(TourActivity act, States states) {
tourActivities.put(act, states);
}
}

View file

@ -61,8 +61,8 @@ class TourStateUpdater implements VehicleRouteUpdater{
forwardUpdate = new UpdateTourStatesForwardInTime(costs, costs, costFunction);
backwardUpdate = new UpdateTourStatesBackwardInTime(costs);
actStates=activityStates;
forwardUpdate.setActivityStates(actStates);
backwardUpdate.setActivityStates(actStates);
forwardUpdate.setStates(actStates);
backwardUpdate.setStates(actStates);
}
/*

View file

@ -46,7 +46,7 @@ class UpdateTourStatesBackwardInTime implements VehicleRouteUpdater{
private RouteStates actStates;
public void setActivityStates(RouteStates actStates){
public void setStates(RouteStates actStates){
this.actStates = actStates;
}

View file

@ -50,7 +50,7 @@ class UpdateTourStatesForwardInTime implements VehicleRouteUpdater{
private boolean activityStatesSet = false;
public void setActivityStates(RouteStates actStates){
public void setStates(RouteStates actStates){
this.routeStates = actStates;
activityStatesSet = true;
}