1
0
Fork 0
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:
oblonski 2016-11-02 14:23:23 +01:00
parent 4542f8370d
commit f8ea447cb9
No known key found for this signature in database
GPG key ID: 179DE487285680D1
2 changed files with 237 additions and 0 deletions

View file

@ -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);
}
}
}

View file

@ -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;
}
}