mirror of
https://github.com/graphhopper/jsprit.git
synced 2020-01-24 07:45:05 +01:00
event based sheduling and insertion
This commit is contained in:
parent
a4dd1d9ac5
commit
71fbc8ad38
14 changed files with 210 additions and 56 deletions
|
|
@ -71,12 +71,15 @@ public abstract class AbstractInsertionStrategy implements InsertionStrategy{
|
||||||
|
|
||||||
private Inserter inserter;
|
private Inserter inserter;
|
||||||
|
|
||||||
|
private EventListeners eventListeners;
|
||||||
|
|
||||||
protected VehicleRoutingProblem vrp;
|
protected VehicleRoutingProblem vrp;
|
||||||
|
|
||||||
public AbstractInsertionStrategy(VehicleRoutingProblem vrp) {
|
public AbstractInsertionStrategy(VehicleRoutingProblem vrp) {
|
||||||
this.insertionsListeners = new InsertionListeners();
|
this.insertionsListeners = new InsertionListeners();
|
||||||
this.vrp = vrp;
|
this.vrp = vrp;
|
||||||
inserter = new Inserter(insertionsListeners, vrp);
|
inserter = new Inserter(insertionsListeners, vrp);
|
||||||
|
eventListeners = new EventListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRandom(Random random) {
|
public void setRandom(Random random) {
|
||||||
|
|
@ -111,7 +114,14 @@ public abstract class AbstractInsertionStrategy implements InsertionStrategy{
|
||||||
|
|
||||||
protected void insertJob(Job unassignedJob, InsertionData iData, VehicleRoute inRoute){
|
protected void insertJob(Job unassignedJob, InsertionData iData, VehicleRoute inRoute){
|
||||||
logger.trace("insert: [jobId=" + unassignedJob.getId() + "]" + iData );
|
logger.trace("insert: [jobId=" + unassignedJob.getId() + "]" + iData );
|
||||||
inserter.insertJob(unassignedJob, iData, inRoute);
|
insertionsListeners.informBeforeJobInsertion(unassignedJob, iData, inRoute);
|
||||||
|
if(!(inRoute.getVehicle().getId().equals(iData.getSelectedVehicle().getId()))){
|
||||||
|
insertionsListeners.informVehicleSwitched(inRoute, inRoute.getVehicle(), iData.getSelectedVehicle());
|
||||||
|
}
|
||||||
|
for(Event e : iData.getEvents()){
|
||||||
|
eventListeners.inform(e);
|
||||||
|
}
|
||||||
|
insertionsListeners.informJobInserted(unassignedJob, inRoute, iData.getInsertionCost(), iData.getAdditionalTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
package jsprit.core.algorithm.recreate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by schroeder on 19/05/15.
|
||||||
|
*/
|
||||||
|
public interface Event {
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
package jsprit.core.algorithm.recreate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by schroeder on 19/05/15.
|
||||||
|
*/
|
||||||
|
interface EventListener {
|
||||||
|
|
||||||
|
void inform(Event event);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
package jsprit.core.algorithm.recreate;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by schroeder on 19/05/15.
|
||||||
|
*/
|
||||||
|
class EventListeners {
|
||||||
|
|
||||||
|
private List<EventListener> listeners = new ArrayList<EventListener>();
|
||||||
|
|
||||||
|
public EventListeners() {
|
||||||
|
listeners.add(new InsertActivityListener());
|
||||||
|
listeners.add(new SwitchVehicleListener());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void inform(Event event){
|
||||||
|
for(EventListener l : listeners){
|
||||||
|
l.inform(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
package jsprit.core.algorithm.recreate;
|
||||||
|
|
||||||
|
import jsprit.core.problem.solution.route.VehicleRoute;
|
||||||
|
import jsprit.core.problem.solution.route.activity.TourActivity;
|
||||||
|
import jsprit.core.problem.vehicle.Vehicle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by schroeder on 19/05/15.
|
||||||
|
*/
|
||||||
|
class InsertActivity implements Event {
|
||||||
|
|
||||||
|
private VehicleRoute vehicleRoute;
|
||||||
|
|
||||||
|
private Vehicle newVehicle;
|
||||||
|
|
||||||
|
private TourActivity activity;
|
||||||
|
|
||||||
|
private int index;
|
||||||
|
|
||||||
|
public InsertActivity(VehicleRoute vehicleRoute, Vehicle newVehicle, TourActivity activity, int index) {
|
||||||
|
this.vehicleRoute = vehicleRoute;
|
||||||
|
this.newVehicle = newVehicle;
|
||||||
|
this.activity = activity;
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vehicle getNewVehicle() {
|
||||||
|
return newVehicle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VehicleRoute getVehicleRoute() {
|
||||||
|
return vehicleRoute;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TourActivity getActivity() {
|
||||||
|
return activity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
package jsprit.core.algorithm.recreate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by schroeder on 19/05/15.
|
||||||
|
*/
|
||||||
|
class InsertActivityListener implements EventListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void inform(Event event) {
|
||||||
|
if(event instanceof InsertActivity){
|
||||||
|
InsertActivity insertActivity = (InsertActivity) event;
|
||||||
|
if(!insertActivity.getNewVehicle().isReturnToDepot()){
|
||||||
|
if(insertActivity.getIndex()>=insertActivity.getVehicleRoute().getActivities().size()){
|
||||||
|
insertActivity.getVehicleRoute().getEnd().setLocation(insertActivity.getActivity().getLocation());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
insertActivity.getVehicleRoute().getTourActivities().addActivity(insertActivity.getIndex(),((InsertActivity) event).getActivity());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -19,6 +19,9 @@ package jsprit.core.algorithm.recreate;
|
||||||
import jsprit.core.problem.driver.Driver;
|
import jsprit.core.problem.driver.Driver;
|
||||||
import jsprit.core.problem.vehicle.Vehicle;
|
import jsprit.core.problem.vehicle.Vehicle;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Data object that collects insertion information. It collects insertionCosts, insertionIndeces, vehicle and driver to be employed
|
* Data object that collects insertion information. It collects insertionCosts, insertionIndeces, vehicle and driver to be employed
|
||||||
* and departureTime of vehicle at vehicle's start location (e.g. depot).
|
* and departureTime of vehicle at vehicle's start location (e.g. depot).
|
||||||
|
|
@ -66,6 +69,12 @@ public class InsertionData {
|
||||||
|
|
||||||
private double additionalTime;
|
private double additionalTime;
|
||||||
|
|
||||||
|
private List<Event> events = new ArrayList<Event>();
|
||||||
|
|
||||||
|
List<Event> getEvents(){
|
||||||
|
return events;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the additionalTime
|
* @return the additionalTime
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,7 @@ final class JobInsertionConsideringFixCostsCalculator implements JobInsertionCos
|
||||||
double totalInsertionCost = iData.getInsertionCost() + fixcost_contribution;
|
double totalInsertionCost = iData.getInsertionCost() + fixcost_contribution;
|
||||||
InsertionData insertionData = new InsertionData(totalInsertionCost, iData.getPickupInsertionIndex(), iData.getDeliveryInsertionIndex(), newVehicle, newDriver);
|
InsertionData insertionData = new InsertionData(totalInsertionCost, iData.getPickupInsertionIndex(), iData.getDeliveryInsertionIndex(), newVehicle, newDriver);
|
||||||
insertionData.setVehicleDepartureTime(newVehicleDepartureTime);
|
insertionData.setVehicleDepartureTime(newVehicleDepartureTime);
|
||||||
|
insertionData.getEvents().addAll(iData.getEvents());
|
||||||
return insertionData;
|
return insertionData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -155,6 +155,8 @@ final class ServiceInsertionCalculator implements JobInsertionCostsCalculator{
|
||||||
return InsertionData.createEmptyInsertionData();
|
return InsertionData.createEmptyInsertionData();
|
||||||
}
|
}
|
||||||
InsertionData insertionData = new InsertionData(bestCost, InsertionData.NO_INDEX, insertionIndex, newVehicle, newDriver);
|
InsertionData insertionData = new InsertionData(bestCost, InsertionData.NO_INDEX, insertionIndex, newVehicle, newDriver);
|
||||||
|
insertionData.getEvents().add(new InsertActivity(currentRoute,newVehicle,deliveryAct2Insert,insertionIndex));
|
||||||
|
insertionData.getEvents().add(new SwitchVehicle(currentRoute,newVehicle,newVehicleDepartureTime));
|
||||||
insertionData.setVehicleDepartureTime(newVehicleDepartureTime);
|
insertionData.setVehicleDepartureTime(newVehicleDepartureTime);
|
||||||
return insertionData;
|
return insertionData;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -225,6 +225,9 @@ final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator{
|
||||||
}
|
}
|
||||||
InsertionData insertionData = new InsertionData(bestCost, pickupInsertionIndex, deliveryInsertionIndex, newVehicle, newDriver);
|
InsertionData insertionData = new InsertionData(bestCost, pickupInsertionIndex, deliveryInsertionIndex, newVehicle, newDriver);
|
||||||
insertionData.setVehicleDepartureTime(newVehicleDepartureTime);
|
insertionData.setVehicleDepartureTime(newVehicleDepartureTime);
|
||||||
|
insertionData.getEvents().add(new InsertActivity(currentRoute,newVehicle,deliverShipment,deliveryInsertionIndex));
|
||||||
|
insertionData.getEvents().add(new InsertActivity(currentRoute,newVehicle,pickupShipment,pickupInsertionIndex));
|
||||||
|
insertionData.getEvents().add(new SwitchVehicle(currentRoute,newVehicle,newVehicleDepartureTime));
|
||||||
return insertionData;
|
return insertionData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
package jsprit.core.algorithm.recreate;
|
||||||
|
|
||||||
|
import jsprit.core.problem.solution.route.VehicleRoute;
|
||||||
|
import jsprit.core.problem.vehicle.Vehicle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by schroeder on 19/05/15.
|
||||||
|
*/
|
||||||
|
class SwitchVehicle implements Event {
|
||||||
|
|
||||||
|
private VehicleRoute route;
|
||||||
|
|
||||||
|
private Vehicle vehicle;
|
||||||
|
|
||||||
|
private double departureTime;
|
||||||
|
|
||||||
|
public SwitchVehicle(VehicleRoute route, Vehicle vehicle, double departureTime) {
|
||||||
|
this.route = route;
|
||||||
|
this.vehicle = vehicle;
|
||||||
|
this.departureTime = departureTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VehicleRoute getRoute() {
|
||||||
|
return route;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vehicle getVehicle() {
|
||||||
|
return vehicle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getDepartureTime() {
|
||||||
|
return departureTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
package jsprit.core.algorithm.recreate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by schroeder on 19/05/15.
|
||||||
|
*/
|
||||||
|
class SwitchVehicleListener implements EventListener{
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void inform(Event event) {
|
||||||
|
if(event instanceof SwitchVehicle){
|
||||||
|
SwitchVehicle switchVehicle = (SwitchVehicle) event;
|
||||||
|
switchVehicle.getRoute().setVehicleAndDepartureTime(switchVehicle.getVehicle(),((SwitchVehicle) event).getDepartureTime());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -168,6 +168,8 @@ public class RegretInsertionTest {
|
||||||
if(currentRoute.isEmpty()){
|
if(currentRoute.isEmpty()){
|
||||||
double mc = getCost(service.getLocation(), vehicle.getStartLocation());
|
double mc = getCost(service.getLocation(), vehicle.getStartLocation());
|
||||||
iData = new InsertionData(2*mc,-1,0,vehicle,newDriver);
|
iData = new InsertionData(2*mc,-1,0,vehicle,newDriver);
|
||||||
|
iData.getEvents().add(new InsertActivity(currentRoute,vehicle,vrp.copyAndGetActivities(newJob).get(0),0));
|
||||||
|
iData.getEvents().add(new SwitchVehicle(currentRoute,vehicle,newVehicleDepartureTime));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
double best = Double.MAX_VALUE;
|
double best = Double.MAX_VALUE;
|
||||||
|
|
@ -189,6 +191,8 @@ public class RegretInsertionTest {
|
||||||
bestIndex = index;
|
bestIndex = index;
|
||||||
}
|
}
|
||||||
iData = new InsertionData(best,-1,bestIndex,vehicle,newDriver);
|
iData = new InsertionData(best,-1,bestIndex,vehicle,newDriver);
|
||||||
|
iData.getEvents().add(new InsertActivity(currentRoute,vehicle,vrp.copyAndGetActivities(newJob).get(0),bestIndex));
|
||||||
|
iData.getEvents().add(new SwitchVehicle(currentRoute,vehicle,newVehicleDepartureTime));
|
||||||
}
|
}
|
||||||
return iData;
|
return iData;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,24 @@
|
||||||
<problem xmlns="http://www.w3schools.com"
|
<problem xmlns="http://www.w3schools.com"
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.w3schools.com vrp_xml_schema.xsd">
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.w3schools.com vrp_xml_schema.xsd">
|
||||||
<problemType>
|
<problemType>
|
||||||
<fleetSize>INFINITE</fleetSize>
|
<fleetSize>FINITE</fleetSize>
|
||||||
</problemType>
|
</problemType>
|
||||||
<vehicles>
|
<vehicles>
|
||||||
|
<vehicle>
|
||||||
|
<id>v2</id>
|
||||||
|
<typeId>vehType2</typeId>
|
||||||
|
<startLocation>
|
||||||
|
<id>loc</id>
|
||||||
|
</startLocation>
|
||||||
|
<endLocation>
|
||||||
|
<id>loc</id>
|
||||||
|
</endLocation>
|
||||||
|
<timeSchedule>
|
||||||
|
<start>0.0</start>
|
||||||
|
<end>1.7976931348623157E308</end>
|
||||||
|
</timeSchedule>
|
||||||
|
<returnToDepot>true</returnToDepot>
|
||||||
|
</vehicle>
|
||||||
<vehicle>
|
<vehicle>
|
||||||
<id>v1</id>
|
<id>v1</id>
|
||||||
<typeId>vehType</typeId>
|
<typeId>vehType</typeId>
|
||||||
|
|
@ -33,58 +48,16 @@
|
||||||
<time>0.0</time>
|
<time>0.0</time>
|
||||||
</costs>
|
</costs>
|
||||||
</type>
|
</type>
|
||||||
|
<type>
|
||||||
|
<id>vehType2</id>
|
||||||
|
<capacity-dimensions>
|
||||||
|
<dimension index="0">200</dimension>
|
||||||
|
</capacity-dimensions>
|
||||||
|
<costs>
|
||||||
|
<fixed>0.0</fixed>
|
||||||
|
<distance>1.0</distance>
|
||||||
|
<time>0.0</time>
|
||||||
|
</costs>
|
||||||
|
</type>
|
||||||
</vehicleTypes>
|
</vehicleTypes>
|
||||||
<services>
|
|
||||||
<service id="1" type="service">
|
|
||||||
<location>
|
|
||||||
<id>loc</id>
|
|
||||||
</location>
|
|
||||||
<capacity-dimensions>
|
|
||||||
<dimension index="0">1</dimension>
|
|
||||||
</capacity-dimensions>
|
|
||||||
<duration>2.0</duration>
|
|
||||||
<timeWindows>
|
|
||||||
<timeWindow>
|
|
||||||
<start>0.0</start>
|
|
||||||
<end>1.7976931348623157E308</end>
|
|
||||||
</timeWindow>
|
|
||||||
</timeWindows>
|
|
||||||
</service>
|
|
||||||
<service id="2" type="service">
|
|
||||||
<location>
|
|
||||||
<id>loc2</id>
|
|
||||||
</location>
|
|
||||||
<capacity-dimensions>
|
|
||||||
<dimension index="0">1</dimension>
|
|
||||||
</capacity-dimensions>
|
|
||||||
<duration>4.0</duration>
|
|
||||||
<timeWindows>
|
|
||||||
<timeWindow>
|
|
||||||
<start>0.0</start>
|
|
||||||
<end>1.7976931348623157E308</end>
|
|
||||||
</timeWindow>
|
|
||||||
</timeWindows>
|
|
||||||
</service>
|
|
||||||
</services>
|
|
||||||
<solutions>
|
|
||||||
<solution>
|
|
||||||
<cost>10.0</cost>
|
|
||||||
<routes>
|
|
||||||
<route>
|
|
||||||
<driverId>noDriver</driverId>
|
|
||||||
<vehicleId>v1</vehicleId>
|
|
||||||
<start>0.0</start>
|
|
||||||
<act type="service">
|
|
||||||
<serviceId>1</serviceId>
|
|
||||||
<arrTime>0.0</arrTime>
|
|
||||||
<endTime>0.0</endTime>
|
|
||||||
</act>
|
|
||||||
<end>0.0</end>
|
|
||||||
</route>
|
|
||||||
</routes>
|
|
||||||
<unassignedJobs>
|
|
||||||
<job id="2"/>
|
|
||||||
</unassignedJobs>
|
|
||||||
</solution>
|
|
||||||
</solutions>
|
|
||||||
</problem>
|
</problem>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue