mirror of
https://github.com/graphhopper/jsprit.git
synced 2020-01-24 07:45:05 +01:00
add max distance feature - related to #285
This commit is contained in:
parent
4542f8370d
commit
f8ea447cb9
2 changed files with 237 additions and 0 deletions
|
|
@ -0,0 +1,120 @@
|
||||||
|
/*
|
||||||
|
* Licensed to GraphHopper GmbH under one or more contributor
|
||||||
|
* license agreements. See the NOTICE file distributed with this work for
|
||||||
|
* additional information regarding copyright ownership.
|
||||||
|
*
|
||||||
|
* GraphHopper GmbH licenses this file to you under the Apache License,
|
||||||
|
* Version 2.0 (the "License"); you may not use this file except in
|
||||||
|
* compliance with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.graphhopper.jsprit.core.algorithm.state;
|
||||||
|
|
||||||
|
import com.graphhopper.jsprit.core.problem.Location;
|
||||||
|
import com.graphhopper.jsprit.core.problem.cost.TransportDistance;
|
||||||
|
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
|
||||||
|
import com.graphhopper.jsprit.core.problem.solution.route.activity.ActivityVisitor;
|
||||||
|
import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity;
|
||||||
|
import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
|
||||||
|
import com.graphhopper.jsprit.core.problem.vehicle.VehicleTypeKey;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by schroeder on 17/05/16.
|
||||||
|
*/
|
||||||
|
public class VehicleDependentTraveledDistance implements StateUpdater, ActivityVisitor {
|
||||||
|
|
||||||
|
static class State {
|
||||||
|
|
||||||
|
Location prevLocation;
|
||||||
|
|
||||||
|
double distance;
|
||||||
|
|
||||||
|
public State(Location prevLocation, double distance) {
|
||||||
|
this.prevLocation = prevLocation;
|
||||||
|
this.distance = distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Location getPrevLocation() {
|
||||||
|
return prevLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getDistance() {
|
||||||
|
return distance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final TransportDistance transportDistance;
|
||||||
|
|
||||||
|
private final StateManager stateManager;
|
||||||
|
|
||||||
|
private final StateId traveledDistanceId;
|
||||||
|
|
||||||
|
private VehicleRoute route;
|
||||||
|
|
||||||
|
private List<Vehicle> uniqueVehicles;
|
||||||
|
|
||||||
|
private Map<VehicleTypeKey,State> states;
|
||||||
|
|
||||||
|
public VehicleDependentTraveledDistance(TransportDistance transportCostMatrices, StateManager stateManager, StateId distanceInRouteId, Collection<Vehicle> vehicles) {
|
||||||
|
this.transportDistance = transportCostMatrices;
|
||||||
|
this.stateManager = stateManager;
|
||||||
|
this.traveledDistanceId = distanceInRouteId;
|
||||||
|
uniqueVehicles = getUniqueVehicles(vehicles);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Vehicle> getUniqueVehicles(Collection<Vehicle> vehicles) {
|
||||||
|
Set<VehicleTypeKey> types = new HashSet<>();
|
||||||
|
List<Vehicle> uniqueVehicles = new ArrayList<>();
|
||||||
|
for(Vehicle v : vehicles){
|
||||||
|
if(!types.contains(v.getVehicleTypeIdentifier())){
|
||||||
|
types.add(v.getVehicleTypeIdentifier());
|
||||||
|
uniqueVehicles.add(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return uniqueVehicles;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void begin(VehicleRoute route) {
|
||||||
|
this.route = route;
|
||||||
|
states = new HashMap<>();
|
||||||
|
for(Vehicle v : uniqueVehicles){
|
||||||
|
State state = new State(v.getStartLocation(),0);
|
||||||
|
states.put(v.getVehicleTypeIdentifier(),state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(TourActivity activity) {
|
||||||
|
for(Vehicle v : uniqueVehicles){
|
||||||
|
State old = states.get(v.getVehicleTypeIdentifier());
|
||||||
|
double distance = old.getDistance();
|
||||||
|
distance += transportDistance.getDistance(old.getPrevLocation(),activity.getLocation(),0,v);
|
||||||
|
stateManager.putActivityState(activity,v,traveledDistanceId,distance);
|
||||||
|
states.put(v.getVehicleTypeIdentifier(),new State(activity.getLocation(),distance));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void finish() {
|
||||||
|
for(Vehicle v : uniqueVehicles){
|
||||||
|
State old = states.get(v.getVehicleTypeIdentifier());
|
||||||
|
double distance = old.getDistance();
|
||||||
|
if(v.isReturnToDepot()) {
|
||||||
|
distance += transportDistance.getDistance(old.getPrevLocation(), v.getEndLocation(), 0, v);
|
||||||
|
}
|
||||||
|
stateManager.putRouteState(route,v,traveledDistanceId, distance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,117 @@
|
||||||
|
/*
|
||||||
|
* Licensed to GraphHopper GmbH under one or more contributor
|
||||||
|
* license agreements. See the NOTICE file distributed with this work for
|
||||||
|
* additional information regarding copyright ownership.
|
||||||
|
*
|
||||||
|
* GraphHopper GmbH licenses this file to you under the Apache License,
|
||||||
|
* Version 2.0 (the "License"); you may not use this file except in
|
||||||
|
* compliance with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.graphhopper.jsprit.core.problem.constraint;
|
||||||
|
|
||||||
|
import com.graphhopper.jsprit.core.algorithm.state.StateId;
|
||||||
|
import com.graphhopper.jsprit.core.algorithm.state.StateManager;
|
||||||
|
import com.graphhopper.jsprit.core.problem.cost.TransportDistance;
|
||||||
|
import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext;
|
||||||
|
import com.graphhopper.jsprit.core.problem.solution.route.activity.DeliverShipment;
|
||||||
|
import com.graphhopper.jsprit.core.problem.solution.route.activity.End;
|
||||||
|
import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity;
|
||||||
|
import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by schroeder on 11/10/16.
|
||||||
|
*/
|
||||||
|
public class MaxDistanceConstraint implements HardActivityConstraint{
|
||||||
|
|
||||||
|
private StateManager stateManager;
|
||||||
|
|
||||||
|
private StateId distanceId;
|
||||||
|
|
||||||
|
private TransportDistance distanceCalculator;
|
||||||
|
|
||||||
|
private Double[] maxDistances;
|
||||||
|
|
||||||
|
public MaxDistanceConstraint(StateManager stateManager, StateId distanceId, TransportDistance distanceCalculator, Map<Vehicle,Double> maxDistancePerVehicleMap) {
|
||||||
|
this.stateManager = stateManager;
|
||||||
|
this.distanceId = distanceId;
|
||||||
|
this.distanceCalculator = distanceCalculator;
|
||||||
|
makeArray(maxDistancePerVehicleMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void makeArray(Map<Vehicle, Double> maxDistances) {
|
||||||
|
int maxIndex = getMaxIndex(maxDistances.keySet());
|
||||||
|
this.maxDistances = new Double[maxIndex];
|
||||||
|
for(Vehicle v : maxDistances.keySet()){
|
||||||
|
this.maxDistances[v.getIndex()]=maxDistances.get(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getMaxIndex(Collection<Vehicle> vehicles) {
|
||||||
|
int index = 0;
|
||||||
|
for(Vehicle v : vehicles){
|
||||||
|
if(v.getIndex() > index) index = v.getIndex();
|
||||||
|
}
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConstraintsStatus fulfilled(JobInsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime) {
|
||||||
|
if(!hasMaxDistance(iFacts.getNewVehicle())) return ConstraintsStatus.FULFILLED;
|
||||||
|
Double currentDistance = 0d;
|
||||||
|
if(!iFacts.getRoute().isEmpty()){
|
||||||
|
currentDistance = stateManager.getRouteState(iFacts.getRoute(),iFacts.getNewVehicle(), distanceId,Double.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
double distanceNewAct2nextAct = distanceCalculator.getDistance(newAct.getLocation(), nextAct.getLocation(), iFacts.getNewDepTime(), iFacts.getNewVehicle());
|
||||||
|
double distancePrevAct2NextAct = distanceCalculator.getDistance(prevAct.getLocation(), nextAct.getLocation(), iFacts.getNewDepTime(), iFacts.getNewVehicle());
|
||||||
|
if(nextAct instanceof End && !iFacts.getNewVehicle().isReturnToDepot()){
|
||||||
|
distanceNewAct2nextAct = 0;
|
||||||
|
distancePrevAct2NextAct = 0;
|
||||||
|
}
|
||||||
|
double distancePrevAct2NewAct = distanceCalculator.getDistance(prevAct.getLocation(), newAct.getLocation(), iFacts.getNewDepTime(), iFacts.getNewVehicle());
|
||||||
|
double additionalDistance = distancePrevAct2NewAct + distanceNewAct2nextAct - distancePrevAct2NextAct;
|
||||||
|
|
||||||
|
double maxDistance = getMaxDistance(iFacts.getNewVehicle());
|
||||||
|
if(currentDistance + additionalDistance > maxDistance) return ConstraintsStatus.NOT_FULFILLED;
|
||||||
|
|
||||||
|
if(newAct instanceof DeliverShipment){
|
||||||
|
int iIndexOfPickup = iFacts.getRelatedActivityContext().getInsertionIndex();
|
||||||
|
TourActivity pickup = iFacts.getAssociatedActivities().get(0);
|
||||||
|
TourActivity actBeforePickup;
|
||||||
|
TourActivity actAfterPickup = iFacts.getRoute().getActivities().get(iIndexOfPickup);
|
||||||
|
if(iIndexOfPickup > 0) actBeforePickup = iFacts.getRoute().getActivities().get(iIndexOfPickup-1);
|
||||||
|
else actBeforePickup = iFacts.getRoute().getStart();
|
||||||
|
double additionalDistanceOfPickup = distanceCalculator.getDistance(actBeforePickup.getLocation(),pickup.getLocation(),0,iFacts.getNewVehicle())
|
||||||
|
+ distanceCalculator.getDistance(pickup.getLocation(),actAfterPickup.getLocation(),0,iFacts.getNewVehicle())
|
||||||
|
- distanceCalculator.getDistance(actBeforePickup.getLocation(), actAfterPickup.getLocation(),0,iFacts.getNewVehicle());
|
||||||
|
|
||||||
|
if(currentDistance + additionalDistance + additionalDistanceOfPickup > maxDistance){
|
||||||
|
return ConstraintsStatus.NOT_FULFILLED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ConstraintsStatus.FULFILLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasMaxDistance(Vehicle newVehicle){
|
||||||
|
return this.maxDistances[newVehicle.getIndex()] != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private double getMaxDistance(Vehicle newVehicle) {
|
||||||
|
Double maxDistance = this.maxDistances[newVehicle.getIndex()];
|
||||||
|
if(maxDistance == null) return Double.MAX_VALUE;
|
||||||
|
return maxDistance;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue