mirror of
https://github.com/graphhopper/jsprit.git
synced 2020-01-24 07:45:05 +01:00
Merge pull request #463 from einride/master
Fixes/enhancements (mostly) about non-job activities
This commit is contained in:
commit
23368a5409
9 changed files with 72 additions and 41 deletions
|
|
@ -572,28 +572,30 @@ public class GraphStreamViewer {
|
||||||
n.addAttribute("ui.label", "start");
|
n.addAttribute("ui.label", "start");
|
||||||
}
|
}
|
||||||
for (TourActivity act : route.getActivities()) {
|
for (TourActivity act : route.getActivities()) {
|
||||||
Job job = ((JobActivity) act).getJob();
|
if (act instanceof JobActivity) {
|
||||||
String currIdentifier = makeId(job.getId(), act.getLocation().getId());
|
Job job = ((JobActivity) act).getJob();
|
||||||
if (label.equals(Label.ACTIVITY)) {
|
String currIdentifier = makeId(job.getId(), act.getLocation().getId());
|
||||||
Node actNode = g.getNode(currIdentifier);
|
if (label.equals(Label.ACTIVITY)) {
|
||||||
actNode.addAttribute("ui.label", act.getName());
|
Node actNode = g.getNode(currIdentifier);
|
||||||
} else if (label.equals(Label.JOB_NAME)) {
|
actNode.addAttribute("ui.label", act.getName());
|
||||||
Node actNode = g.getNode(currIdentifier);
|
} else if (label.equals(Label.JOB_NAME)) {
|
||||||
actNode.addAttribute("ui.label", job.getName());
|
Node actNode = g.getNode(currIdentifier);
|
||||||
} else if (label.equals(Label.ARRIVAL_TIME)) {
|
actNode.addAttribute("ui.label", job.getName());
|
||||||
Node actNode = g.getNode(currIdentifier);
|
} else if (label.equals(Label.ARRIVAL_TIME)) {
|
||||||
actNode.addAttribute("ui.label", Time.parseSecondsToTime(act.getArrTime()));
|
Node actNode = g.getNode(currIdentifier);
|
||||||
} else if (label.equals(Label.DEPARTURE_TIME)) {
|
actNode.addAttribute("ui.label", Time.parseSecondsToTime(act.getArrTime()));
|
||||||
Node actNode = g.getNode(currIdentifier);
|
} else if (label.equals(Label.DEPARTURE_TIME)) {
|
||||||
actNode.addAttribute("ui.label", Time.parseSecondsToTime(act.getEndTime()));
|
Node actNode = g.getNode(currIdentifier);
|
||||||
|
actNode.addAttribute("ui.label", Time.parseSecondsToTime(act.getEndTime()));
|
||||||
|
}
|
||||||
|
g.addEdge(makeEdgeId(routeId, vehicle_edgeId), prevIdentifier, currIdentifier, true);
|
||||||
|
if (act instanceof PickupActivity) g.getNode(currIdentifier).addAttribute("ui.class", "pickupInRoute");
|
||||||
|
else if (act instanceof DeliveryActivity)
|
||||||
|
g.getNode(currIdentifier).addAttribute("ui.class", "deliveryInRoute");
|
||||||
|
prevIdentifier = currIdentifier;
|
||||||
|
vehicle_edgeId++;
|
||||||
|
sleep(renderDelay_in_ms);
|
||||||
}
|
}
|
||||||
g.addEdge(makeEdgeId(routeId, vehicle_edgeId), prevIdentifier, currIdentifier, true);
|
|
||||||
if (act instanceof PickupActivity) g.getNode(currIdentifier).addAttribute("ui.class", "pickupInRoute");
|
|
||||||
else if (act instanceof DeliveryActivity)
|
|
||||||
g.getNode(currIdentifier).addAttribute("ui.class", "deliveryInRoute");
|
|
||||||
prevIdentifier = currIdentifier;
|
|
||||||
vehicle_edgeId++;
|
|
||||||
sleep(renderDelay_in_ms);
|
|
||||||
}
|
}
|
||||||
if (route.getVehicle().isReturnToDepot()) {
|
if (route.getVehicle().isReturnToDepot()) {
|
||||||
String lastIdentifier = makeId(route.getVehicle().getId(), route.getVehicle().getEndLocation().getId());
|
String lastIdentifier = makeId(route.getVehicle().getId(), route.getVehicle().getEndLocation().getId());
|
||||||
|
|
|
||||||
|
|
@ -302,6 +302,10 @@ public class Plotter {
|
||||||
final XYPlot plot = createPlot(problem, shipments, solution);
|
final XYPlot plot = createPlot(problem, shipments, solution);
|
||||||
JFreeChart chart = new JFreeChart(title, plot);
|
JFreeChart chart = new JFreeChart(title, plot);
|
||||||
|
|
||||||
|
plot.setBackgroundPaint(Color.WHITE);
|
||||||
|
plot.setDomainGridlinesVisible(false);
|
||||||
|
plot.setRangeGridlinesVisible(false);
|
||||||
|
|
||||||
LegendTitle legend = createLegend(routes, shipments, plot);
|
LegendTitle legend = createLegend(routes, shipments, plot);
|
||||||
chart.removeLegend();
|
chart.removeLegend();
|
||||||
chart.addLegend(legend);
|
chart.addLegend(legend);
|
||||||
|
|
|
||||||
|
|
@ -135,23 +135,28 @@ public class VehicleRoutingAlgorithm {
|
||||||
this.objectiveFunction = objectiveFunction;
|
this.objectiveFunction = objectiveFunction;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds solution to the collection of initial solutions.
|
* Adds solution to the collection of initial solutions.
|
||||||
*
|
*
|
||||||
* @param solution the solution to be added
|
* This method may lead to errors if tour activities in the solution are different to the
|
||||||
*/
|
* ones in the VRP (including differences in indexing)
|
||||||
public void addInitialSolution(VehicleRoutingProblemSolution solution) {
|
*
|
||||||
|
* @param solution the solution to be added
|
||||||
|
*/
|
||||||
|
public void addInitialSolution(VehicleRoutingProblemSolution solution) {
|
||||||
// We will make changes so let's make a copy
|
// We will make changes so let's make a copy
|
||||||
solution = VehicleRoutingProblemSolution.copyOf(solution);
|
solution = VehicleRoutingProblemSolution.copyOf(solution);
|
||||||
verify(solution);
|
verifyAndAdaptSolution(solution);
|
||||||
initialSolutions.add(solution);
|
initialSolutions.add(solution);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void verify(VehicleRoutingProblemSolution solution) {
|
//this method may lead to errors if tour activities in the solution are different to the ones in the VRP
|
||||||
Set<Job> allJobs = new HashSet<Job>(problem.getJobs().values());
|
//(including differences in indexing)
|
||||||
allJobs.removeAll(solution.getUnassignedJobs());
|
private void verifyAndAdaptSolution(VehicleRoutingProblemSolution solution) {
|
||||||
|
Set<Job> jobsNotInSolution = new HashSet<Job>(problem.getJobs().values());
|
||||||
|
jobsNotInSolution.removeAll(solution.getUnassignedJobs());
|
||||||
for (VehicleRoute route : solution.getRoutes()) {
|
for (VehicleRoute route : solution.getRoutes()) {
|
||||||
allJobs.removeAll(route.getTourActivities().getJobs());
|
jobsNotInSolution.removeAll(route.getTourActivities().getJobs());
|
||||||
if (route.getVehicle().getIndex() == 0)
|
if (route.getVehicle().getIndex() == 0)
|
||||||
throw new IllegalStateException("vehicle used in initial solution has no index. probably a vehicle is used that has not been added to the " +
|
throw new IllegalStateException("vehicle used in initial solution has no index. probably a vehicle is used that has not been added to the " +
|
||||||
" the VehicleRoutingProblem. only use vehicles that have already been added to the problem.");
|
" the VehicleRoutingProblem. only use vehicles that have already been added to the problem.");
|
||||||
|
|
@ -164,7 +169,9 @@ public class VehicleRoutingAlgorithm {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
solution.getUnassignedJobs().addAll(allJobs);
|
//if solution is partial (not all jobs are considered), add these jobs to solution.unassignedJobs
|
||||||
|
solution.getUnassignedJobs().addAll(jobsNotInSolution);
|
||||||
|
//update the cost of solution (regardless if partial or not)
|
||||||
solution.setCost(getObjectiveFunction().getCosts(solution));
|
solution.setCost(getObjectiveFunction().getCosts(solution));
|
||||||
|
|
||||||
// if (nuJobs != problem.getJobs().values().size()) {
|
// if (nuJobs != problem.getJobs().values().size()) {
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,10 @@ public final class RuinWorst extends AbstractRuinStrategy {
|
||||||
TourActivity actBefore = route.getStart();
|
TourActivity actBefore = route.getStart();
|
||||||
TourActivity actToEval = null;
|
TourActivity actToEval = null;
|
||||||
for (TourActivity act : route.getActivities()) {
|
for (TourActivity act : route.getActivities()) {
|
||||||
|
if (!(act instanceof TourActivity.JobActivity)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (actToEval == null) {
|
if (actToEval == null) {
|
||||||
actToEval = act;
|
actToEval = act;
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -119,6 +123,9 @@ public final class RuinWorst extends AbstractRuinStrategy {
|
||||||
actBefore = actToEval;
|
actBefore = actToEval;
|
||||||
actToEval = act;
|
actToEval = act;
|
||||||
}
|
}
|
||||||
|
if (actToEval == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
double savings = savings(route, actBefore, actToEval, route.getEnd());
|
double savings = savings(route, actBefore, actToEval, route.getEnd());
|
||||||
Job job = ((TourActivity.JobActivity) actToEval).getJob();
|
Job job = ((TourActivity.JobActivity) actToEval).getJob();
|
||||||
if (!savingsMap.containsKey(job)) {
|
if (!savingsMap.containsKey(job)) {
|
||||||
|
|
|
||||||
|
|
@ -414,6 +414,17 @@ public class VehicleRoutingProblem {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final List<AbstractActivity> nonJobActivities = new ArrayList<>();
|
||||||
|
|
||||||
|
public Builder addNonJobActivities(Collection<? extends AbstractActivity> nonJobActivities) {
|
||||||
|
for (AbstractActivity act : nonJobActivities) {
|
||||||
|
act.setIndex(activityIndexCounter);
|
||||||
|
incActivityIndexCounter();
|
||||||
|
this.nonJobActivities.add(act);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds the {@link VehicleRoutingProblem}.
|
* Builds the {@link VehicleRoutingProblem}.
|
||||||
* <p>
|
* <p>
|
||||||
|
|
|
||||||
|
|
@ -78,8 +78,8 @@ public class MaxDistanceConstraint implements HardActivityConstraint {
|
||||||
double maxDistance = getMaxDistance(iFacts.getNewVehicle());
|
double maxDistance = getMaxDistance(iFacts.getNewVehicle());
|
||||||
if (currentDistance > maxDistance) return ConstraintsStatus.NOT_FULFILLED_BREAK;
|
if (currentDistance > maxDistance) return ConstraintsStatus.NOT_FULFILLED_BREAK;
|
||||||
|
|
||||||
double distancePrevAct2NewAct = distanceCalculator.getDistance(prevAct.getLocation(), newAct.getLocation(), iFacts.getNewDepTime(), iFacts.getNewVehicle());
|
double distancePrevAct2NewAct = distanceCalculator.getDistance(prevAct.getLocation(), newAct.getLocation(), prevActDepTime, iFacts.getNewVehicle());
|
||||||
double distanceNewAct2nextAct = distanceCalculator.getDistance(newAct.getLocation(), nextAct.getLocation(), iFacts.getNewDepTime(), iFacts.getNewVehicle());
|
double distanceNewAct2nextAct = distanceCalculator.getDistance(newAct.getLocation(), nextAct.getLocation(), prevActDepTime, iFacts.getNewVehicle());
|
||||||
double distancePrevAct2NextAct = distanceCalculator.getDistance(prevAct.getLocation(), nextAct.getLocation(), prevActDepTime, iFacts.getNewVehicle());
|
double distancePrevAct2NextAct = distanceCalculator.getDistance(prevAct.getLocation(), nextAct.getLocation(), prevActDepTime, iFacts.getNewVehicle());
|
||||||
if (prevAct instanceof Start && nextAct instanceof End) distancePrevAct2NextAct = 0;
|
if (prevAct instanceof Start && nextAct instanceof End) distancePrevAct2NextAct = 0;
|
||||||
if (nextAct instanceof End && !iFacts.getNewVehicle().isReturnToDepot()) {
|
if (nextAct instanceof End && !iFacts.getNewVehicle().isReturnToDepot()) {
|
||||||
|
|
|
||||||
|
|
@ -398,9 +398,9 @@ public class Service extends AbstractJob {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get priority of service. Only 1 = high priority, 2 = medium and 3 = low are allowed.
|
* Get priority of service. Only 1 (high) to 10 (low) are allowed.
|
||||||
* <p>
|
* <p>
|
||||||
* Default is 2 = medium.
|
* Default is 2.
|
||||||
*
|
*
|
||||||
* @return priority
|
* @return priority
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -318,7 +318,7 @@ public class Shipment extends AbstractJob {
|
||||||
/**
|
/**
|
||||||
* Set priority to shipment. Only 1 (high) to 10 (low) are allowed.
|
* Set priority to shipment. Only 1 (high) to 10 (low) are allowed.
|
||||||
* <p>
|
* <p>
|
||||||
* Default is 2 = medium.
|
* Default is 2.
|
||||||
*
|
*
|
||||||
* @param priority
|
* @param priority
|
||||||
* @return builder
|
* @return builder
|
||||||
|
|
@ -505,9 +505,9 @@ public class Shipment extends AbstractJob {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get priority of shipment. Only 1 = high priority, 2 = medium and 3 = low are allowed.
|
* Get priority of shipment. Only 1 (high) to 10 (low) are allowed.
|
||||||
* <p>
|
* <p>
|
||||||
* Default is 2 = medium.
|
* Default is 2.
|
||||||
*
|
*
|
||||||
* @return priority
|
* @return priority
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -367,7 +367,7 @@ public class VehicleRoute {
|
||||||
* @return list of tourActivities
|
* @return list of tourActivities
|
||||||
*/
|
*/
|
||||||
public List<TourActivity> getActivities() {
|
public List<TourActivity> getActivities() {
|
||||||
return Collections.unmodifiableList(tourActivities.getActivities());
|
return tourActivities.getActivities();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue