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

Merge branch 'master' into multiple-cap-constraints

Conflicts:
	jsprit-core/src/main/java/jsprit/core/problem/job/Job.java
	jsprit-core/src/main/java/jsprit/core/problem/job/Service.java
	jsprit-core/src/main/java/jsprit/core/problem/job/Shipment.java
	jsprit-core/src/test/java/jsprit/core/problem/job/ServiceTest.java
This commit is contained in:
oblonski 2014-02-04 21:47:15 +01:00
commit ef2723d801
34 changed files with 1517 additions and 203 deletions

View file

@ -47,7 +47,7 @@ import jsprit.core.util.CalculationUtils;
if(arrTimeAtNextAct > latestArrTimeAtNextAct){
return ConstraintsStatus.NOT_FULFILLED;
}
double arrTimeAtNextOnDirectRouteWithNewVehicle = prevActDepTime + routingCosts.getTransportCost(prevAct.getLocationId(), nextAct.getLocationId(), prevActDepTime, iFacts.getNewDriver(), iFacts.getNewVehicle());
double arrTimeAtNextOnDirectRouteWithNewVehicle = prevActDepTime + routingCosts.getTransportTime(prevAct.getLocationId(), nextAct.getLocationId(), prevActDepTime, iFacts.getNewDriver(), iFacts.getNewVehicle());
//if vehicle cannot even manage direct-route - break
if(arrTimeAtNextOnDirectRouteWithNewVehicle > latestArrTimeAtNextAct){
return ConstraintsStatus.NOT_FULFILLED_BREAK;

View file

@ -316,13 +316,16 @@ public class VrpXMLReader{
int cap = getCap(shipmentConfig);
Shipment.Builder builder = Shipment.Builder.newInstance(id, cap);
//pickup-locationId
String pickupLocationId = shipmentConfig.getString("pickup.locationId");
builder.setPickupLocation(pickupLocationId);
if(pickupLocationId != null){
builder.setPickupLocation(pickupLocationId);
}
//pickup-coord
Coordinate pickupCoord = getCoord(shipmentConfig,"pickup.");
builder.setPickupCoord(pickupCoord);
if(pickupCoord != null){
builder.setPickupCoord(pickupCoord);
if(pickupLocationId != null){
vrpBuilder.addLocation(pickupLocationId,pickupCoord);
}
@ -331,32 +334,49 @@ public class VrpXMLReader{
builder.setPickupLocation(pickupCoord.toString());
}
}
//pickup-serviceTime
String pickupServiceTime = shipmentConfig.getString("pickup.duration");
if(pickupServiceTime != null) builder.setPickupServiceTime(Double.parseDouble(pickupServiceTime));
// String pickupTWStart = shipmentConfig.getString("pickup.timeWindows.timeWindow(0).start");
// String pickupTWEnd = shipmentConfig.getString("pickup.timeWindows.timeWindow(0).end");
// TimeWindow pickupTW = TimeWindow.newInstance(Double.parseDouble(pickupTWStart), Double.parseDouble(pickupTWEnd));
// builder.setPickupTimeWindow(pickupTW);
//pickup-tw
String pickupTWStart = shipmentConfig.getString("pickup.timeWindows.timeWindow(0).start");
String pickupTWEnd = shipmentConfig.getString("pickup.timeWindows.timeWindow(0).end");
if(pickupTWStart != null && pickupTWEnd != null){
TimeWindow pickupTW = TimeWindow.newInstance(Double.parseDouble(pickupTWStart), Double.parseDouble(pickupTWEnd));
builder.setPickupTimeWindow(pickupTW);
}
//delivery-locationId
String deliveryLocationId = shipmentConfig.getString("delivery.locationId");
builder.setDeliveryLocation(deliveryLocationId);
if(deliveryLocationId != null){
builder.setDeliveryLocation(deliveryLocationId);
}
//delivery-coord
Coordinate deliveryCoord = getCoord(shipmentConfig,"delivery.");
builder.setDeliveryCoord(deliveryCoord);
if(deliveryCoord != null){
builder.setDeliveryCoord(deliveryCoord);
if(deliveryLocationId != null){
vrpBuilder.addLocation(deliveryLocationId,deliveryCoord);
}
else{
vrpBuilder.addLocation(deliveryCoord.toString(),deliveryCoord);
builder.setPickupLocation(deliveryCoord.toString());
builder.setDeliveryLocation(deliveryCoord.toString());
}
}
//delivery-serviceTime
String deliveryServiceTime = shipmentConfig.getString("delivery.duration");
if(deliveryServiceTime != null) builder.setDeliveryServiceTime(Double.parseDouble(deliveryServiceTime));
//delivery-tw
String delTWStart = shipmentConfig.getString("delivery.timeWindows.timeWindow(0).start");
String delTWEnd = shipmentConfig.getString("delivery.timeWindows.timeWindow(0).end");
TimeWindow delTW = TimeWindow.newInstance(Double.parseDouble(delTWStart), Double.parseDouble(delTWEnd));
builder.setDeliveryTimeWindow(delTW);
if(delTWStart != null && delTWEnd != null){
TimeWindow delTW = TimeWindow.newInstance(Double.parseDouble(delTWStart), Double.parseDouble(delTWEnd));
builder.setDeliveryTimeWindow(delTW);
}
Shipment shipment = builder.build();
vrpBuilder.addJob(shipment);
@ -391,10 +411,10 @@ public class VrpXMLReader{
int cap = getCap(serviceConfig);
Service.Builder builder = serviceBuilderFactory.createBuilder(type, id, cap);
String serviceLocationId = serviceConfig.getString("locationId");
builder.setLocationId(serviceLocationId);
if(serviceLocationId != null) builder.setLocationId(serviceLocationId);
Coordinate serviceCoord = getCoord(serviceConfig,"");
builder.setCoord(serviceCoord);
if(serviceCoord != null){
builder.setCoord(serviceCoord);
if(serviceLocationId != null){
vrpBuilder.addLocation(serviceLocationId,serviceCoord);
}

View file

@ -16,19 +16,44 @@
******************************************************************************/
package jsprit.core.problem.job;
/**
* Delivery extends Service and is intended to model a Service where smth is UNLOADED (i.e. delivered) from a transport unit.
*
* @author schroeder
*
*/
public class Delivery extends Service{
public static class Builder extends Service.Builder {
/**
* Returns a new instance of Delivery.Builder
*
* @param id
* @param size
* @return builder
* @throws IllegalArgumentException if size < 0 or id is null
*/
public static Builder newInstance(String id, int size){
return new Builder(id,size);
}
/**
* Constructs the builder
*
* @param id
* @param size
* @throws IllegalArgumentException if size < 0 or id is null
*/
Builder(String id, int size) {
super(id, size);
}
/**
* Builds Delivery.
*
* @return delivery
* @throw IllegalStateException if neither locationId nor coord is set
*/
public Delivery build(){
if(locationId == null) {
if(coord == null) throw new IllegalStateException("either locationId or a coordinate must be given. But is not.");
@ -40,6 +65,11 @@ public class Delivery extends Service{
}
/**
* Constructs Delivery.
*
* @param builder
*/
Delivery(Builder builder) {
super(builder);

View file

@ -16,12 +16,32 @@
******************************************************************************/
package jsprit.core.problem.job;
import jsprit.core.problem.Capacity;
/**
* Basic interface for all jobs.
*
* @author schroeder
*
*/
public interface Job {
/**
* Returns the unique identifier (id) of a job.
*
* @return id
*/
public String getId();
/**
* Returns capacity (demand) of job.
*
* <p>It determines how much capacity this job consumes of vehicle/transport unit.
*
* @deprecated use getCapacity() instead
* @return
*/
@Deprecated
public int getCapacityDemand();

View file

@ -16,18 +16,47 @@
******************************************************************************/
package jsprit.core.problem.job;
/**
* Pickup extends Service and is intended to model a Service where smth is LOADED (i.e. picked up) to a transport unit.
*
* @author schroeder
*
*/
public class Pickup extends Service {
public static class Builder extends Service.Builder {
/**
* Returns a new instance of Pickup.Builder
*
* @param id
* @param size
* @return builder
* @throws IllegalArgumentException if size < 0 or id is null
*/
public static Builder newInstance(String id, int size){
return new Builder(id,size);
}
/**
* Constructs the builder.
*
* @param id
* @param size
* @throws IllegalArgumentException if size < 0 or id is null
*/
Builder(String id, int size) {
super(id, size);
}
/**
* Builds Pickup.
*
*<p>Pickup type is "pickup"
*
* @return pickup
* @throw IllegalStateException if neither locationId nor coordinate has been set
*/
public Pickup build(){
if(locationId == null) {
if(coord == null) throw new IllegalStateException("either locationId or a coordinate must be given. But is not.");
@ -39,6 +68,11 @@ public class Pickup extends Service {
}
/**
* Constructs the Pickup
*
* @param builder
*/
Pickup(Builder builder) {
super(builder);
}

View file

@ -20,11 +20,35 @@ import jsprit.core.problem.Capacity;
import jsprit.core.problem.solution.route.activity.TimeWindow;
import jsprit.core.util.Coordinate;
/**
* Service implementation of a job.
*
* <p>A service distinguishes itself from a shipment such that it has only one location. Thus a service
* is a single point in space (where a service-activity occurs).
*
* <p>Note that two services are equal if they have the same id.
*
* @author schroeder
*
*/
public class Service implements Job {
/**
* Builder that builds a service.
*
* @author schroeder
*
*/
public static class Builder {
/**
* Returns a new instance of service-builder.
*
* @param id of service
* @param size of capacity-demand
* @return builder
* @throws IllegalArgumentException if size < 0 or id is null
*/
public static Builder newInstance(String id, int size){
Builder builder = new Builder(id,size);
builder.addCapacityDimension(0, size);
@ -36,17 +60,31 @@ public class Service implements Job {
}
private String id;
protected String locationId;
private String type = "service";
protected Coordinate coord;
protected double serviceTime;
protected TimeWindow timeWindow = TimeWindow.newInstance(0.0, Double.MAX_VALUE);
protected int demand;
protected Capacity.Builder capacityBuilder = Capacity.Builder.newInstance();
protected Capacity capacity;
/**
* Constructs the builder.
*
* @param id
* @param size
* @throws IllegalArgumentException if size < 0 or id is null
*/
Builder(String id, int size) {
if(size < 0) throw new IllegalArgumentException("size must be greater than or equal to zero");
if(id == null) throw new IllegalArgumentException("id must not be null");
this.id = id;
this.demand = size;
}
@ -55,37 +93,84 @@ public class Service implements Job {
this.id = id;
}
/**
* Protected method to set the type-name of the service.
*
* <p>Currently there are {@link Service}, {@link Pickup} and {@link Delivery}.
*
* @param name
* @return the builder
*/
protected Builder setType(String name){
this.type = name;
return this;
}
/**
* Sets the location-id of this service.
*
* @param locationId
* @return builder
*/
public Builder setLocationId(String locationId){
this.locationId = locationId;
return this;
}
/**
* Sets the coordinate of this service.
*
* @param coord
* @return builder
*/
public Builder setCoord(Coordinate coord){
this.coord = coord;
return this;
}
/**
* Sets the serviceTime of this service.
*
* <p>It is understood as time that a service or its implied activity takes at the service-location, for instance
* to unload goods.
*
* @param serviceTime
* @return builder
* @throws IllegalArgumentException if serviceTime < 0
*/
public Builder setServiceTime(double serviceTime){
if(serviceTime < 0) throw new IllegalArgumentException("serviceTime must be greate than or equal to zero");
if(serviceTime < 0) throw new IllegalArgumentException("serviceTime must be greater than or equal to zero");
this.serviceTime = serviceTime;
return this;
}
public Builder addCapacityDimension(int dimensionIndex, int dimensionValue){
capacityBuilder.addDimension(dimensionIndex, dimensionValue);
return this;
}
/**
* Sets the time-window of this service.
*
* <p>The time-window indicates the time period a service/activity/operation is allowed to start.
*
* @param tw
* @return builder
* @throw IllegalArgumentException if timeWindow is null
*/
public Builder setTimeWindow(TimeWindow tw){
if(tw == null) throw new IllegalArgumentException("time-window arg must not be null");
this.timeWindow = tw;
return this;
}
/**
* Builds the service.
*
* @return {@link Service}
* @throws IllegalStateException if neither locationId nor coordinate is set.
*/
public Service build(){
if(locationId == null) {
if(coord == null) throw new IllegalStateException("either locationId or a coordinate must be given. But is not.");
@ -131,18 +216,38 @@ public class Service implements Job {
return id;
}
/**
* Returns the location-id of this service.
*
* @return String that indicates the location
*/
public String getLocationId() {
return locationId;
}
/**
* Returns the coordinate of this service.
*
* @return {@link Coordinate}
*/
public Coordinate getCoord(){
return coord;
}
/**
* Returns the service-time/duration a service takes at service-location.
*
* @return service duration
*/
public double getServiceDuration() {
return serviceTime;
}
/**
* Returns the time-window a service(-operation) is allowed to start.
*
* @return time window
*/
public TimeWindow getTimeWindow(){
return timeWindow;
}
@ -159,14 +264,17 @@ public class Service implements Job {
return type;
}
/**
* Returns a string with the service's attributes.
*
* <p>String is built as follows: [attr1=val1][attr2=val2]...
*/
@Override
public String toString() {
return "[id=" + id + "][type="+type+"][locationId=" + locationId + "][coord="+coord+"][size=" + demand + "][serviceTime=" + serviceTime + "][timeWindow=" + timeWindow + "]";
}
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 31;
@ -175,8 +283,9 @@ public class Service implements Job {
return result;
}
/* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
/**
* Two services are equal if they have the same id.
*
*/
@Override
public boolean equals(Object obj) {

View file

@ -4,8 +4,31 @@ import jsprit.core.problem.Capacity;
import jsprit.core.problem.solution.route.activity.TimeWindow;
import jsprit.core.util.Coordinate;
/**
* Shipment is an implementation of Job and consists of a pickup and a delivery of something.
*
* <p>It distinguishes itself from {@link Service} as two locations are involved a pickup where usually
* something is loaded to the transport unit and a delivery where something is unloaded.
*
* <p>By default serviceTimes of both pickup and delivery is 0.0 and timeWindows of both is [0.0, Double.MAX_VALUE],
*
* <p>A shipment can be built with a builder. You can get an instance of the builder by coding <code>Shipment.Builder.newInstance(...)</code>.
* This way you can specify the shipment. Once you build the shipment, it is immutable, i.e. fields/attributes cannot be changed anymore and
* you can only 'get' the specified values.
*
* <p>Note that two shipments are equal if they have the same id.
*
* @author schroeder
*
*/
public class Shipment implements Job{
/**
* Builder that builds the shipment.
*
* @author schroeder
*
*/
public static class Builder {
private int demand;
@ -32,6 +55,14 @@ public class Shipment implements Job{
private Capacity capacity;
/**
* Returns a new instance of this builder.
*
* @param id
* @param size
* @return builder
* @throws IllegalArgumentException if size < 0 or id is null
*/
public static Builder newInstance(String id, int size){
Builder builder = new Builder(id,size);
builder.addCapacityDimension(0, size);
@ -42,8 +73,16 @@ public class Shipment implements Job{
return new Builder(id);
}
/**
* Constructs the builder
*
* @param id
* @param size
* @throws IllegalArgumentException if size < 0 or id is null
*/
Builder(String id, int size) {
if(size < 0) throw new IllegalArgumentException("size must be greater than or equal to zero");
if(id == null) throw new IllegalArgumentException("id must not be null");
this.id = id;
this.demand = size;
}
@ -52,51 +91,140 @@ public class Shipment implements Job{
this.id = id;
}
/**
* Sets pickup-location.
*
* @param pickupLocation
* @return builder
* @throws IllegalArgumentException if location is null
*/
public Builder setPickupLocation(String pickupLocation){
if(pickupLocation == null) throw new IllegalArgumentException("location must not be null");
this.pickupLocation = pickupLocation;
return this;
}
/**
* Sets pickup-coordinate.
*
* @param pickupCoord
* @return builder
* @throws IllegalArgumentException if pickupCoord is null
*/
public Builder setPickupCoord(Coordinate pickupCoord){
if(pickupCoord == null) throw new IllegalArgumentException("coord must not be null");
this.pickupCoord = pickupCoord;
return this;
}
/**
* Sets pickupServiceTime.
*
* <p>ServiceTime is intended to be the time the implied activity takes at the pickup-location.
*
* @param serviceTime
* @return builder
* @throws IllegalArgumentException if servicTime < 0.0
*/
public Builder setPickupServiceTime(double serviceTime){
if(serviceTime < 0.0) throw new IllegalArgumentException("serviceTime must not be < 0.0");
this.pickupServiceTime = serviceTime;
return this;
}
/**
* Sets the timeWindow for the pickup, i.e. the time-period in which a pickup operation is
* allowed to start.
*
* <p>By default timeWindow is [0.0, Double.MAX_VALUE}
*
* @param timeWindow
* @return builder
* @throws IllegalArgumentException if timeWindow is null
*/
public Builder setPickupTimeWindow(TimeWindow timeWindow){
if(timeWindow == null) throw new IllegalArgumentException("timeWindow cannot be null");
this.pickupTimeWindow = timeWindow;
return this;
}
/**
* Sets the delivery-location.
*
* @param deliveryLocation
* @return builder
* @throws IllegalArgumentException if location is null
*/
public Builder setDeliveryLocation(String deliveryLocation){
if(deliveryLocation == null) throw new IllegalArgumentException("delivery location must not be null");
this.deliveryLocation = deliveryLocation;
return this;
}
/**
* Sets delivery-coord.
*
* @param deliveryCoord
* @return builder
* @throws IllegalArgumentException if coord is null;
*/
public Builder setDeliveryCoord(Coordinate deliveryCoord){
if(deliveryCoord == null) throw new IllegalArgumentException("coord must not be null");
this.deliveryCoord = deliveryCoord;
return this;
}
/**
* Sets the delivery service-time.
*
* <p>ServiceTime is intended to be the time the implied activity takes at the delivery-location.
*
* @param deliveryServiceTime
* @return builder
* @throws IllegalArgumentException if serviceTime < 0.0
*/
public Builder setDeliveryServiceTime(double deliveryServiceTime){
if(deliveryServiceTime < 0.0) throw new IllegalArgumentException("deliveryServiceTime must not be < 0.0");
this.deliveryServiceTime = deliveryServiceTime;
return this;
}
/**
* Sets the timeWindow for the delivery, i.e. the time-period in which a delivery operation is
* allowed to start.
*
* <p>By default timeWindow is [0.0, Double.MAX_VALUE}
*
* @param timeWindow
* @return builder
* @throws IllegalArgumentException if timeWindow is null
*/
public Builder setDeliveryTimeWindow(TimeWindow timeWindow){
if(timeWindow == null) throw new IllegalArgumentException("delivery time-window must not be null");
this.deliveryTimeWindow = timeWindow;
return this;
}
/**
* Adds capacity dimension.
*
* @param dimIndex
* @param dimVal
* @return
*/
public Builder addCapacityDimension(int dimIndex, int dimVal) {
capacityBuilder.addDimension(dimIndex, dimVal);
return this;
}
/**
* Builds the shipment.
*
* @return shipment
* @throws IllegalStateException if neither pickup-location nor pickup-coord is set or if neither delivery-location nor delivery-coord
* is set
*/
public Shipment build(){
if(pickupLocation == null) {
if(pickupCoord == null) throw new IllegalStateException("either locationId or a coordinate must be given. But is not.");
@ -134,7 +262,13 @@ public class Shipment implements Job{
private final TimeWindow pickupTimeWindow;
private final Capacity capacity;
/**
* Constructs the shipment.
*
* @param builder
*/
Shipment(Builder builder){
this.id = builder.id;
this.demand = builder.demand;
@ -159,34 +293,76 @@ public class Shipment implements Job{
return demand;
}
/**
* Returns the pickup-location.
*
* @return pickup-location
*/
public String getPickupLocation() {
return pickupLocation;
}
/**
* Returns the pickup-coordinate.
*
* @return coordinate of the pickup
*/
public Coordinate getPickupCoord() {
return pickupCoord;
}
/**
* Returns the pickup service-time.
*
* <p>By default service-time is 0.0.
*
* @return service-time
*/
public double getPickupServiceTime() {
return pickupServiceTime;
}
/**
* Returns delivery-location.
*
* @return delivery-location
*/
public String getDeliveryLocation() {
return deliveryLocation;
}
/**
* Returns coordinate of the delivery.
*
* @return coordinate of delivery
*/
public Coordinate getDeliveryCoord() {
return deliveryCoord;
}
/**
* Returns service-time of delivery.
*
* @return service-time of delivery
*/
public double getDeliveryServiceTime() {
return deliveryServiceTime;
}
/**
* Returns the time-window of delivery.
*
* @return time-window of delivery
*/
public TimeWindow getDeliveryTimeWindow() {
return deliveryTimeWindow;
}
/**
* Returns the time-window of pickup.
*
* @return time-window of pickup
*/
public TimeWindow getPickupTimeWindow() {
return pickupTimeWindow;
}
@ -199,6 +375,11 @@ public class Shipment implements Job{
return result;
}
/**
* Two shipments are equal if they have the same id.
*
* @return true if shipments are equal (have the same id)
*/
@Override
public boolean equals(Object obj) {
if (this == obj)

View file

@ -37,22 +37,65 @@ import jsprit.core.problem.vehicle.Vehicle;
import jsprit.core.problem.vehicle.VehicleImpl;
import jsprit.core.problem.vehicle.VehicleImpl.NoVehicle;
/**
* Contains the tour, i.e. a number of activities, a vehicle servicing the tour and a driver.
*
*
* @author stefan
*
*/
public class VehicleRoute {
/**
* Returns a deep copy of this vehicleRoute.
*
* @param route
* @return copied route
* @throws IllegalArgumentException if route is null
*/
public static VehicleRoute copyOf(VehicleRoute route) {
if(route == null) throw new IllegalArgumentException("route must not be null");
return new VehicleRoute(route);
}
/**
* Returns a newInstance of {@link VehicleRoute}.
*
* @param tour
* @param driver
* @param vehicle
* @return
*/
public static VehicleRoute newInstance(TourActivities tour, Driver driver, Vehicle vehicle) {
return new VehicleRoute(tour,driver,vehicle);
}
/**
* Returns an empty route.
*
* <p>An empty route has an empty list of tour-activities, no driver (DriverImpl.noDriver()) and no vehicle (VehicleImpl.createNoVehicle()).
*
* @return
*/
public static VehicleRoute emptyRoute() {
return new VehicleRoute(TourActivities.emptyTour(), DriverImpl.noDriver(), VehicleImpl.createNoVehicle());
}
/**
* Builder that builds the vehicle route.
*
* @author stefan
*
*/
public static class Builder {
/**
* Returns new instance of this builder.
*
* @param vehicle
* @param driver
* @return this builder
*/
public static Builder newInstance(Vehicle vehicle, Driver driver){
return new Builder(vehicle,driver);
}
@ -73,10 +116,24 @@ public class VehicleRoute {
private Set<Shipment> openShipments = new HashSet<Shipment>();
/**
* Sets the serviceActivityFactory to create serviceActivities.
*
* <p>By default {@link DefaultTourActivityFactory} is used.
*
* @param serviceActivityFactory
*/
public void setServiceActivityFactory(TourActivityFactory serviceActivityFactory) {
this.serviceActivityFactory = serviceActivityFactory;
}
/**
* Sets the shipmentActivityFactory to create shipmentActivities.
*
* <p>By default {@link DefaultShipmentActivityFactory} is used.
*
* @param shipmentActivityFactory
*/
public void setShipmentActivityFactory(TourShipmentActivityFactory shipmentActivityFactory) {
this.shipmentActivityFactory = shipmentActivityFactory;
}
@ -100,7 +157,7 @@ public class VehicleRoute {
}
/**
* Sets the departure-time of the route.
* Sets the departure-time of the route, i.e. which is the time the vehicle departs from start-location.
*
* @param departureTime
* @return
@ -110,16 +167,46 @@ public class VehicleRoute {
return this;
}
/**
* Sets the end-time of the route, i.e. which is the time the vehicle has to be at its end-location at latest.
*
* @param endTime
* @return this builder
*/
public Builder setRouteEndArrivalTime(double endTime){
end.setArrTime(endTime);
return this;
}
/**
* Adds a service to this route.
*
* <p>This implies that for this service a serviceActivity is created with {@link TourActivityFactory} and added to the sequence of tourActivities.
*
* <p>The resulting activity occurs in the activity-sequence in the order adding/inserting.
*
* @param service
* @return this builder
* @throws IllegalArgumentException if service is null
*/
public Builder addService(Service service){
if(service == null) throw new IllegalArgumentException("service must not be null");
addService(service,0.0,0.0);
return this;
}
/**
* Adds a service with specified activity arrival- and endTime.
*
* <p>This implies that for this service a serviceActivity is created with {@link TourActivityFactory} and added to the sequence of tourActivities.
*
* <p>Basically this activity is then scheduled with an activity arrival and activity endTime.
*
* @param service
* @param arrTime
* @param endTime
* @return builder
*/
public Builder addService(Service service, double arrTime, double endTime){
TourActivity act = serviceActivityFactory.createActivity(service);
act.setArrTime(arrTime);
@ -266,15 +353,38 @@ public class VehicleRoute {
return tourActivities;
}
/**
* Returns the vehicle operating this route.
*
* @return Vehicle
*/
public Vehicle getVehicle() {
return vehicle;
}
/**
* Returns the driver operating this route.
*
* @return Driver
*/
public Driver getDriver() {
return driver;
}
/**
* Sets the vehicle and its departureTime.
*
* <p>This implies the following:<br>
* if start and end are null, new start and end activities are created.<br>
* <p>startActivity is initialized with the location of the specified vehicle. the time-window of this activity is initialized
* as follows: [time-window.start = vehicle.getEarliestDeparture()][time-window.end = vehicle.getLatestArrival()]
* <p>endActivity is initialized with the location of the specified vehicle as well. time-window of this activity:[time-window.start = vehicle.getEarliestDeparture()][time-window.end = vehicle.getLatestArrival()]
* <p>start.endTime is set to the specified departureTime
* <p>Note that start end end-locations are always initialized with the location of the specified vehicle. (this will change soon, then there will be start and end location of vehicle which can be different, 23.01.14)
*
* @param vehicle
* @param vehicleDepTime
*/
public void setVehicle(Vehicle vehicle, double vehicleDepTime){
this.vehicle = vehicle;
setStartAndEnd(vehicle, vehicleDepTime);
@ -297,24 +407,50 @@ public class VehicleRoute {
}
/**
* Sets departureTime of this route, i.e. the time the vehicle departs from its start-location.
*
* @param vehicleDepTime
*/
public void setDepartureTime(double vehicleDepTime){
if(start == null) throw new IllegalStateException("cannot set departureTime without having a vehicle on this route. use setVehicle(vehicle,departureTime) instead.");
start.setEndTime(vehicleDepTime);
}
/**
* Returns the departureTime of this vehicle.
*
* @return departureTime
* @throws IllegalStateException if start is null
*/
public double getDepartureTime(){
if(start == null) throw new IllegalStateException("cannot get departureTime without having a vehicle on this route. use setVehicle(vehicle,departureTime) instead.");
return start.getEndTime();
}
/**
* Returns tour if tour-activity-sequence is empty, i.e. to activity on the tour yet.
*
* @return
*/
public boolean isEmpty() {
return tourActivities.isEmpty();
}
/**
* Returns start-activity of this route.
*
* @return start
*/
public Start getStart() {
return start;
}
/**
* Returns end-activity of this route.
*
* @return end
*/
public End getEnd() {
return end;
}

View file

@ -17,6 +17,7 @@
package jsprit.core.problem.solution.route.activity;
/**
* TimeWindow consists of a startTime and endTime.
*
* @author stefan schroeder
*
@ -24,6 +25,14 @@ package jsprit.core.problem.solution.route.activity;
public class TimeWindow {
/**
* Returns new instance of TimeWindow.
*
* @param start
* @param end
* @return TimeWindow
* @throw IllegalArgumentException either if start or end < 0.0 or end < start
*/
public static TimeWindow newInstance(double start, double end){
return new TimeWindow(start,end);
}
@ -31,16 +40,35 @@ public class TimeWindow {
private final double start;
private final double end;
/**
* Constructs the timeWindow
*
* @param start
* @param end
* @throw IllegalArgumentException either if start or end < 0.0 or end < start
*/
public TimeWindow(double start, double end) {
super();
if(start < 0.0 || end < 0.0) throw new IllegalArgumentException("neither start nor end must be < 0.0");
if(end < start) throw new IllegalArgumentException("end cannot be smaller than start");
this.start = start;
this.end = end;
}
/**
* Returns startTime of TimeWindow.
*
* @return startTime
*/
public double getStart() {
return start;
}
/**
* Returns endTime of TimeWindow.
*
* @return endTime
*/
public double getEnd() {
return end;
}
@ -62,6 +90,9 @@ public class TimeWindow {
return result;
}
/**
* Two timeWindows are equal if they have the same start AND endTime.
*/
@Override
public boolean equals(Object obj) {
if (this == obj)

View file

@ -0,0 +1,178 @@
/*******************************************************************************
* Copyright (C) 2013 Stefan Schroeder
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
package jsprit.core.reporting;
import jsprit.core.problem.VehicleRoutingProblem;
import jsprit.core.problem.job.Job;
import jsprit.core.problem.job.Service;
import jsprit.core.problem.job.Shipment;
import jsprit.core.problem.solution.VehicleRoutingProblemSolution;
import jsprit.core.problem.solution.route.VehicleRoute;
import jsprit.core.problem.solution.route.activity.TourActivity;
import jsprit.core.problem.solution.route.activity.TourActivity.JobActivity;
/**
* Printer to print the details of a vehicle-routing-problem solution.
*
* @author stefan schroeder
*
*/
public class SolutionPrinter {
/**
* Enum to indicate verbose-level.
*
* <p> Print.CONCISE and Print.VERBOSE are available.
*
* @author stefan schroeder
*
*/
public enum Print {
CONCISE,VERBOSE
}
/**
* Prints costs and #vehicles to stdout (System.out.println).
*
* @param solution
*/
public static void print(VehicleRoutingProblemSolution solution){
System.out.println("[costs="+solution.getCost() + "]");
System.out.println("[#vehicles="+solution.getRoutes().size() + "]");
}
private static class Jobs {
int nServices;
int nShipments;
public Jobs(int nServices, int nShipments) {
super();
this.nServices = nServices;
this.nShipments = nShipments;
}
}
public static void print(VehicleRoutingProblem problem, VehicleRoutingProblemSolution solution, Print print){
String leftAlign = "| %-13s | %-8s | %n";
System.out.format("+--------------------------+%n");
System.out.printf("| problem |%n");
System.out.format("+---------------+----------+%n");
System.out.printf("| indicator | value |%n");
System.out.format("+---------------+----------+%n");
System.out.format(leftAlign, "nJobs", problem.getJobs().values().size());
Jobs jobs = getNuOfJobs(problem);
System.out.format(leftAlign, "nServices",jobs.nServices);
System.out.format(leftAlign, "nShipments",jobs.nShipments);
System.out.format(leftAlign, "fleetsize",problem.getFleetSize().toString());
System.out.format("+--------------------------+%n");
String leftAlignSolution = "| %-13s | %-40s | %n";
System.out.format("+----------------------------------------------------------+%n");
System.out.printf("| solution |%n");
System.out.format("+---------------+------------------------------------------+%n");
System.out.printf("| indicator | value |%n");
System.out.format("+---------------+------------------------------------------+%n");
System.out.format(leftAlignSolution, "costs",solution.getCost());
System.out.format(leftAlignSolution, "nVehicles",solution.getRoutes().size());
System.out.format("+----------------------------------------------------------+%n");
if(print.equals(Print.VERBOSE)){
printVerbose(problem,solution);
}
}
private static void printVerbose(VehicleRoutingProblem problem, VehicleRoutingProblemSolution solution) {
String leftAlgin = "| %-7s | %-20s | %-21s | %-15s | %-15s | %-15s | %-15s |%n";
System.out.format("+--------------------------------------------------------------------------------------------------------------------------------+%n");
System.out.printf("| detailed solution |%n");
System.out.format("+---------+----------------------+-----------------------+-----------------+-----------------+-----------------+-----------------+%n");
System.out.printf("| route | vehicle | activity | job | arrTime | endTime | costs |%n");
int routeNu = 1;
for(VehicleRoute route : solution.getRoutes()){
System.out.format("+---------+----------------------+-----------------------+-----------------+-----------------+-----------------+-----------------+%n");
double costs = 0;
System.out.format(leftAlgin, routeNu, route.getVehicle().getId(), route.getStart().getName(), "-", "undef", Math.round(route.getStart().getEndTime()),Math.round(costs));
TourActivity prevAct = route.getStart();
for(TourActivity act : route.getActivities()){
String jobId;
if(act instanceof JobActivity) jobId = ((JobActivity)act).getJob().getId();
else jobId = "-";
double c = problem.getTransportCosts().getTransportCost(prevAct.getLocationId(), act.getLocationId(), prevAct.getEndTime(), route.getDriver(), route.getVehicle());
c+= problem.getActivityCosts().getActivityCost(act, act.getArrTime(), route.getDriver(), route.getVehicle());
costs+=c;
System.out.format(leftAlgin, routeNu, route.getVehicle().getId(), act.getName(), jobId, Math.round(act.getArrTime()), Math.round(act.getEndTime()),Math.round(costs));
prevAct=act;
}
double c = problem.getTransportCosts().getTransportCost(prevAct.getLocationId(), route.getEnd().getLocationId(), prevAct.getEndTime(), route.getDriver(), route.getVehicle());
c+= problem.getActivityCosts().getActivityCost(route.getEnd(), route.getEnd().getArrTime(), route.getDriver(), route.getVehicle());
costs+=c;
System.out.format(leftAlgin, routeNu, route.getVehicle().getId(), route.getEnd().getName(), "-", Math.round(route.getEnd().getArrTime()), "undef", Math.round(costs));
routeNu++;
}
System.out.format("+--------------------------------------------------------------------------------------------------------------------------------+%n");
}
private static Jobs getNuOfJobs(VehicleRoutingProblem problem) {
int nShipments = 0;
int nServices = 0;
for(Job j : problem.getJobs().values()){
if(j instanceof Shipment) nShipments++;
if(j instanceof Service) nServices++;
}
return new Jobs(nServices,nShipments);
}
// /**
// * Prints the details of the solution according to a print-level, i.e. Print.CONCISE or PRINT.VERBOSE.
// *
// * <p>CONCISE prints total-costs and #vehicles.
// * <p>VERBOSE prints the route-details additionally. If the DefaultVehicleRouteCostCalculator (which is the standard-calculator)
// * is used in VehicleRoute, then route-costs are differentiated further between transport, activity, vehicle, driver and other-costs.
// *
// * @param solution
// * @param level
// *
// * @deprecated is not going to work anymore
// */
// @Deprecated
// public static void print(VehicleRoutingProblemSolution solution, Print level){
// if(level.equals(Print.CONCISE)){
// print(solution);
// }
// else{
// print(solution);
// System.out.println("routes");
// int routeCount = 1;
// for(VehicleRoute route : solution.getRoutes()){
// System.out.println("[route="+routeCount+"][departureTime="+route.getStart().getEndTime()+"[total=" + route.getCost() + "]");
// if(route.getVehicleRouteCostCalculator() instanceof DefaultVehicleRouteCostCalculator){
// DefaultVehicleRouteCostCalculator defaultCalc = (DefaultVehicleRouteCostCalculator) route.getVehicleRouteCostCalculator();
// System.out.println("[transport=" + defaultCalc.getTpCosts() + "][activity=" + defaultCalc.getActCosts() +
// "][vehicle=" + defaultCalc.getVehicleCosts() + "][driver=" + defaultCalc.getDriverCosts() + "][other=" + defaultCalc.getOther() + "]");
// }
// routeCount++;
// }
// }
//
//
// }
}

View file

@ -40,7 +40,7 @@
<xs:element name="location">
<xs:complexType>
<xs:all>
<xs:element name="id" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:element name="id" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="coord" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="x" type="xs:decimal" use="required"/>
@ -95,7 +95,7 @@
<xs:element name="service" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:all>
<xs:element name="locationId" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:element name="locationId" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="coord" type="coordType" minOccurs="0" maxOccurs="1"/>
<xs:element name="capacity-demand" type="xs:integer" minOccurs="0" maxOccurs="1" default="0"/>
<xs:element name="duration" type="xs:decimal" minOccurs="0" maxOccurs="1" default="0.0"/>
@ -125,7 +125,7 @@
<xs:element name="pickup" minOccurs="1" maxOccurs="1">
<xs:complexType>
<xs:all>
<xs:element name="locationId" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:element name="locationId" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="coord" type="coordType" minOccurs="0" maxOccurs="1"/>
<xs:element name="duration" type="xs:decimal" minOccurs="0" maxOccurs="1" default="0.0"/>
<xs:element name="timeWindows" minOccurs="0" maxOccurs="1">
@ -141,7 +141,7 @@
<xs:element name="delivery" minOccurs="1" maxOccurs="1">
<xs:complexType>
<xs:all>
<xs:element name="locationId" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:element name="locationId" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="coord" type="coordType" minOccurs="0" maxOccurs="1"/>
<xs:element name="duration" type="xs:decimal" minOccurs="0" maxOccurs="1" default="0.0"/>
<xs:element name="timeWindows" minOccurs="0" maxOccurs="1">