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

Compare commits

...

9 commits

Author SHA1 Message Date
oblonski
d03906950f
add tests for job activities 2019-07-19 11:40:17 +02:00
oblonski
7351a05730
clean up 2019-07-19 10:41:20 +02:00
oblonski
af69361cd4
add helper to compare time windows 2019-07-19 10:30:59 +02:00
oblonski
d8bb1ca95a
clean up 2019-07-19 10:30:42 +02:00
oblonski
298210bb9c
add activities 2019-07-19 10:30:19 +02:00
oblonski
ac84b62651
remove instanceof job stuff 2019-07-19 09:05:12 +02:00
oblonski
ad851b1951
make list unmodifiable 2019-07-18 22:48:22 +02:00
oblonski
fe590fc9f8
simplify according to getActivities 2019-07-18 22:45:38 +02:00
oblonski
dd3f29b5cc
add option to get activities from job 2019-07-18 22:44:46 +02:00
20 changed files with 363 additions and 322 deletions

View file

@ -153,8 +153,6 @@ public class AlgorithmEventsViewer {
private long delayRuin = 5;
private long delay = 2;
public void setRecreationDelay(long delay_in_ms) {
this.delayRecreation = delay_in_ms;
}
@ -174,6 +172,7 @@ public class AlgorithmEventsViewer {
DelayContainer delayContainer = new DelayContainer();
DelaySink delaySink = new DelaySink(delayContainer);
long delay = 2;
delaySink.setDelay(delay);
delaySink.setRecreateDelay(delayRecreation);
delaySink.setRuinDelay(delayRuin);
@ -197,7 +196,7 @@ public class AlgorithmEventsViewer {
}
}
public static void main(String[] args) throws IOException {
public static void main(String[] args) {
AlgorithmEventsViewer viewer = new AlgorithmEventsViewer();
viewer.setRuinDelay(10);
viewer.setRecreationDelay(5);

View file

@ -19,9 +19,8 @@ package com.graphhopper.jsprit.analysis.toolbox;
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
import com.graphhopper.jsprit.core.problem.job.Activity;
import com.graphhopper.jsprit.core.problem.job.Job;
import com.graphhopper.jsprit.core.problem.job.Service;
import com.graphhopper.jsprit.core.problem.job.Shipment;
import com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolution;
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
import com.graphhopper.jsprit.core.problem.solution.route.activity.DeliveryActivity;
@ -46,7 +45,7 @@ public class GraphStreamViewer {
public static class StyleSheets {
public static String BLUE_FOREST =
static String BLUE_FOREST =
"graph { fill-color: #141F2E; }" +
"node {" +
" size: 7px, 7px;" +
@ -169,7 +168,7 @@ public class GraphStreamViewer {
}
public static Graph createMultiGraph(String name, String style) {
static Graph createMultiGraph(String name, String style) {
Graph g = new MultiGraph(name);
g.addAttribute("ui.quality");
g.addAttribute("ui.antialias");
@ -177,66 +176,14 @@ public class GraphStreamViewer {
return g;
}
public static ViewPanel createEmbeddedView(Graph graph, double scaling) {
private static ViewPanel createEmbeddedView(Graph graph, double scaling) {
Viewer viewer = new Viewer(graph, Viewer.ThreadingModel.GRAPH_IN_ANOTHER_THREAD);
ViewPanel view = viewer.addDefaultView(false);
view.setPreferredSize(new Dimension((int) (698 * scaling), (int) (440 * scaling)));
return view;
}
public static String STYLESHEET =
"node {" +
" size: 10px, 10px;" +
" fill-color: #6CC644;" +
" text-alignment: at-right;" +
" stroke-mode: plain;" +
" stroke-color: #999;" +
" stroke-width: 1.0;" +
" text-font: couriernew;" +
" text-offset: 2,-5;" +
" text-size: 8;" +
"}" +
"node.pickup {" +
" fill-color: #6CC644;" +
"}" +
"node.delivery {" +
" fill-color: #f93;" +
"}" +
"node.pickupInRoute {" +
" fill-color: #6CC644;" +
" stroke-mode: plain;" +
" stroke-color: #333;" +
" stroke-width: 2.0;" +
"}" +
"node.deliveryInRoute {" +
" fill-color: #f93;" +
" stroke-mode: plain;" +
" stroke-color: #333;" +
" stroke-width: 2.0;" +
"}" +
"node.depot {" +
" fill-color: #BD2C00;" +
" size: 10px, 10px;" +
" shape: box;" +
"}" +
"node.removed {" +
" fill-color: #BD2C00;" +
" size: 10px, 10px;" +
" stroke-mode: plain;" +
" stroke-color: #333;" +
" stroke-width: 2.0;" +
"}" +
"edge {" +
" fill-color: #333;" +
" arrow-size: 6px,3px;" +
"}" +
"edge.shipment {" +
" fill-color: #999;" +
" arrow-size: 6px,3px;" +
"}";
public static enum Label {
public enum Label {
NO_LABEL, ID, JOB_NAME, ARRIVAL_TIME, DEPARTURE_TIME, ACTIVITY
}
@ -244,7 +191,7 @@ public class GraphStreamViewer {
final double x;
final double y;
public Center(double x, double y) {
Center(double x, double y) {
super();
this.x = x;
this.y = y;
@ -319,13 +266,9 @@ public class GraphStreamViewer {
public void display() {
System.setProperty("org.graphstream.ui.renderer", "org.graphstream.ui.j2dviewer.J2DGraphRenderer");
Graph g = createMultiGraph("g");
Graph g = createMultiGraph();
ViewPanel view = createEmbeddedView(g, scaling);
createJFrame(view, scaling);
render(g, view);
}
@ -369,8 +312,58 @@ public class GraphStreamViewer {
return jframe;
}
private Graph createMultiGraph(String name) {
return GraphStreamViewer.createMultiGraph(name, STYLESHEET);
private Graph createMultiGraph() {
String STYLESHEET = "node {" +
" size: 10px, 10px;" +
" fill-color: #6CC644;" +
" text-alignment: at-right;" +
" stroke-mode: plain;" +
" stroke-color: #999;" +
" stroke-width: 1.0;" +
" text-font: couriernew;" +
" text-offset: 2,-5;" +
" text-size: 8;" +
"}" +
"node.pickup {" +
" fill-color: #6CC644;" +
"}" +
"node.delivery {" +
" fill-color: #f93;" +
"}" +
"node.pickupInRoute {" +
" fill-color: #6CC644;" +
" stroke-mode: plain;" +
" stroke-color: #333;" +
" stroke-width: 2.0;" +
"}" +
"node.deliveryInRoute {" +
" fill-color: #f93;" +
" stroke-mode: plain;" +
" stroke-color: #333;" +
" stroke-width: 2.0;" +
"}" +
"node.depot {" +
" fill-color: #BD2C00;" +
" size: 10px, 10px;" +
" shape: box;" +
"}" +
"node.removed {" +
" fill-color: #BD2C00;" +
" size: 10px, 10px;" +
" stroke-mode: plain;" +
" stroke-color: #333;" +
" stroke-width: 2.0;" +
"}" +
"edge {" +
" fill-color: #333;" +
" arrow-size: 6px,3px;" +
"}" +
"edge.shipment {" +
" fill-color: #999;" +
" arrow-size: 6px,3px;" +
"}";
return GraphStreamViewer.createMultiGraph("g", STYLESHEET);
}
private void render(Graph g, ViewPanel view) {
@ -385,11 +378,7 @@ public class GraphStreamViewer {
}
for (Job j : vrp.getJobs().values()) {
if (j instanceof Service) {
renderService(g, (Service) j, label);
} else if (j instanceof Shipment) {
renderShipment(g, (Shipment) j, label, renderShipments);
}
renderJob(g, j, label);
sleep(renderDelay_in_ms);
}
@ -404,6 +393,7 @@ public class GraphStreamViewer {
}
private void alignCamera(View view) {
view.getCamera().setViewCenter(center.x, center.y, 0);
view.getCamera().setViewPercent(zoomFactor);
@ -501,26 +491,22 @@ public class GraphStreamViewer {
return 0.0;
}
private void renderShipment(Graph g, Shipment shipment, Label label, boolean renderShipments) {
Node n1 = g.addNode(makeId(shipment.getId(), shipment.getPickupLocation().getId()));
if (label.equals(Label.ID)) n1.addAttribute("ui.label", shipment.getId());
n1.addAttribute("x", shipment.getPickupLocation().getCoordinate().getX());
n1.addAttribute("y", shipment.getPickupLocation().getCoordinate().getY());
n1.setAttribute("ui.class", "pickup");
Node n2 = g.addNode(makeId(shipment.getId(), shipment.getDeliveryLocation().getId()));
if (label.equals(Label.ID)) n2.addAttribute("ui.label", shipment.getId());
n2.addAttribute("x", shipment.getDeliveryLocation().getCoordinate().getX());
n2.addAttribute("y", shipment.getDeliveryLocation().getCoordinate().getY());
n2.setAttribute("ui.class", "delivery");
if (renderShipments) {
Edge s = g.addEdge(shipment.getId(), makeId(shipment.getId(), shipment.getPickupLocation().getId()),
makeId(shipment.getId(), shipment.getDeliveryLocation().getId()), true);
s.addAttribute("ui.class", "shipment");
private void renderJob(Graph g, Job j, Label label) {
String lastNodeId = null;
for (Activity act : j.getActivities()) {
String nodeId = makeId(j.getId(), act.getLocation().getId());
Node n1 = g.addNode(nodeId);
if (label.equals(Label.ID)) n1.addAttribute("ui.label", j.getId());
n1.addAttribute("x", act.getLocation().getCoordinate().getX());
n1.addAttribute("y", act.getLocation().getCoordinate().getY());
if (act.getActivityType().equals(Activity.Type.PICKUP)) n1.setAttribute("ui.class", "pickup");
else if (act.getActivityType().equals(Activity.Type.DELIVERY)) n1.setAttribute("ui.class", "delivery");
if (renderShipments && lastNodeId != null) {
Edge s = g.addEdge(j.getId(), lastNodeId, nodeId, true);
s.addAttribute("ui.class", "shipment");
}
lastNodeId = nodeId;
}
}
private void sleep(long renderDelay_in_ms2) {
@ -532,15 +518,6 @@ public class GraphStreamViewer {
}
}
private void renderService(Graph g, Service service, Label label) {
Node n = g.addNode(makeId(service.getId(), service.getLocation().getId()));
if (label.equals(Label.ID)) n.addAttribute("ui.label", service.getId());
n.addAttribute("x", service.getLocation().getCoordinate().getX());
n.addAttribute("y", service.getLocation().getCoordinate().getY());
if (service.getType().equals("pickup")) n.setAttribute("ui.class", "pickup");
if (service.getType().equals("delivery")) n.setAttribute("ui.class", "delivery");
}
private String makeId(String id, String locationId) {
return id + "_" + locationId;
}
@ -575,18 +552,24 @@ public class GraphStreamViewer {
if (act instanceof JobActivity) {
Job job = ((JobActivity) act).getJob();
String currIdentifier = makeId(job.getId(), act.getLocation().getId());
if (label.equals(Label.ACTIVITY)) {
Node actNode = g.getNode(currIdentifier);
actNode.addAttribute("ui.label", act.getName());
} else if (label.equals(Label.JOB_NAME)) {
Node actNode = g.getNode(currIdentifier);
actNode.addAttribute("ui.label", job.getName());
} else if (label.equals(Label.ARRIVAL_TIME)) {
Node actNode = g.getNode(currIdentifier);
actNode.addAttribute("ui.label", Time.parseSecondsToTime(act.getArrTime()));
} else if (label.equals(Label.DEPARTURE_TIME)) {
Node actNode = g.getNode(currIdentifier);
actNode.addAttribute("ui.label", Time.parseSecondsToTime(act.getEndTime()));
Node actNode = g.getNode(currIdentifier);
switch (label) {
case ACTIVITY: {
actNode.addAttribute("ui.label", act.getName());
break;
}
case JOB_NAME: {
actNode.addAttribute("ui.label", job.getName());
break;
}
case ARRIVAL_TIME: {
actNode.addAttribute("ui.label", Time.parseSecondsToTime(act.getArrTime()));
break;
}
case DEPARTURE_TIME: {
actNode.addAttribute("ui.label", Time.parseSecondsToTime(act.getEndTime()));
break;
}
}
g.addEdge(makeEdgeId(routeId, vehicle_edgeId), prevIdentifier, currIdentifier, true);
if (act instanceof PickupActivity) g.getNode(currIdentifier).addAttribute("ui.class", "pickupInRoute");
@ -607,7 +590,4 @@ public class GraphStreamViewer {
return Integer.valueOf(routeId).toString() + "." + Integer.valueOf(vehicle_edgeId).toString();
}
// public void saveAsPNG(String filename){
//
// }
}

View file

@ -19,7 +19,7 @@ package com.graphhopper.jsprit.analysis.toolbox;
import com.graphhopper.jsprit.core.problem.Location;
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
import com.graphhopper.jsprit.core.problem.job.*;
import com.graphhopper.jsprit.core.problem.job.Job;
import com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolution;
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity;
@ -27,14 +27,12 @@ import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
import com.graphhopper.jsprit.core.util.Coordinate;
import org.jfree.chart.*;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.labels.XYItemLabelGenerator;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.chart.title.LegendTitle;
import org.jfree.data.Range;
import org.jfree.data.xy.XYDataItem;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.ui.RectangleEdge;
@ -79,7 +77,7 @@ public class Plotter {
private Set<XYDataItem> firstActivities;
public MyActivityRenderer(XYSeriesCollection seriesCollection, Map<XYDataItem, Activity> activities, Set<XYDataItem> firstActivities) {
MyActivityRenderer(XYSeriesCollection seriesCollection, Map<XYDataItem, Activity> activities, Set<XYDataItem> firstActivities) {
super(false, true);
this.seriesCollection = seriesCollection;
this.activities = activities;
@ -126,7 +124,7 @@ public class Plotter {
double maxX;
double maxY;
public BoundingBox(double minX, double minY, double maxX, double maxY) {
BoundingBox(double minX, double minY, double maxX, double maxY) {
super();
this.minX = minX;
this.minY = minY;
@ -148,7 +146,7 @@ public class Plotter {
*
* @author schroeder
*/
public static enum Label {
public enum Label {
ID, SIZE, @SuppressWarnings("UnusedDeclaration")NO_LABEL
}
@ -164,13 +162,13 @@ public class Plotter {
private BoundingBox boundingBox = null;
private Map<XYDataItem, Activity> activitiesByDataItem = new HashMap<XYDataItem, Plotter.Activity>();
private Map<XYDataItem, Activity> activitiesByDataItem = new HashMap<>();
private Map<XYDataItem, String> labelsByDataItem = new HashMap<XYDataItem, String>();
private Map<XYDataItem, String> labelsByDataItem = new HashMap<>();
private XYSeries activities;
private Set<XYDataItem> firstActivities = new HashSet<XYDataItem>();
private Set<XYDataItem> firstActivities = new HashSet<>();
private boolean containsPickupAct = false;
@ -247,7 +245,7 @@ public class Plotter {
* @param minY lower left y
* @param maxX upper right x
* @param maxY upper right y
* @return
* @return Plotter
*/
@SuppressWarnings("UnusedDeclaration")
public Plotter setBoundingBox(double minX, double minY, double maxX, double maxY) {
@ -321,27 +319,15 @@ public class Plotter {
@Override
public LegendItemCollection getLegendItems() {
LegendItemCollection lic = new LegendItemCollection();
LegendItem vehLoc = new LegendItem("vehLoc", Color.RED);
vehLoc.setShape(ELLIPSE);
vehLoc.setShapeVisible(true);
lic.add(vehLoc);
addLegendItem(lic, "vehLoc", Color.RED);
if (containsServiceAct) {
LegendItem item = new LegendItem("service", Color.BLUE);
item.setShape(ELLIPSE);
item.setShapeVisible(true);
lic.add(item);
addLegendItem(lic, "service", Color.BLUE);
}
if (containsPickupAct) {
LegendItem item = new LegendItem("pickup", Color.GREEN);
item.setShape(ELLIPSE);
item.setShapeVisible(true);
lic.add(item);
addLegendItem(lic, "pickup", Color.GREEN);
}
if (containsDeliveryAct) {
LegendItem item = new LegendItem("delivery", Color.BLUE);
item.setShape(ELLIPSE);
item.setShapeVisible(true);
lic.add(item);
addLegendItem(lic, "delivery", Color.BLUE);
}
if (routes != null) {
LegendItem item = new LegendItem("firstActivity", Color.BLACK);
@ -363,6 +349,13 @@ public class Plotter {
}
return lic;
}
private void addLegendItem(LegendItemCollection lic, String jobType, Color color) {
LegendItem item = new LegendItem(jobType, color);
item.setShape(ELLIPSE);
item.setShapeVisible(true);
lic.add(item);
}
};
LegendTitle legend = new LegendTitle(lis);
@ -384,14 +377,9 @@ public class Plotter {
private MyActivityRenderer getProblemRenderer(final XYSeriesCollection problem) {
MyActivityRenderer problemRenderer = new MyActivityRenderer(problem, activitiesByDataItem, firstActivities);
problemRenderer.setBaseItemLabelGenerator(new XYItemLabelGenerator() {
@Override
public String generateLabel(XYDataset arg0, int arg1, int arg2) {
XYDataItem item = problem.getSeries(arg1).getDataItem(arg2);
return labelsByDataItem.get(item);
}
problemRenderer.setBaseItemLabelGenerator((arg0, arg1, arg2) -> {
XYDataItem item = problem.getSeries(arg1).getDataItem(arg2);
return labelsByDataItem.get(item);
});
problemRenderer.setBaseItemLabelsVisible(true);
problemRenderer.setBaseItemLabelPaint(Color.BLACK);
@ -467,7 +455,7 @@ public class Plotter {
}
}
private XYSeriesCollection makeSolutionSeries(VehicleRoutingProblem vrp, Collection<VehicleRoute> routes) throws NoLocationFoundException {
private XYSeriesCollection makeSolutionSeries(VehicleRoutingProblem vrp, Collection<VehicleRoute> routes) {
Map<String, Coordinate> coords = makeMap(vrp.getAllLocations());
XYSeriesCollection coll = new XYSeriesCollection();
int counter = 1;
@ -493,22 +481,20 @@ public class Plotter {
}
private Map<String, Coordinate> makeMap(Collection<Location> allLocations) {
Map<String, Coordinate> coords = new HashMap<String, Coordinate>();
Map<String, Coordinate> coords = new HashMap<>();
for (Location l : allLocations) coords.put(l.getId(), l.getCoordinate());
return coords;
}
private XYSeriesCollection makeShipmentSeries(Collection<Job> jobs) throws NoLocationFoundException {
private XYSeriesCollection makeShipmentSeries(Collection<Job> jobs) {
XYSeriesCollection coll = new XYSeriesCollection();
if (!plotShipments) return coll;
int sCounter = 1;
String ship = "shipment";
boolean first = true;
for (Job job : jobs) {
if (!(job instanceof Shipment)) {
continue;
}
Shipment shipment = (Shipment) job;
if (job.getActivities().size() == 1) continue;
// Shipment shipment = (Shipment) job;
XYSeries shipmentSeries;
if (first) {
first = false;
@ -517,57 +503,34 @@ public class Plotter {
shipmentSeries = new XYSeries(sCounter, false, true);
sCounter++;
}
Coordinate pickupCoordinate = getCoordinate(shipment.getPickupLocation().getCoordinate());
Coordinate delCoordinate = getCoordinate(shipment.getDeliveryLocation().getCoordinate());
shipmentSeries.add(pickupCoordinate.getX() * scalingFactor, pickupCoordinate.getY() * scalingFactor);
shipmentSeries.add(delCoordinate.getX() * scalingFactor, delCoordinate.getY() * scalingFactor);
for (com.graphhopper.jsprit.core.problem.job.Activity act : job.getActivities()) {
Coordinate actCoordinate = getCoordinate(act.getLocation().getCoordinate());
shipmentSeries.add(actCoordinate.getX() * scalingFactor, actCoordinate.getY() * scalingFactor);
}
coll.addSeries(shipmentSeries);
}
return coll;
}
private void addJob(XYSeries activities, Job job) {
if (job instanceof Shipment) {
Shipment s = (Shipment) job;
Coordinate pickupCoordinate = getCoordinate(s.getPickupLocation().getCoordinate());
XYDataItem dataItem = new XYDataItem(pickupCoordinate.getX() * scalingFactor, pickupCoordinate.getY() * scalingFactor);
for (com.graphhopper.jsprit.core.problem.job.Activity act : job.getActivities()) {
XYDataItem dataItem = new XYDataItem(getCoordinate(act.getLocation().getCoordinate()).getX() * scalingFactor, getCoordinate(act.getLocation().getCoordinate()).getY() * scalingFactor);
activities.add(dataItem);
addLabel(s, dataItem);
markItem(dataItem, Activity.PICKUP);
containsPickupAct = true;
Coordinate deliveryCoordinate = getCoordinate(s.getDeliveryLocation().getCoordinate());
XYDataItem dataItem2 = new XYDataItem(deliveryCoordinate.getX() * scalingFactor, deliveryCoordinate.getY() * scalingFactor);
activities.add(dataItem2);
addLabel(s, dataItem2);
markItem(dataItem2, Activity.DELIVERY);
containsDeliveryAct = true;
} else if (job instanceof Pickup) {
Pickup service = (Pickup) job;
Coordinate coord = getCoordinate(service.getLocation().getCoordinate());
XYDataItem dataItem = new XYDataItem(coord.getX() * scalingFactor, coord.getY() * scalingFactor);
activities.add(dataItem);
addLabel(service, dataItem);
markItem(dataItem, Activity.PICKUP);
containsPickupAct = true;
} else if (job instanceof Delivery) {
Delivery service = (Delivery) job;
Coordinate coord = getCoordinate(service.getLocation().getCoordinate());
XYDataItem dataItem = new XYDataItem(coord.getX() * scalingFactor, coord.getY() * scalingFactor);
activities.add(dataItem);
addLabel(service, dataItem);
markItem(dataItem, Activity.DELIVERY);
containsDeliveryAct = true;
} else if (job instanceof Service) {
Service service = (Service) job;
Coordinate coord = getCoordinate(service.getLocation().getCoordinate());
XYDataItem dataItem = new XYDataItem(coord.getX() * scalingFactor, coord.getY() * scalingFactor);
activities.add(dataItem);
addLabel(service, dataItem);
markItem(dataItem, Activity.SERVICE);
containsServiceAct = true;
} else {
throw new IllegalStateException("job instanceof " + job.getClass().toString() + ". this is not supported.");
addLabel(job, dataItem);
switch (act.getActivityType()) {
case PICKUP:
markItem(dataItem, Activity.PICKUP);
containsPickupAct = true;
break;
case DELIVERY:
markItem(dataItem, Activity.DELIVERY);
containsDeliveryAct = true;
break;
case SERVICE:
markItem(dataItem, Activity.SERVICE);
containsServiceAct = true;
break;
}
}
}
@ -585,11 +548,11 @@ public class Plotter {
boolean firstDim = true;
for (int i = 0; i < job.getSize().getNuOfDimensions(); i++) {
if (firstDim) {
builder.append(String.valueOf(job.getSize().get(i)));
builder.append(job.getSize().get(i));
firstDim = false;
} else {
builder.append(",");
builder.append(String.valueOf(job.getSize().get(i)));
builder.append(job.getSize().get(i));
}
}
builder.append(")");
@ -606,16 +569,16 @@ public class Plotter {
private void retrieveActivities(VehicleRoutingProblem vrp) throws NoLocationFoundException {
activities = new XYSeries("activities", false, true);
for (Vehicle v : vrp.getVehicles()) {
Coordinate start_coordinate = getCoordinate(v.getStartLocation().getCoordinate());
if (start_coordinate == null) throw new NoLocationFoundException();
XYDataItem item = new XYDataItem(start_coordinate.getX() * scalingFactor, start_coordinate.getY() * scalingFactor);
Coordinate startCoordinate = getCoordinate(v.getStartLocation().getCoordinate());
if (startCoordinate == null) throw new NoLocationFoundException();
XYDataItem item = new XYDataItem(startCoordinate.getX() * scalingFactor, startCoordinate.getY() * scalingFactor);
markItem(item, Activity.START);
activities.add(item);
if (!v.getStartLocation().getId().equals(v.getEndLocation().getId())) {
Coordinate end_coordinate = getCoordinate(v.getEndLocation().getCoordinate());
if (end_coordinate == null) throw new NoLocationFoundException();
XYDataItem end_item = new XYDataItem(end_coordinate.getX() * scalingFactor, end_coordinate.getY() * scalingFactor);
Coordinate endCoordinate = getCoordinate(v.getEndLocation().getCoordinate());
if (endCoordinate == null) throw new NoLocationFoundException();
XYDataItem end_item = new XYDataItem(endCoordinate.getX() * scalingFactor, endCoordinate.getY() * scalingFactor);
markItem(end_item, Activity.END);
activities.add(end_item);
}

View file

@ -20,9 +20,9 @@ package com.graphhopper.jsprit.core.algorithm.recreate;
import com.graphhopper.jsprit.core.problem.Location;
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
import com.graphhopper.jsprit.core.problem.job.Activity;
import com.graphhopper.jsprit.core.problem.job.Job;
import com.graphhopper.jsprit.core.problem.job.Service;
import com.graphhopper.jsprit.core.problem.job.Shipment;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow;
/**
* Created by schroeder on 15/10/15.
@ -41,52 +41,40 @@ public class DefaultScorer implements ScoringFunction {
this.vrp = vrp;
}
public void setTimeWindowParam(double tw_param) {
this.timeWindowParam = tw_param;
public void setTimeWindowParam(double twParam) {
this.timeWindowParam = twParam;
}
public void setDepotDistanceParam(double depotDistance_param) {
this.depotDistanceParam = depotDistance_param;
public void setDepotDistanceParam(double depotDistanceParam) {
this.depotDistanceParam = depotDistanceParam;
}
@Override
public double score(InsertionData best, Job job) {
double score;
if (job instanceof Service) {
score = scoreService(best, job);
} else if (job instanceof Shipment) {
score = scoreShipment(best, job);
} else throw new IllegalStateException("not supported");
return score;
return scoreJob(best, job);
}
private double scoreShipment(InsertionData best, Job job) {
Shipment shipment = (Shipment) job;
double maxDepotDistance_1 = Math.max(
getDistance(best.getSelectedVehicle().getStartLocation(), shipment.getPickupLocation()),
getDistance(best.getSelectedVehicle().getStartLocation(), shipment.getDeliveryLocation())
);
double maxDepotDistance_2 = Math.max(
getDistance(best.getSelectedVehicle().getEndLocation(), shipment.getPickupLocation()),
getDistance(best.getSelectedVehicle().getEndLocation(), shipment.getDeliveryLocation())
);
double maxDepotDistance = Math.max(maxDepotDistance_1, maxDepotDistance_2);
double minTimeToOperate = Math.min(shipment.getPickupTimeWindow().getEnd() - shipment.getPickupTimeWindow().getStart(),
shipment.getDeliveryTimeWindow().getEnd() - shipment.getDeliveryTimeWindow().getStart());
private double scoreJob(InsertionData best, Job job) {
Location startLocation = best.getSelectedVehicle().getStartLocation();
Location endLocation = best.getSelectedVehicle().getEndLocation();
double maxDepotDistance = 0;
double minTimeToOperate = Double.MAX_VALUE;
for (Activity act : job.getActivities()) {
maxDepotDistance = Math.max(maxDepotDistance, getDistance(startLocation, act.getLocation()));
maxDepotDistance = Math.max(maxDepotDistance, getDistance(endLocation, act.getLocation()));
TimeWindow tw = getLargestTimeWindow(act);
minTimeToOperate = Math.min(minTimeToOperate, tw.getEnd() - tw.getStart());
}
return Math.max(timeWindowParam * minTimeToOperate, minTimeWindowScore) + depotDistanceParam * maxDepotDistance;
}
private double scoreService(InsertionData best, Job job) {
Location location = ((Service) job).getLocation();
double maxDepotDistance = 0;
if (location != null) {
maxDepotDistance = Math.max(
getDistance(best.getSelectedVehicle().getStartLocation(), location),
getDistance(best.getSelectedVehicle().getEndLocation(), location)
);
private TimeWindow getLargestTimeWindow(Activity act) {
TimeWindow timeWindow = null;
for (TimeWindow tw : act.getTimeWindows()) {
if (timeWindow == null) timeWindow = tw;
else if (tw.larger(timeWindow)) timeWindow = tw;
}
return Math.max(timeWindowParam * (((Service) job).getTimeWindow().getEnd() - ((Service) job).getTimeWindow().getStart()), minTimeWindowScore) +
depotDistanceParam * maxDepotDistance;
return TimeWindow.newInstance(0, Double.MAX_VALUE);
}

View file

@ -52,10 +52,6 @@ final class ServiceInsertionCalculator extends AbstractInsertionCalculator {
private static final Logger logger = LoggerFactory.getLogger(ServiceInsertionCalculator.class);
// private HardRouteConstraint hardRouteLevelConstraint;
// private HardActivityConstraint hardActivityLevelConstraint;
private final SoftRouteConstraint softRouteConstraint;
private final SoftActivityConstraint softActivityConstraint;

View file

@ -20,10 +20,7 @@ package com.graphhopper.jsprit.core.problem;
import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingActivityCosts;
import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingTransportCosts;
import com.graphhopper.jsprit.core.problem.cost.WaitingTimeCosts;
import com.graphhopper.jsprit.core.problem.job.Break;
import com.graphhopper.jsprit.core.problem.job.Job;
import com.graphhopper.jsprit.core.problem.job.Service;
import com.graphhopper.jsprit.core.problem.job.Shipment;
import com.graphhopper.jsprit.core.problem.job.*;
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
import com.graphhopper.jsprit.core.problem.solution.route.activity.BreakActivity;
import com.graphhopper.jsprit.core.problem.solution.route.activity.DefaultShipmentActivityFactory;
@ -226,18 +223,8 @@ public class VehicleRoutingProblem {
}
private void addLocationToTentativeLocations(Job job) {
if (job instanceof Service) {
Location location = ((Service) job).getLocation();
// tentative_coordinates.put(location.getId(), location.getCoordinate());
addLocationToTentativeLocations(location);
} else if (job instanceof Shipment) {
Shipment shipment = (Shipment) job;
Location pickupLocation = shipment.getPickupLocation();
addLocationToTentativeLocations(pickupLocation);
// tentative_coordinates.put(pickupLocation.getId(), pickupLocation.getCoordinate());
Location deliveryLocation = shipment.getDeliveryLocation();
addLocationToTentativeLocations(deliveryLocation);
// tentative_coordinates.put(deliveryLocation.getId(), deliveryLocation.getCoordinate());
for (Activity act : job.getActivities()) {
addLocationToTentativeLocations(act.getLocation());
}
}
@ -247,13 +234,7 @@ public class VehicleRoutingProblem {
}
private void addJobToFinalJobMapAndCreateActivities(Job job) {
if (job instanceof Service) {
Service service = (Service) job;
addService(service);
} else if (job instanceof Shipment) {
Shipment shipment = (Shipment) job;
addShipment(shipment);
}
addJobToFinalMap(job);
List<AbstractActivity> jobActs = jobActivityFactory.createActivities(job);
for (AbstractActivity act : jobActs) {
act.setIndex(activityIndexCounter);
@ -333,13 +314,11 @@ public class VehicleRoutingProblem {
return this;
}
private void addShipment(Shipment job) {
private void addJobToFinalMap(Job job) {
if (jobs.containsKey(job.getId())) {
logger.warn("The job " + job + " has already been added to the job list. This overrides the existing job.");
}
addLocationToTentativeLocations(job);
// tentative_coordinates.put(job.getPickupLocation().getId(), job.getPickupLocation().getCoordinate());
// tentative_coordinates.put(job.getDeliveryLocation().getId(), job.getDeliveryLocation().getCoordinate());
jobs.put(job.getId(), job);
}
@ -516,15 +495,6 @@ public class VehicleRoutingProblem {
return Collections.unmodifiableCollection(tentativeJobs.values());
}
private Builder addService(Service service) {
addLocationToTentativeLocations(service);
if (jobs.containsKey(service.getId())) {
logger.warn("The service " + service + " has already been added to job list. This overrides existing job.");
}
jobs.put(service.getId(), service);
return this;
}
}

View file

@ -0,0 +1,92 @@
/*
* 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.job;
import com.graphhopper.jsprit.core.problem.Location;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow;
import java.util.Collection;
public class Activity {
public enum Type {
PICKUP, DELIVERY, SERVICE, BREAK;
}
public static class Builder {
private final Type activityType;
private Location location;
Collection<TimeWindow> timeWindows;
private double serviceTime;
public Builder(Location location, Type activityType) {
this.location = location;
this.activityType = activityType;
}
public Builder setTimeWindows(Collection<TimeWindow> timeWindows) {
this.timeWindows = timeWindows;
return this;
}
public Builder setServiceTime(double serviceTime) {
this.serviceTime = serviceTime;
return this;
}
public Activity build() {
return new Activity(this);
}
}
private Location location;
private Collection<TimeWindow> timeWindows;
private double serviceTime;
private Activity.Type activityType;
Activity(Builder builder) {
location = builder.location;
timeWindows = builder.timeWindows;
serviceTime = builder.serviceTime;
activityType = builder.activityType;
}
public Type getActivityType() {
return activityType;
}
public Location getLocation() {
return location;
}
public Collection<TimeWindow> getTimeWindows() {
return timeWindows;
}
public double getServiceTime() {
return serviceTime;
}
}

View file

@ -61,12 +61,13 @@ public class Break extends Service {
this.setType("break");
super.capacity = Capacity.Builder.newInstance().build();
super.skills = Skills.Builder.newInstance().build();
super.activity = new Activity.Builder(null, Activity.Type.BREAK).setServiceTime(serviceTime).setTimeWindows(timeWindows.getTimeWindows()).build();
return new Break(this);
}
}
private boolean variableLocation = true;
private boolean variableLocation;
Break(Builder builder) {
super(builder);

View file

@ -59,6 +59,7 @@ public class Delivery extends Service {
this.setType("delivery");
super.capacity = super.capacityBuilder.build();
super.skills = super.skillBuilder.build();
super.activity = new Activity.Builder(location, Activity.Type.DELIVERY).setTimeWindows(timeWindows.getTimeWindows()).setServiceTime(serviceTime).build();
return new Delivery(this);
}

View file

@ -23,6 +23,8 @@ import com.graphhopper.jsprit.core.problem.HasId;
import com.graphhopper.jsprit.core.problem.HasIndex;
import com.graphhopper.jsprit.core.problem.Skills;
import java.util.List;
/**
* Basic interface for all jobs.
*
@ -36,23 +38,23 @@ public interface Job extends HasId, HasIndex {
*
* @return id
*/
public String getId();
String getId();
/**
* Returns size, i.e. capacity-demand, of this job which can consist of an arbitrary number of capacity dimensions.
*
* @return Capacity
*/
public Capacity getSize();
Capacity getSize();
public Skills getRequiredSkills();
Skills getRequiredSkills();
/**
* Returns name.
*
* @return name
*/
public String getName();
String getName();
/**
* Get priority of job. Only 1 (very high) to 10 (very low) are allowed.
@ -61,8 +63,10 @@ public interface Job extends HasId, HasIndex {
*
* @return priority
*/
public int getPriority();
int getPriority();
public double getMaxTimeInVehicle();
double getMaxTimeInVehicle();
List<Activity> getActivities();
}

View file

@ -61,6 +61,7 @@ public class Pickup extends Service {
this.setType("pickup");
super.capacity = super.capacityBuilder.build();
super.skills = super.skillBuilder.build();
super.activity = new Activity.Builder(location, Activity.Type.PICKUP).setTimeWindows(timeWindows.getTimeWindows()).setServiceTime(serviceTime).build();
return new Pickup(this);
}

View file

@ -26,7 +26,10 @@ import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindows;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindowsImpl;
import com.graphhopper.jsprit.core.util.Coordinate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
* Service implementation of a job.
@ -93,6 +96,8 @@ public class Service extends AbstractJob {
protected double maxTimeInVehicle = Double.MAX_VALUE;
protected Activity activity;
Builder(String id){
this.id = id;
timeWindows = new TimeWindowsImpl();
@ -209,6 +214,7 @@ public class Service extends AbstractJob {
this.setType("service");
capacity = capacityBuilder.build();
skills = skillBuilder.build();
activity = new Activity.Builder(location, Activity.Type.SERVICE).setServiceTime(serviceTime).setTimeWindows(timeWindows.getTimeWindows()).build();
return (T) new Service(this);
}
@ -282,6 +288,8 @@ public class Service extends AbstractJob {
private final double maxTimeInVehicle;
private List<Activity> activities = new ArrayList<>();
Service(Builder<?> builder) {
setUserData(builder.userData);
id = builder.id;
@ -294,6 +302,8 @@ public class Service extends AbstractJob {
timeWindows = builder.timeWindows;
priority = builder.priority;
maxTimeInVehicle = builder.maxTimeInVehicle;
activities.add(builder.activity);
activities = Collections.unmodifiableList(activities);
}
public Collection<TimeWindow> getTimeWindows(){
@ -414,4 +424,9 @@ public class Service extends AbstractJob {
return this.maxTimeInVehicle;
}
@Override
public List<Activity> getActivities() {
return activities;
}
}

View file

@ -24,7 +24,10 @@ import com.graphhopper.jsprit.core.problem.Skills;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindowsImpl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
@ -46,8 +49,6 @@ import java.util.Collection;
public class Shipment extends AbstractJob {
/**
* Builder that builds the shipment.
*
@ -89,6 +90,10 @@ public class Shipment extends AbstractJob {
public double maxTimeInVehicle = Double.MAX_VALUE;
private Activity pickup;
private Activity delivery;
/**
* Returns new instance of this builder.
*
@ -252,6 +257,8 @@ public class Shipment extends AbstractJob {
if (deliveryLocation_ == null) throw new IllegalArgumentException("The delivery location is missing.");
capacity = capacityBuilder.build();
skills = skillBuilder.build();
pickup = new Activity.Builder(pickupLocation_, Activity.Type.PICKUP).setServiceTime(pickupServiceTime).setTimeWindows(pickupTimeWindows.getTimeWindows()).build();
delivery = new Activity.Builder(deliveryLocation_, Activity.Type.DELIVERY).setServiceTime(deliveryServiceTime).setTimeWindows(deliveryTimeWindows.getTimeWindows()).build();
return new Shipment(this);
}
@ -368,6 +375,8 @@ public class Shipment extends AbstractJob {
private final double maxTimeInVehicle;
private List<Activity> activities = new ArrayList<>();
Shipment(Builder builder) {
setUserData(builder.userData);
this.id = builder.id;
@ -382,6 +391,9 @@ public class Shipment extends AbstractJob {
this.pickupTimeWindows = builder.pickupTimeWindows;
this.priority = builder.priority;
this.maxTimeInVehicle = builder.maxTimeInVehicle;
activities.add(builder.pickup);
activities.add(builder.delivery);
activities = Collections.unmodifiableList(activities);
}
@Override
@ -520,4 +532,9 @@ public class Shipment extends AbstractJob {
public double getMaxTimeInVehicle() {
return maxTimeInVehicle;
}
@Override
public List<Activity> getActivities() {
return activities;
}
}

View file

@ -75,6 +75,10 @@ public class TimeWindow {
return end;
}
public boolean larger(TimeWindow timeWindow) {
return (this.getEnd() - this.getStart()) > (timeWindow.getEnd() - timeWindow.getStart());
}
@Override
public String toString() {
return "[start=" + start + "][end=" + end + "]";

View file

@ -46,8 +46,7 @@ public class TourActivities {
@Override
public boolean hasNext() {
if (currentIndex >= 0) return true;
return false;
return currentIndex >= 0;
}
@Override
@ -67,9 +66,9 @@ public class TourActivities {
}
}
private final ArrayList<TourActivity> tourActivities = new ArrayList<TourActivity>();
private final ArrayList<TourActivity> tourActivities = new ArrayList<>();
private final Set<Job> jobs = new HashSet<Job>();
private final Set<Job> jobs = new HashSet<>();
private ReverseActivityIterator backward;
@ -123,7 +122,7 @@ public class TourActivities {
* @return true if job has been removed, otherwise false.
*/
public boolean removeJob(Job job) {
boolean jobRemoved = false;
boolean jobRemoved;
if (!jobs.contains(job)) {
return false;
} else {
@ -161,7 +160,7 @@ public class TourActivities {
}
boolean jobIsAlsoAssociateToOtherActs = false;
boolean actRemoved = false;
List<TourActivity> acts = new ArrayList<TourActivity>(tourActivities);
List<TourActivity> acts = new ArrayList<>(tourActivities);
for (TourActivity act : acts) {
if (act == activity) {
tourActivities.remove(act);

View file

@ -31,9 +31,9 @@ import com.graphhopper.jsprit.core.problem.job.Job;
*/
public interface TourActivity extends HasIndex {
public void setTheoreticalEarliestOperationStartTime(double earliest);
void setTheoreticalEarliestOperationStartTime(double earliest);
public void setTheoreticalLatestOperationStartTime(double latest);
void setTheoreticalLatestOperationStartTime(double latest);
/**
* Basic interface of job-activies.
@ -42,14 +42,14 @@ public interface TourActivity extends HasIndex {
*
* @author schroeder
*/
public interface JobActivity extends TourActivity {
interface JobActivity extends TourActivity {
/**
* Returns the job that is involved with this activity.
*
* @return job
*/
public Job getJob();
Job getJob();
}
@ -58,14 +58,14 @@ public interface TourActivity extends HasIndex {
*
* @return name
*/
public abstract String getName();
String getName();
/**
* Returns location.
*
* @return location
*/
public abstract Location getLocation();
Location getLocation();
/**
* Returns the theoretical earliest operation start time, which is the time that is just allowed
@ -73,7 +73,7 @@ public interface TourActivity extends HasIndex {
*
* @return earliest start time
*/
public abstract double getTheoreticalEarliestOperationStartTime();
double getTheoreticalEarliestOperationStartTime();
/**
* Returns the theoretical latest operation start time, which is the time that is just allowed
@ -81,7 +81,7 @@ public interface TourActivity extends HasIndex {
*
* @return latest start time
*/
public abstract double getTheoreticalLatestOperationStartTime();
double getTheoreticalLatestOperationStartTime();
/**
* Returns the operation-time this activity takes.
@ -91,35 +91,35 @@ public interface TourActivity extends HasIndex {
*
* @return operation time
*/
public abstract double getOperationTime();
double getOperationTime();
/**
* Returns the arrival-time of this activity.
*
* @return arrival time
*/
public abstract double getArrTime();
double getArrTime();
/**
* Returns end-time of this activity.
*
* @return end time
*/
public abstract double getEndTime();
double getEndTime();
/**
* Sets the arrival time of that activity.
*
* @param arrTime
*/
public abstract void setArrTime(double arrTime);
void setArrTime(double arrTime);
/**
* Sets the end-time of this activity.
*
* @param endTime
*/
public abstract void setEndTime(double endTime);
void setEndTime(double endTime);
/**
* Returns the capacity-demand of that activity, in terms of what needs to be loaded or unloaded at
@ -127,13 +127,13 @@ public interface TourActivity extends HasIndex {
*
* @return capacity
*/
public abstract Capacity getSize();
Capacity getSize();
/**
* Makes a deep copy of this activity.
*
* @return copied activity
*/
public abstract TourActivity duplicate();
TourActivity duplicate();
}

View file

@ -130,12 +130,8 @@ public class VehicleRoutingProblemTest {
@Test
public void whenServicesAreAdded_vrpShouldContainThem() {
Service s1 = mock(Service.class);
when(s1.getId()).thenReturn("s1");
when(s1.getLocation()).thenReturn(Location.Builder.newInstance().setIndex(1).build());
Service s2 = mock(Service.class);
when(s2.getId()).thenReturn("s2");
when(s2.getLocation()).thenReturn(Location.Builder.newInstance().setIndex(1).build());
Service s1 = Service.Builder.newInstance("s1").setLocation(Location.Builder.newInstance().setIndex(1).build()).build();
Service s2 = Service.Builder.newInstance("s2").setLocation(Location.Builder.newInstance().setIndex(1).build()).build();
VehicleRoutingProblem.Builder vrpBuilder = VehicleRoutingProblem.Builder.newInstance();
vrpBuilder.addJob(s1).addJob(s2);

View file

@ -307,4 +307,11 @@ public class ServiceTest {
assertEquals(42, two.getUserData());
assertNull(three.getUserData());
}
@Test
public void testServiceActivity() {
Service one = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")).build();
assertEquals(1, one.getActivities().size());
assertEquals(Activity.Type.SERVICE, one.getActivities().get(0).getActivityType());
}
}

View file

@ -464,4 +464,13 @@ public class ShipmentTest {
Assert.assertEquals(Double.MAX_VALUE, s.getMaxTimeInVehicle(),0.001);
}
@Test
public void testShipmentActivities() {
Job job = Shipment.Builder.newInstance("s").setPickupLocation(Location.newInstance("loc")).setDeliveryLocation(Location.newInstance("loc"))
.build();
assertEquals(2, job.getActivities().size());
assertEquals(Activity.Type.PICKUP, job.getActivities().get(0).getActivityType());
assertEquals(Activity.Type.DELIVERY, job.getActivities().get(1).getActivityType());
}
}

View file

@ -22,7 +22,6 @@ import com.graphhopper.jsprit.analysis.toolbox.GraphStreamViewer.Label;
import com.graphhopper.jsprit.analysis.toolbox.Plotter;
import com.graphhopper.jsprit.core.algorithm.VehicleRoutingAlgorithm;
import com.graphhopper.jsprit.core.algorithm.box.Jsprit;
import com.graphhopper.jsprit.core.algorithm.box.SchrimpfFactory;
import com.graphhopper.jsprit.core.problem.Location;
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
import com.graphhopper.jsprit.core.problem.job.Service;