mirror of
https://github.com/graphhopper/jsprit.git
synced 2020-01-24 07:45:05 +01:00
play with bicycle-messenger example
This commit is contained in:
parent
0693ddb071
commit
ebefbb0eb2
3 changed files with 82 additions and 22 deletions
|
|
@ -31,6 +31,7 @@ import jsprit.core.algorithm.recreate.listener.JobInsertedListener;
|
||||||
import jsprit.core.algorithm.ruin.listener.RuinListener;
|
import jsprit.core.algorithm.ruin.listener.RuinListener;
|
||||||
import jsprit.core.algorithm.ruin.listener.RuinListeners;
|
import jsprit.core.algorithm.ruin.listener.RuinListeners;
|
||||||
import jsprit.core.problem.VehicleRoutingProblem;
|
import jsprit.core.problem.VehicleRoutingProblem;
|
||||||
|
import jsprit.core.problem.cost.VehicleRoutingTransportCosts;
|
||||||
import jsprit.core.problem.job.Job;
|
import jsprit.core.problem.job.Job;
|
||||||
import jsprit.core.problem.solution.VehicleRoutingProblemSolution;
|
import jsprit.core.problem.solution.VehicleRoutingProblemSolution;
|
||||||
import jsprit.core.problem.solution.route.ReverseRouteActivityVisitor;
|
import jsprit.core.problem.solution.route.ReverseRouteActivityVisitor;
|
||||||
|
|
@ -69,7 +70,7 @@ public class StateManager implements RouteAndActivityStateGetter, IterationStart
|
||||||
|
|
||||||
private Map<StateId,State> defaultActivityStates = new HashMap<StateId, State>();
|
private Map<StateId,State> defaultActivityStates = new HashMap<StateId, State>();
|
||||||
|
|
||||||
private VehicleRoutingProblem vrp;
|
private VehicleRoutingTransportCosts routingCosts;
|
||||||
|
|
||||||
private boolean updateLoad = false;
|
private boolean updateLoad = false;
|
||||||
|
|
||||||
|
|
@ -77,9 +78,14 @@ public class StateManager implements RouteAndActivityStateGetter, IterationStart
|
||||||
|
|
||||||
public StateManager(VehicleRoutingProblem vrp) {
|
public StateManager(VehicleRoutingProblem vrp) {
|
||||||
super();
|
super();
|
||||||
this.vrp = vrp;
|
this.routingCosts = vrp.getTransportCosts();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public StateManager(VehicleRoutingTransportCosts routingCosts){
|
||||||
|
this.routingCosts = routingCosts;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public void addDefaultRouteState(StateId stateId, State defaultState){
|
public void addDefaultRouteState(StateId stateId, State defaultState){
|
||||||
if(StateFactory.isReservedId(stateId)) StateFactory.throwReservedIdException(stateId.toString());
|
if(StateFactory.isReservedId(stateId)) StateFactory.throwReservedIdException(stateId.toString());
|
||||||
defaultRouteStates.put(stateId, defaultState);
|
defaultRouteStates.put(stateId, defaultState);
|
||||||
|
|
@ -295,7 +301,7 @@ public class StateManager implements RouteAndActivityStateGetter, IterationStart
|
||||||
public void updateTimeWindowStates() {
|
public void updateTimeWindowStates() {
|
||||||
if(!updateTWs){
|
if(!updateTWs){
|
||||||
updateTWs=true;
|
updateTWs=true;
|
||||||
addActivityVisitor(new UpdateTimeWindow(this, vrp.getTransportCosts()));
|
addActivityVisitor(new UpdateTimeWindow(this, routingCosts));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,12 +35,14 @@
|
||||||
<searchStrategies>
|
<searchStrategies>
|
||||||
<searchStrategy name="radialRuinAndRecreate">
|
<searchStrategy name="radialRuinAndRecreate">
|
||||||
<selector name="selectBest"/>
|
<selector name="selectBest"/>
|
||||||
<acceptor name="acceptNewRemoveWorst"/>
|
<acceptor name="schrimpfAcceptance">
|
||||||
|
<alpha>0.01</alpha>
|
||||||
|
<warmup>40</warmup>
|
||||||
|
</acceptor>
|
||||||
<modules>
|
<modules>
|
||||||
<module name="ruin_and_recreate">
|
<module name="ruin_and_recreate">
|
||||||
<ruin name="randomRuin">
|
<ruin name="randomRuin">
|
||||||
<share>0.5</share>
|
<share>0.3</share>
|
||||||
</ruin>
|
</ruin>
|
||||||
<insertion name="bestInsertion"/>
|
<insertion name="bestInsertion"/>
|
||||||
</module>
|
</module>
|
||||||
|
|
@ -56,7 +58,7 @@
|
||||||
<modules>
|
<modules>
|
||||||
<module name="ruin_and_recreate">
|
<module name="ruin_and_recreate">
|
||||||
<ruin id="1" name="radialRuin">
|
<ruin id="1" name="radialRuin">
|
||||||
<share>0.3</share>
|
<share>0.2</share>
|
||||||
</ruin>
|
</ruin>
|
||||||
<insertion name="bestInsertion"/>
|
<insertion name="bestInsertion"/>
|
||||||
</module>
|
</module>
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import jsprit.analysis.toolbox.AlgorithmSearchProgressChartListener;
|
||||||
import jsprit.analysis.toolbox.Plotter;
|
import jsprit.analysis.toolbox.Plotter;
|
||||||
import jsprit.analysis.toolbox.SolutionPrinter;
|
import jsprit.analysis.toolbox.SolutionPrinter;
|
||||||
import jsprit.core.algorithm.VehicleRoutingAlgorithm;
|
import jsprit.core.algorithm.VehicleRoutingAlgorithm;
|
||||||
|
|
@ -31,6 +32,10 @@ import jsprit.core.problem.solution.route.VehicleRoute;
|
||||||
import jsprit.core.problem.solution.route.activity.DeliverShipment;
|
import jsprit.core.problem.solution.route.activity.DeliverShipment;
|
||||||
import jsprit.core.problem.solution.route.activity.ReverseActivityVisitor;
|
import jsprit.core.problem.solution.route.activity.ReverseActivityVisitor;
|
||||||
import jsprit.core.problem.solution.route.activity.TourActivity;
|
import jsprit.core.problem.solution.route.activity.TourActivity;
|
||||||
|
import jsprit.core.problem.solution.route.activity.TourActivity.JobActivity;
|
||||||
|
import jsprit.core.problem.solution.route.state.RouteAndActivityStateGetter;
|
||||||
|
import jsprit.core.problem.solution.route.state.StateFactory;
|
||||||
|
import jsprit.core.problem.vehicle.PenaltyVehicleType;
|
||||||
import jsprit.core.problem.vehicle.Vehicle;
|
import jsprit.core.problem.vehicle.Vehicle;
|
||||||
import jsprit.core.problem.vehicle.VehicleImpl;
|
import jsprit.core.problem.vehicle.VehicleImpl;
|
||||||
import jsprit.core.problem.vehicle.VehicleType;
|
import jsprit.core.problem.vehicle.VehicleType;
|
||||||
|
|
@ -41,32 +46,48 @@ import jsprit.core.util.Solutions;
|
||||||
|
|
||||||
public class BicycleMessenger {
|
public class BicycleMessenger {
|
||||||
|
|
||||||
static class ThreeTimesLessThanDirectRouteConstraint implements HardActivityStateLevelConstraint {
|
static class ThreeTimesLessThanBestDirectRouteConstraint implements HardActivityStateLevelConstraint {
|
||||||
|
|
||||||
private VehicleRoutingTransportCosts routingCosts;
|
private VehicleRoutingTransportCosts routingCosts;
|
||||||
|
|
||||||
|
private RouteAndActivityStateGetter stateManager;
|
||||||
|
|
||||||
//jobId map direct-distance by nearestMessenger
|
//jobId map direct-distance by nearestMessenger
|
||||||
private Map<String,Double> bestMessengers = new HashMap<String, Double>();
|
private Map<String,Double> bestMessengers = new HashMap<String, Double>();
|
||||||
|
|
||||||
public ThreeTimesLessThanDirectRouteConstraint(Map<String, Double> nearestMessengers, VehicleRoutingTransportCosts routingCosts) {
|
public ThreeTimesLessThanBestDirectRouteConstraint(Map<String, Double> nearestMessengers, VehicleRoutingTransportCosts routingCosts, RouteAndActivityStateGetter stateManager) {
|
||||||
this.bestMessengers = nearestMessengers;
|
this.bestMessengers = nearestMessengers;
|
||||||
this.routingCosts = routingCosts;
|
this.routingCosts = routingCosts;
|
||||||
|
this.stateManager = stateManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ConstraintsStatus fulfilled(JobInsertionContext iFacts,TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime) {
|
public ConstraintsStatus fulfilled(JobInsertionContext iFacts,TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime) {
|
||||||
|
double arrivalTime_at_newAct = prevActDepTime + routingCosts.getTransportTime(prevAct.getLocationId(), newAct.getLocationId(), prevActDepTime, iFacts.getNewDriver(), iFacts.getNewVehicle());
|
||||||
|
//local impact
|
||||||
if(newAct instanceof DeliverShipment){
|
if(newAct instanceof DeliverShipment){
|
||||||
double deliveryTime = prevActDepTime + routingCosts.getTransportTime(prevAct.getLocationId(), newAct.getLocationId(), prevActDepTime, iFacts.getNewDriver(), iFacts.getNewVehicle());
|
|
||||||
double directTimeOfNearestMessenger = bestMessengers.get(((DeliverShipment) newAct).getJob().getId());
|
double directTimeOfNearestMessenger = bestMessengers.get(((DeliverShipment) newAct).getJob().getId());
|
||||||
if(deliveryTime > 3 * directTimeOfNearestMessenger){
|
if(arrivalTime_at_newAct > 3 * directTimeOfNearestMessenger){
|
||||||
|
//not fulfilled AND it can never be fulfilled anymore by going forward in route, thus NOT_FULFILLED_BREAK
|
||||||
return ConstraintsStatus.NOT_FULFILLED_BREAK;
|
return ConstraintsStatus.NOT_FULFILLED_BREAK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//impact on whole route, since insertion of newAct shifts all subsequent activities forward in time
|
||||||
|
double departureTime_at_newAct = arrivalTime_at_newAct + newAct.getOperationTime();
|
||||||
|
double deliverTimeAtNextAct = departureTime_at_newAct + routingCosts.getTransportTime(newAct.getLocationId(), nextAct.getLocationId(), departureTime_at_newAct, iFacts.getNewDriver(), iFacts.getNewVehicle());;
|
||||||
|
if(deliverTimeAtNextAct > stateManager.getActivityState(nextAct, StateFactory.createId("latest-activity-start-time")).toDouble()){
|
||||||
|
return ConstraintsStatus.NOT_FULFILLED;
|
||||||
|
}
|
||||||
return ConstraintsStatus.FULFILLED;
|
return ConstraintsStatus.FULFILLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* one does not need this constraint. but it is faster. the earlier the solution-space can be constraint the better/faster.
|
||||||
|
* @author schroeder
|
||||||
|
*
|
||||||
|
*/
|
||||||
static class IgnoreMessengerThatCanNeverMeetTimeRequirements implements HardRouteStateLevelConstraint {
|
static class IgnoreMessengerThatCanNeverMeetTimeRequirements implements HardRouteStateLevelConstraint {
|
||||||
|
|
||||||
private Map<String,Double> bestMessengers = new HashMap<String, Double>();
|
private Map<String,Double> bestMessengers = new HashMap<String, Double>();
|
||||||
|
|
@ -91,29 +112,52 @@ public class BicycleMessenger {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static class UpdateLatestActivityStartTime implements StateUpdater, ReverseActivityVisitor {
|
/**
|
||||||
|
* updates the state "latest-activity-start-time" once route/activity states changed, i.e. when removing or inserting an envelope-activity
|
||||||
|
*
|
||||||
|
* @author schroeder
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static class UpdateLatestActivityStartTimes implements StateUpdater, ReverseActivityVisitor {
|
||||||
|
|
||||||
private StateManager stateManager;
|
private StateManager stateManager;
|
||||||
|
|
||||||
public UpdateLatestActivityStartTime(StateManager stateManager) {
|
private VehicleRoutingTransportCosts routingCosts;
|
||||||
|
|
||||||
|
private Map<String,Double> bestMessengers;
|
||||||
|
|
||||||
|
private VehicleRoute route;
|
||||||
|
|
||||||
|
private TourActivity prevAct;
|
||||||
|
|
||||||
|
private double latestArrivalTime_at_prevAct;
|
||||||
|
|
||||||
|
public UpdateLatestActivityStartTimes(StateManager stateManager, VehicleRoutingTransportCosts routingCosts, Map<String, Double> bestMessengers) {
|
||||||
super();
|
super();
|
||||||
this.stateManager = stateManager;
|
this.stateManager = stateManager;
|
||||||
|
this.routingCosts = routingCosts;
|
||||||
|
this.bestMessengers = bestMessengers;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void begin(VehicleRoute route) {
|
public void begin(VehicleRoute route) {
|
||||||
|
this.route = route;
|
||||||
|
latestArrivalTime_at_prevAct = route.getEnd().getTheoreticalLatestOperationStartTime();
|
||||||
|
prevAct = route.getEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(TourActivity activity) {
|
public void visit(TourActivity activity) {
|
||||||
|
double timeOfNearestMessenger = bestMessengers.get(((JobActivity)activity).getJob().getId());
|
||||||
|
double potentialLatestArrivalTimeAtCurrAct = latestArrivalTime_at_prevAct - routingCosts.getBackwardTransportTime(activity.getLocationId(), prevAct.getLocationId(), latestArrivalTime_at_prevAct, route.getDriver(),route.getVehicle()) - activity.getOperationTime();
|
||||||
|
double latestArrivalTime_at_activity = Math.min(3*timeOfNearestMessenger, potentialLatestArrivalTimeAtCurrAct);
|
||||||
|
stateManager.putActivityState(activity, StateFactory.createId("latest-activity-start-time"), StateFactory.createState(latestArrivalTime_at_activity));
|
||||||
|
latestArrivalTime_at_prevAct = latestArrivalTime_at_activity;
|
||||||
|
prevAct = activity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void finish() {
|
public void finish() {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -130,18 +174,20 @@ public class BicycleMessenger {
|
||||||
|
|
||||||
VehicleRoutingTransportCosts routingCosts = new CrowFlyCosts(problemBuilder.getLocations());
|
VehicleRoutingTransportCosts routingCosts = new CrowFlyCosts(problemBuilder.getLocations());
|
||||||
Map<String,Double> nearestMessengers = getNearestMessengers(routingCosts, problemBuilder.getAddedJobs(), problemBuilder.getAddedVehicles());
|
Map<String,Double> nearestMessengers = getNearestMessengers(routingCosts, problemBuilder.getAddedJobs(), problemBuilder.getAddedVehicles());
|
||||||
|
StateManager stateManager = new StateManager(routingCosts);
|
||||||
|
stateManager.addDefaultActivityState(StateFactory.createId("latest-activity-start-time"), StateFactory.createState(Double.MAX_VALUE));
|
||||||
|
|
||||||
problemBuilder.setFleetSize(FleetSize.FINITE);
|
problemBuilder.setFleetSize(FleetSize.FINITE);
|
||||||
problemBuilder.addConstraint(new ThreeTimesLessThanDirectRouteConstraint(nearestMessengers, routingCosts));
|
problemBuilder.addConstraint(new ThreeTimesLessThanBestDirectRouteConstraint(nearestMessengers, routingCosts, stateManager));
|
||||||
problemBuilder.addConstraint(new IgnoreMessengerThatCanNeverMeetTimeRequirements(nearestMessengers, routingCosts));
|
problemBuilder.addConstraint(new IgnoreMessengerThatCanNeverMeetTimeRequirements(nearestMessengers, routingCosts));
|
||||||
|
|
||||||
VehicleRoutingProblem bicycleMessengerProblem = problemBuilder.build();
|
VehicleRoutingProblem bicycleMessengerProblem = problemBuilder.build();
|
||||||
|
|
||||||
StateManager stateManager = new StateManager(bicycleMessengerProblem);
|
stateManager.addStateUpdater(new UpdateLatestActivityStartTimes(stateManager, routingCosts, nearestMessengers));
|
||||||
stateManager.addStateUpdater(new UpdateLatestActivityStartTime(stateManager));
|
|
||||||
|
|
||||||
VehicleRoutingAlgorithm algorithm = VehicleRoutingAlgorithms.readAndCreateAlgorithm(bicycleMessengerProblem,"input/algorithmConfig_open.xml", stateManager);
|
VehicleRoutingAlgorithm algorithm = VehicleRoutingAlgorithms.readAndCreateAlgorithm(bicycleMessengerProblem,"input/algorithmConfig_open.xml", stateManager);
|
||||||
algorithm.setPrematureAlgorithmTermination(new IterationWithoutImprovementTermination(200));
|
// algorithm.setPrematureAlgorithmTermination(new IterationWithoutImprovementTermination(500));
|
||||||
|
algorithm.addListener(new AlgorithmSearchProgressChartListener("output/progress.png"));
|
||||||
Collection<VehicleRoutingProblemSolution> solutions = algorithm.searchSolutions();
|
Collection<VehicleRoutingProblemSolution> solutions = algorithm.searchSolutions();
|
||||||
|
|
||||||
SolutionPrinter.print(Solutions.bestOf(solutions));
|
SolutionPrinter.print(Solutions.bestOf(solutions));
|
||||||
|
|
@ -203,12 +249,18 @@ public class BicycleMessenger {
|
||||||
String line = null;
|
String line = null;
|
||||||
boolean firstLine = true;
|
boolean firstLine = true;
|
||||||
VehicleType messengerType = VehicleTypeImpl.Builder.newInstance("messengerType", 15).setCostPerDistance(1).build();
|
VehicleType messengerType = VehicleTypeImpl.Builder.newInstance("messengerType", 15).setCostPerDistance(1).build();
|
||||||
|
VehicleType penaltyType = VehicleTypeImpl.Builder.newInstance("messengerType", 15).setFixedCost(200).setCostPerDistance(4).build();
|
||||||
|
PenaltyVehicleType penaltyVehicleType = new PenaltyVehicleType(penaltyType);
|
||||||
|
|
||||||
while((line = reader.readLine()) != null){
|
while((line = reader.readLine()) != null){
|
||||||
if(firstLine) { firstLine = false; continue; }
|
if(firstLine) { firstLine = false; continue; }
|
||||||
String[] tokens = line.split("\\s+");
|
String[] tokens = line.split("\\s+");
|
||||||
Vehicle vehicle = VehicleImpl.Builder.newInstance(tokens[1]).setLocationCoord(Coordinate.newInstance(Double.parseDouble(tokens[2]), Double.parseDouble(tokens[3])))
|
Vehicle vehicle = VehicleImpl.Builder.newInstance(tokens[1]).setLocationCoord(Coordinate.newInstance(Double.parseDouble(tokens[2]), Double.parseDouble(tokens[3])))
|
||||||
.setReturnToDepot(true).setType(messengerType).build();
|
.setReturnToDepot(true).setType(messengerType).build();
|
||||||
problemBuilder.addVehicle(vehicle);
|
problemBuilder.addVehicle(vehicle);
|
||||||
|
Vehicle penaltyVehicle = VehicleImpl.Builder.newInstance(tokens[1]).setLocationCoord(Coordinate.newInstance(Double.parseDouble(tokens[2]), Double.parseDouble(tokens[3])))
|
||||||
|
.setReturnToDepot(true).setType(penaltyVehicleType).build();
|
||||||
|
problemBuilder.addVehicle(penaltyVehicle);
|
||||||
}
|
}
|
||||||
reader.close();
|
reader.close();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue