mirror of
https://github.com/graphhopper/jsprit.git
synced 2020-01-24 07:45:05 +01:00
javadoc for CustomJob + some visibility change to make the API more compact
This commit is contained in:
parent
bb35142a8f
commit
89570ad2e5
9 changed files with 438 additions and 92 deletions
|
|
@ -47,7 +47,7 @@ public class GraphStreamViewerTest {
|
|||
Vehicle vehicle = VehicleImpl.Builder.newInstance("vehicle").setType(type).setBreak(Break.Builder.newInstance("myBreak").addTimeWindow(5, 10).build())
|
||||
.setStartLocation(Location.newInstance(0, 0))
|
||||
.build();
|
||||
CustomJob cj = CustomJob.Builder.newInstance("job")
|
||||
CustomJob cj = new CustomJob.Builder("job")
|
||||
.addPickup(Location.newInstance(10, 0), SizeDimension.Builder.newInstance().addDimension(0, 1).build())
|
||||
.addPickup(Location.newInstance(5, 0), SizeDimension.Builder.newInstance().addDimension(0, 2).build())
|
||||
.addDelivery(Location.newInstance(20, 0), SizeDimension.Builder.newInstance().addDimension(0, 3).build())
|
||||
|
|
@ -63,7 +63,7 @@ public class GraphStreamViewerTest {
|
|||
VehicleType type = VehicleTypeImpl.Builder.newInstance("type").addCapacityDimension(0, 3).build();
|
||||
Vehicle vehicle = VehicleImpl.Builder.newInstance("vehicle").setStartLocation(Location.newInstance(0, 0))
|
||||
.setType(type).build();
|
||||
CustomJob cj = CustomJob.Builder.newInstance("job")
|
||||
CustomJob cj = new CustomJob.Builder("job")
|
||||
.addPickup(Location.newInstance(10, 0), SizeDimension.Builder.newInstance().addDimension(0, 1).build())
|
||||
.addPickup(Location.newInstance(-5, 4), SizeDimension.Builder.newInstance().addDimension(0, 2).build())
|
||||
.addDelivery(Location.newInstance(20, 10), SizeDimension.Builder.newInstance().addDimension(0, 3).build())
|
||||
|
|
@ -78,7 +78,7 @@ public class GraphStreamViewerTest {
|
|||
VehicleType type = VehicleTypeImpl.Builder.newInstance("type").addCapacityDimension(0, 3).addCapacityDimension(1, 3).build();
|
||||
Vehicle vehicle = VehicleImpl.Builder.newInstance("vehicle").setStartLocation(Location.newInstance(0, 0))
|
||||
.setType(type).build();
|
||||
CustomJob cj = CustomJob.Builder.newInstance("job")
|
||||
CustomJob cj = new CustomJob.Builder("job")
|
||||
.addPickup(Location.newInstance(10, 0), SizeDimension.Builder.newInstance().addDimension(0, 1).addDimension(1, 1).build())
|
||||
.addExchange(Location.newInstance(-5, 4), SizeDimension.Builder.newInstance().addDimension(0, -1).addDimension(1, 1).build())
|
||||
.addDelivery(Location.newInstance(20, 10), SizeDimension.Builder.newInstance().addDimension(0, 3).build())
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ public class PlotterTest {
|
|||
|
||||
Vehicle vehicle = VehicleImpl.Builder.newInstance("vehicle").setStartLocation(Location.newInstance(0, 0))
|
||||
.build();
|
||||
CustomJob cj = CustomJob.Builder.newInstance("job")
|
||||
CustomJob cj = new CustomJob.Builder("job")
|
||||
.addPickup(Location.newInstance(10, 0), SizeDimension.Builder.newInstance().addDimension(0, 1).build())
|
||||
.addPickup(Location.newInstance(5, 0), SizeDimension.Builder.newInstance().addDimension(0, 2).build())
|
||||
.addDelivery(Location.newInstance(20, 00), SizeDimension.Builder.newInstance().addDimension(0, 3).build())
|
||||
|
|
@ -59,7 +59,7 @@ public class PlotterTest {
|
|||
VehicleType type = VehicleTypeImpl.Builder.newInstance("type").addCapacityDimension(0, 3).build();
|
||||
Vehicle vehicle = VehicleImpl.Builder.newInstance("vehicle").setStartLocation(Location.newInstance(0, 0))
|
||||
.setType(type).build();
|
||||
CustomJob cj = CustomJob.Builder.newInstance("job")
|
||||
CustomJob cj = new CustomJob.Builder("job")
|
||||
.addPickup(Location.newInstance(10, 0), SizeDimension.Builder.newInstance().addDimension(0, 1).build())
|
||||
.addPickup(Location.newInstance(-5, 4), SizeDimension.Builder.newInstance().addDimension(0, 2).build())
|
||||
.addDelivery(Location.newInstance(20, 10), SizeDimension.Builder.newInstance().addDimension(0, 3).build())
|
||||
|
|
@ -74,7 +74,7 @@ public class PlotterTest {
|
|||
VehicleType type = VehicleTypeImpl.Builder.newInstance("type").addCapacityDimension(0, 3).addCapacityDimension(1, 3).build();
|
||||
Vehicle vehicle = VehicleImpl.Builder.newInstance("vehicle").setStartLocation(Location.newInstance(0, 0))
|
||||
.setType(type).build();
|
||||
CustomJob cj = CustomJob.Builder.newInstance("job")
|
||||
CustomJob cj = new CustomJob.Builder("job")
|
||||
.addPickup(Location.newInstance(10, 0), SizeDimension.Builder.newInstance().addDimension(0, 1).addDimension(1, 1).build())
|
||||
.addExchange(Location.newInstance(-5, 4), SizeDimension.Builder.newInstance().addDimension(0, -1).addDimension(1, 1).build())
|
||||
.addDelivery(Location.newInstance(20, 10), SizeDimension.Builder.newInstance().addDimension(0, 3).build())
|
||||
|
|
|
|||
|
|
@ -54,44 +54,101 @@ import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindowsIm
|
|||
*/
|
||||
public class CustomJob extends AbstractJob {
|
||||
|
||||
/**
|
||||
* Protected base builder class for {@linkplain CustomJob}.
|
||||
* <p>
|
||||
* The class is the protected part of the inheritable builder pattern. For
|
||||
* more information, see {@linkplain AbstractJob.JobBuilder}.
|
||||
* </p>
|
||||
*
|
||||
* @author Balage
|
||||
*
|
||||
* @param <T>
|
||||
* The type of the job it creates.
|
||||
* @param <B>
|
||||
* Self-refering generic value.
|
||||
*/
|
||||
protected static abstract class BuilderBase<T extends CustomJob, B extends CustomJob.BuilderBase<T, B>>
|
||||
extends JobBuilder<T, B> {
|
||||
|
||||
/**
|
||||
* The possible activity types.
|
||||
*
|
||||
* <p>
|
||||
* Note, that the set of activity types are final.
|
||||
* </p>
|
||||
*
|
||||
* @author Balage
|
||||
*
|
||||
*/
|
||||
public enum ActivityType {
|
||||
/**
|
||||
* Service activity type.
|
||||
* <p>
|
||||
* The service activity type represents an activity with no cargo
|
||||
* change (nothing is loaded or unloaded).
|
||||
* </p>
|
||||
*/
|
||||
SERVICE {
|
||||
|
||||
@Override
|
||||
public JobActivity create(CustomJob job, BuilderActivityInfo info) {
|
||||
protected JobActivity create(CustomJob job, BuilderActivityInfo info) {
|
||||
return new ServiceActivity(job, info.getName() == null ? name().toLowerCase() : info.getName(),
|
||||
info.getLocation(), info.getOperationTime(), info.getSize(), prepareTimeWindows(info));
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Pickup activity type.
|
||||
* <p>
|
||||
* The pickup activity type represents an activity where something
|
||||
* is picked up (loaded). It has a positive impact on the cargo
|
||||
* size.
|
||||
* </p>
|
||||
*/
|
||||
PICKUP {
|
||||
|
||||
@Override
|
||||
public JobActivity create(CustomJob job, BuilderActivityInfo info) {
|
||||
protected JobActivity create(CustomJob job, BuilderActivityInfo info) {
|
||||
return new PickupActivity(job, info.getName() == null ? name().toLowerCase() : info.getName(),
|
||||
info.getLocation(), info.getOperationTime(), info.getSize(), prepareTimeWindows(info));
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Delivery activity type.
|
||||
* <p>
|
||||
* The delivery activity type represents an activity where something
|
||||
* is delivered (unloaded). It has a negative impact on the cargo
|
||||
* size.
|
||||
* </p>
|
||||
*/
|
||||
DELIVERY {
|
||||
|
||||
@Override
|
||||
public JobActivity create(CustomJob job, BuilderActivityInfo info) {
|
||||
protected JobActivity create(CustomJob job, BuilderActivityInfo info) {
|
||||
return new DeliveryActivity(job, info.getName() == null ? name().toLowerCase() : info.getName(),
|
||||
info.getLocation(), info.getOperationTime(), info.getSize(), prepareTimeWindows(info));
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Exchange activity type.
|
||||
* <p>
|
||||
* The exchange activity type represents an activity where something
|
||||
* is delivered and something else is picked up at the same time.
|
||||
* (loaded and unloaded). It has a mixed (may be even zero) impact
|
||||
* on the cargo size. It may increase one dimension and reduce
|
||||
* another one.
|
||||
* </p>
|
||||
*/
|
||||
EXCHANGE {
|
||||
|
||||
@Override
|
||||
public JobActivity create(CustomJob job, BuilderActivityInfo info) {
|
||||
protected JobActivity create(CustomJob job, BuilderActivityInfo info) {
|
||||
return new ExchangeActivity(job, info.getName() == null ? name().toLowerCase() : info.getName(),
|
||||
info.getLocation(), info.getOperationTime(), info.getSize(), prepareTimeWindows(info));
|
||||
}
|
||||
};
|
||||
|
||||
public abstract JobActivity create(CustomJob job, BuilderActivityInfo builderActivityInfo);
|
||||
protected abstract JobActivity create(CustomJob job, BuilderActivityInfo builderActivityInfo);
|
||||
|
||||
private static Collection<TimeWindow> prepareTimeWindows(BuilderActivityInfo info) {
|
||||
TimeWindows tws = info.getTimeWindows();
|
||||
|
|
@ -103,6 +160,18 @@ public class CustomJob extends AbstractJob {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Class for defining custom activities when the standard methods of
|
||||
* {@linkplain Builder} are not enough. The class applies the fluent API
|
||||
* pattern.
|
||||
* <p>
|
||||
* Note that this class is <b>NOT</b> immutable, so always create a new
|
||||
* instance for each activity!
|
||||
* </p>
|
||||
*
|
||||
* @author Balage
|
||||
*
|
||||
*/
|
||||
public static class BuilderActivityInfo {
|
||||
private ActivityType type;
|
||||
private Location locs;
|
||||
|
|
@ -112,69 +181,146 @@ public class CustomJob extends AbstractJob {
|
|||
private TimeWindowsImpl timeWindows = new TimeWindowsImpl();
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a new instance.
|
||||
*
|
||||
* @param type
|
||||
* The type of the activity.
|
||||
* @param locs
|
||||
* The location of the activity.
|
||||
*/
|
||||
public BuilderActivityInfo(ActivityType type, Location locs) {
|
||||
super();
|
||||
this.type = type;
|
||||
this.locs = locs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The type of the activity.
|
||||
*/
|
||||
public ActivityType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The location of the activity.
|
||||
*/
|
||||
public Location getLocation() {
|
||||
return locs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The size dimensions (cargo change) of the activity.
|
||||
*/
|
||||
public SizeDimension getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the size dimensions (cargo change) of the activity.
|
||||
*
|
||||
* @param size
|
||||
* The size dimensions. (May be negative.)
|
||||
* @return The info object.
|
||||
*/
|
||||
public BuilderActivityInfo withSize(SizeDimension size) {
|
||||
this.size = size;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The name of the activity (for debug and reporting).
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the activity for debugging and reporting
|
||||
* purpose.
|
||||
*
|
||||
* @param name
|
||||
* The name.
|
||||
* @return The info object.
|
||||
*/
|
||||
public BuilderActivityInfo withName(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The time windows of the activity.
|
||||
*/
|
||||
public TimeWindows getTimeWindows() {
|
||||
return timeWindows;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a time window to the activity.
|
||||
*
|
||||
* @param timeWindow
|
||||
* A time window.
|
||||
* @return The info object.
|
||||
*/
|
||||
public BuilderActivityInfo withTimeWindow(TimeWindow timeWindow) {
|
||||
timeWindows.add(timeWindow);
|
||||
return this;
|
||||
}
|
||||
|
||||
public BuilderActivityInfo withTimeWindows(TimeWindow... tws) {
|
||||
timeWindows.addAll(tws);
|
||||
/**
|
||||
* Adds several time windows to the activity.
|
||||
*
|
||||
* @param timeWindows
|
||||
* The list of time windows.
|
||||
* @return The info object.
|
||||
*/
|
||||
public BuilderActivityInfo withTimeWindows(TimeWindow... timeWindows) {
|
||||
this.timeWindows.addAll(timeWindows);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds several time windows.
|
||||
*
|
||||
* @param tws
|
||||
* The collection of time windows.
|
||||
* @return The info object.
|
||||
*/
|
||||
public BuilderActivityInfo withTimeWindows(Collection<TimeWindow> tws) {
|
||||
timeWindows.addAll(tws);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The operation time (time taken to fulfill the activity at
|
||||
* the location) of the activity.
|
||||
*/
|
||||
public double getOperationTime() {
|
||||
return operationTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the operation time (time taken to fulfill the activity at
|
||||
* the location).
|
||||
*
|
||||
* @param operationTime
|
||||
* The operation time.
|
||||
* @return The info object.
|
||||
*/
|
||||
public BuilderActivityInfo withOperationTime(double operationTime) {
|
||||
this.operationTime = operationTime;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
List<BuilderActivityInfo> acts = new ArrayList<>();
|
||||
private List<BuilderActivityInfo> acts = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param id
|
||||
* The id of the job. Should be unique within the problem.
|
||||
*/
|
||||
public BuilderBase(String id) {
|
||||
super(id);
|
||||
}
|
||||
|
|
@ -186,8 +332,28 @@ public class CustomJob extends AbstractJob {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* General activity add method.
|
||||
* <p>
|
||||
* It constructs a {@linkplain BuilderActivityInfo} objects and calls
|
||||
* the {@linkplain #addActivity(BuilderActivityInfo)} function.
|
||||
* </p>
|
||||
*
|
||||
* @param type
|
||||
* The type of the activity.
|
||||
* @param location
|
||||
* The location of the activity.
|
||||
* @param operationTime
|
||||
* The operation time of the activity.
|
||||
* @param size
|
||||
* The cargo change of the activity. May be null.
|
||||
* @param name
|
||||
* The name of the activity. May be null.
|
||||
* @param timeWindows
|
||||
* The time windows of the activity. May be null.
|
||||
*/
|
||||
private void add(ActivityType type, Location location, double operationTime, SizeDimension size, String name,
|
||||
Collection<TimeWindow> tws) {
|
||||
Collection<TimeWindow> timeWindows) {
|
||||
BuilderActivityInfo builderActivityInfo = new BuilderActivityInfo(type, location);
|
||||
builderActivityInfo.withOperationTime(operationTime);
|
||||
if (name != null) {
|
||||
|
|
@ -196,8 +362,8 @@ public class CustomJob extends AbstractJob {
|
|||
if (size != null) {
|
||||
builderActivityInfo.withSize(size);
|
||||
}
|
||||
if (tws != null) {
|
||||
builderActivityInfo.withTimeWindows(tws);
|
||||
if (timeWindows != null) {
|
||||
builderActivityInfo.withTimeWindows(timeWindows);
|
||||
}
|
||||
|
||||
acts.add(builderActivityInfo);
|
||||
|
|
@ -205,79 +371,191 @@ public class CustomJob extends AbstractJob {
|
|||
|
||||
// Service
|
||||
|
||||
/**
|
||||
* Adds a {@linkplain ActivityType#SERVICE} activity to the job with 0
|
||||
* operation time, without time windows and name.
|
||||
*
|
||||
* @param location
|
||||
* The location of the activity.
|
||||
* @return The builder instance.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public B addService(Location location) {
|
||||
add(ActivityType.SERVICE, location, 0d, null, null, null);
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds a {@linkplain ActivityType#SERVICE} activity to the job without
|
||||
* time windows and name.
|
||||
*
|
||||
* @param location
|
||||
* The location of the activity.
|
||||
* @param operationTime
|
||||
* The operation time of the activity.
|
||||
* @return The builder instance.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public B addService(Location location, SizeDimension size) {
|
||||
add(ActivityType.SERVICE, location, 0d, size, null, null);
|
||||
public B addService(Location location, double operationTime) {
|
||||
add(ActivityType.SERVICE, location, operationTime, null, null, null);
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a {@linkplain ActivityType#SERVICE} activity to the job without
|
||||
* name and with a single time window.
|
||||
*
|
||||
* @param location
|
||||
* The location of the activity.
|
||||
* @param operationTime
|
||||
* The operation time of the activity.
|
||||
* @param timeWindow
|
||||
* The time window of the activity.
|
||||
* @return The builder instance.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public B addService(Location location, SizeDimension size, double operationTime) {
|
||||
add(ActivityType.SERVICE, location, operationTime, size, null, null);
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public B addService(Location location, SizeDimension size, double operationTime,
|
||||
TimeWindow tw) {
|
||||
add(ActivityType.SERVICE, location, operationTime, size, null, Collections.singleton(tw));
|
||||
public B addService(Location location, double operationTime, TimeWindow timeWindow) {
|
||||
add(ActivityType.SERVICE, location, operationTime, null, null, Collections.singleton(timeWindow));
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
|
||||
// Pickup
|
||||
|
||||
/**
|
||||
* Adds a {@linkplain ActivityType#PICKUP} activity to the job with 0
|
||||
* operation time, without cargo change, time windows and name.
|
||||
*
|
||||
* @param location
|
||||
* The location of the activity.
|
||||
* @return The builder instance.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public B addPickup(Location location) {
|
||||
add(ActivityType.PICKUP, location, 0d, null, null, null);
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a {@linkplain ActivityType#PICKUP} activity to the job with 0
|
||||
* operation time, without time windows and name.
|
||||
*
|
||||
* @param location
|
||||
* The location of the activity.
|
||||
* @param size
|
||||
* The cargo change of the pickup. Should be positive.
|
||||
* @return The builder instance.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public B addPickup(Location location, SizeDimension size) {
|
||||
add(ActivityType.PICKUP, location, 0d, size, null, null);
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a {@linkplain ActivityType#PICKUP} activity to the job without
|
||||
* time windows and name.
|
||||
*
|
||||
* @param location
|
||||
* The location of the activity.
|
||||
* @param size
|
||||
* The cargo change of the pickup. Should be positive.
|
||||
* @param operationTime
|
||||
* The operation time of the activity.
|
||||
* @return The builder instance.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public B addPickup(Location location, SizeDimension size, double operationTime) {
|
||||
add(ActivityType.PICKUP, location, operationTime, size, null, null);
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a {@linkplain ActivityType#PICKUP} activity to the job without
|
||||
* name and with a single time window.
|
||||
*
|
||||
* @param location
|
||||
* The location of the activity.
|
||||
* @param size
|
||||
* The cargo change of the pickup. Should be positive.
|
||||
* @param operationTime
|
||||
* The operation time of the activity.
|
||||
* @param timeWindow
|
||||
* The time window of the activity.
|
||||
* @return The builder instance.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public B addPickup(Location location, SizeDimension size, double operationTime,
|
||||
TimeWindow tw) {
|
||||
add(ActivityType.PICKUP, location, operationTime, size, null, Collections.singleton(tw));
|
||||
TimeWindow timeWindow) {
|
||||
add(ActivityType.PICKUP, location, operationTime, size, null, Collections.singleton(timeWindow));
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
// Delivery
|
||||
|
||||
/**
|
||||
* Adds a {@linkplain ActivityType#DELIVERY} activity to the job with 0
|
||||
* operation time, without cargo change, time windows and name.
|
||||
*
|
||||
* @param location
|
||||
* The location of the activity.
|
||||
* @return The builder instance.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public B addDelivery(Location location) {
|
||||
add(ActivityType.DELIVERY, location, 0d, null, null, null);
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a {@linkplain ActivityType#DELIVERY} activity to the job with 0
|
||||
* operation time, without time windows and name.
|
||||
*
|
||||
* @param location
|
||||
* The location of the activity.
|
||||
* @param size
|
||||
* The cargo change of the delivery. Should be negative.
|
||||
* @return The builder instance.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public B addDelivery(Location location, SizeDimension size) {
|
||||
add(ActivityType.DELIVERY, location, 0d, size, null, null);
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a {@linkplain ActivityType#DELIVERY} activity to the job without
|
||||
* time windows and name.
|
||||
*
|
||||
* @param location
|
||||
* The location of the activity.
|
||||
* @param size
|
||||
* The cargo change of the delivery. Should be negative.
|
||||
* @param operationTime
|
||||
* The operation time of the activity.
|
||||
* @return The builder instance.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public B addDelivery(Location location, SizeDimension size, double operationTime) {
|
||||
add(ActivityType.DELIVERY, location, operationTime, size, null, null);
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a {@linkplain ActivityType#DELIVERY} activity to the job without
|
||||
* name and with a single time window.
|
||||
*
|
||||
* @param location
|
||||
* The location of the activity.
|
||||
* @param size
|
||||
* The cargo change of the delivery. Should be negative.
|
||||
* @param operationTime
|
||||
* The operation time of the activity.
|
||||
* @param timeWindow
|
||||
* The time window of the activity.
|
||||
* @return The builder instance.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public B addDelivery(Location location, SizeDimension size, double operationTime,
|
||||
TimeWindow tw) {
|
||||
|
|
@ -287,24 +565,71 @@ public class CustomJob extends AbstractJob {
|
|||
|
||||
// Exchange
|
||||
|
||||
/**
|
||||
* Adds a {@linkplain ActivityType#EXCHANGE} activity to the job with 0
|
||||
* operation time, without cargo change, time windows and name.
|
||||
*
|
||||
* @param location
|
||||
* The location of the activity.
|
||||
* @return The builder instance.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public B addExchange(Location location) {
|
||||
add(ActivityType.EXCHANGE, location, 0d, null, null, null);
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a {@linkplain ActivityType#EXCHANGE} activity to the job with 0
|
||||
* operation time, without time windows and name.
|
||||
*
|
||||
* @param location
|
||||
* The location of the activity.
|
||||
* @param size
|
||||
* The cargo change of the exchange. May be negative,
|
||||
* positive or mixed.
|
||||
* @return The builder instance.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public B addExchange(Location location, SizeDimension size) {
|
||||
add(ActivityType.EXCHANGE, location, 0d, size, null, null);
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a {@linkplain ActivityType#EXCHANGE} activity to the job without
|
||||
* time windows and name.
|
||||
*
|
||||
* @param location
|
||||
* The location of the activity.
|
||||
* @param size
|
||||
* The cargo change of the exchange. May be negative,
|
||||
* positive or mixed.
|
||||
* @param operationTime
|
||||
* The operation time of the activity.
|
||||
* @return The builder instance.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public B addExchange(Location location, SizeDimension size, double operationTime) {
|
||||
add(ActivityType.EXCHANGE, location, operationTime, size, null, null);
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a {@linkplain ActivityType#EXCHANGE} activity to the job without
|
||||
* name and with a single time window.
|
||||
*
|
||||
* @param location
|
||||
* The location of the activity.
|
||||
* @param size
|
||||
* The cargo change of the exchange. May be negative,
|
||||
* positive or mixed.
|
||||
* @param operationTime
|
||||
* The operation time of the activity.
|
||||
* @param timeWindow
|
||||
* The time window of the activity.
|
||||
* @return The builder instance.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public B addExchange(Location location, SizeDimension size, double operationTime,
|
||||
TimeWindow tw) {
|
||||
|
|
@ -318,7 +643,7 @@ public class CustomJob extends AbstractJob {
|
|||
throw new IllegalStateException("There is no activities defined on this job.");
|
||||
}
|
||||
|
||||
public List<BuilderActivityInfo> getActs() {
|
||||
public List<BuilderActivityInfo> getActivities() {
|
||||
return Collections.unmodifiableList(acts);
|
||||
}
|
||||
|
||||
|
|
@ -334,20 +659,53 @@ public class CustomJob extends AbstractJob {
|
|||
* included into the solution.
|
||||
* </p>
|
||||
* <p>
|
||||
* The builder contains methods for simply configuring basic activities. If
|
||||
* more control needed on the activity creation, an ActivityBuild
|
||||
* The main difference between the jobs and activities known from version 1
|
||||
* and 2 is the bias shift from job to activity. Before version 2 the jobs
|
||||
* has holden most of the business information and activities were
|
||||
* second-class entities, meanwhile the algorithm worked on activities. This
|
||||
* has driven to a state where the code had no indication which job field
|
||||
* belonged to which activities.
|
||||
* </p>
|
||||
* <p>
|
||||
* In the new concept a stronger encapsulation ensures the right behavior.
|
||||
* This led to most of the business data to move from job to activity. These
|
||||
* are:
|
||||
* <ul>
|
||||
* <li>Load change (how the cargo size change (increase or decrease) on the
|
||||
* vehicle)</li>
|
||||
* <li>Location (where the activity should be executed)</li>
|
||||
* <li>Time windows (when the activity should be performed)</li>
|
||||
* <li>Operation time (how much time it takes to fulfill the activity)</li>
|
||||
* </ul>
|
||||
* These parameters are now defined per activity.
|
||||
* </p>
|
||||
* <p>
|
||||
* Some information has left in the scope of the job, because they affects
|
||||
* the whole job:
|
||||
* <ul>
|
||||
* <li>Required skills</li>
|
||||
* <li>Priority</li>
|
||||
* </ul>
|
||||
* </p>
|
||||
* <p>
|
||||
* The builder contains methods for simply configuring basic activities.
|
||||
* They are the counterparts of the version 1 job builders. If more control
|
||||
* is needed on the activity creation, an {@linkplain BuilderActivityInfo}
|
||||
* record has to be created and passed to the builder. (<i>This indirection
|
||||
* is required to keep immutable behavior of a job and its activities after
|
||||
* creation.</i>)
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @author Balage
|
||||
*
|
||||
*/
|
||||
public static final class Builder extends CustomJob.BuilderBase<CustomJob, CustomJob.Builder> {
|
||||
|
||||
public static CustomJob.Builder newInstance(String id) {
|
||||
return new CustomJob.Builder(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param id
|
||||
* The id of the job. Should be unique within a problem.
|
||||
*/
|
||||
public Builder(String id) {
|
||||
super(id);
|
||||
}
|
||||
|
|
@ -379,7 +737,7 @@ public class CustomJob extends AbstractJob {
|
|||
protected void createActivities(JobBuilder<? extends AbstractJob, ?> jobBuilder) {
|
||||
CustomJob.Builder builder = (CustomJob.Builder) jobBuilder;
|
||||
JobActivityList list = new SequentialJobActivityList(this);
|
||||
for (CustomJob.Builder.BuilderActivityInfo info : builder.getActs()) {
|
||||
for (CustomJob.Builder.BuilderActivityInfo info : builder.getActivities()) {
|
||||
JobActivity act = info.getType().create(this, info);
|
||||
list.addActivity(act);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,14 +54,10 @@ import com.graphhopper.jsprit.core.util.Coordinate;
|
|||
*
|
||||
* <ul>
|
||||
* <li>{@linkplain CustomJob.Builder#addService(Location)}</li>
|
||||
* <li>
|
||||
* {@linkplain CustomJob.Builder#addService(Location, SizeDimension)}
|
||||
* <li>{@linkplain CustomJob.Builder#addService(Location, double)}
|
||||
* </li>
|
||||
* <li>
|
||||
* {@linkplain CustomJob.Builder#addService(Location, SizeDimension, double)}
|
||||
* </li>
|
||||
* <li>
|
||||
* {@linkplain CustomJob.Builder#addService(Location, SizeDimension, double, TimeWindow)}
|
||||
* {@linkplain CustomJob.Builder#addService(Location, double, TimeWindow)}
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@
|
|||
*/
|
||||
package com.graphhopper.jsprit.core.problem.job;
|
||||
|
||||
import com.graphhopper.jsprit.core.problem.SizeDimension;
|
||||
import com.graphhopper.jsprit.core.problem.solution.route.activity.ServiceActivity;
|
||||
import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow;
|
||||
|
||||
|
|
@ -35,9 +34,8 @@ import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow;
|
|||
* @author Balage
|
||||
*
|
||||
* @see {@linkplain CustomJob.BuilderBase#addService(Location)}
|
||||
* @see {@linkplain CustomJob.BuilderBase#addService(Location, SizeDimension)}
|
||||
* @see {@linkplain CustomJob.BuilderBase#addService(Location, SizeDimension, double)}
|
||||
* @see {@linkplain CustomJob.BuilderBase#addService(Location, SizeDimension, double, TimeWindow)}
|
||||
* @see {@linkplain CustomJob.BuilderBase#addService(Location, double)}
|
||||
* @see {@linkplain CustomJob.BuilderBase#addService(Location, double, TimeWindow)}
|
||||
*/
|
||||
public class ServiceJob extends AbstractSingleActivityJob<ServiceActivity> {
|
||||
|
||||
|
|
|
|||
|
|
@ -76,13 +76,7 @@ import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindowsIm
|
|||
* <ul>
|
||||
* <li>{@linkplain CustomJob.Builder#addService(Location)}</li>
|
||||
* <li>
|
||||
* {@linkplain CustomJob.Builder#addService(Location, SizeDimension)}
|
||||
* </li>
|
||||
* <li>
|
||||
* {@linkplain CustomJob.Builder#addService(Location, SizeDimension, double)}
|
||||
* </li>
|
||||
* <li>
|
||||
* {@linkplain CustomJob.Builder#addService(Location, SizeDimension, double, TimeWindow)}
|
||||
* {@linkplain CustomJob.Builder#addService(Location, double, TimeWindow)}
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
|
|
|
|||
|
|
@ -39,11 +39,11 @@ public class FirstCustomJobExample {
|
|||
|
||||
@Test
|
||||
public void test() {
|
||||
CustomJob cj = CustomJob.Builder.newInstance("job")
|
||||
.addPickup(Location.newInstance(10, 0), SizeDimension.EMPTY).build();
|
||||
CustomJob cj = new CustomJob.Builder("job")
|
||||
.addPickup(Location.newInstance(10, 0), SizeDimension.EMPTY).build();
|
||||
Vehicle v = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance(0, 0)).build();
|
||||
VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance()
|
||||
.addJob(cj).addVehicle(v).build();
|
||||
.addJob(cj).addVehicle(v).build();
|
||||
VehicleRoutingAlgorithm vra = Jsprit.createAlgorithm(vrp);
|
||||
VehicleRoutingProblemSolution solution = Solutions.bestOf(vra.searchSolutions());
|
||||
SolutionPrinter.print(vrp, solution, SolutionPrinter.Print.VERBOSE);
|
||||
|
|
|
|||
|
|
@ -45,15 +45,15 @@ public class FirstCustomJobWithMultipleActivitiesExample {
|
|||
|
||||
@Test
|
||||
public void shouldRunOK() {
|
||||
CustomJob cj = CustomJob.Builder.newInstance("job")
|
||||
.addPickup(Location.newInstance(10, 0), SizeDimension.Builder.newInstance().addDimension(0, 1).build())
|
||||
.addPickup(Location.newInstance(5, 0), SizeDimension.Builder.newInstance().addDimension(0, 2).build())
|
||||
.addPickup(Location.newInstance(20, 0), SizeDimension.Builder.newInstance().addDimension(0, 1).build())
|
||||
.build();
|
||||
CustomJob cj = new CustomJob.Builder("job")
|
||||
.addPickup(Location.newInstance(10, 0), SizeDimension.Builder.newInstance().addDimension(0, 1).build())
|
||||
.addPickup(Location.newInstance(5, 0), SizeDimension.Builder.newInstance().addDimension(0, 2).build())
|
||||
.addPickup(Location.newInstance(20, 0), SizeDimension.Builder.newInstance().addDimension(0, 1).build())
|
||||
.build();
|
||||
VehicleType type = VehicleTypeImpl.Builder.newInstance("type").addCapacityDimension(0, 4).build();
|
||||
Vehicle v = VehicleImpl.Builder.newInstance("v").setType(type).setStartLocation(Location.newInstance(0, 0)).build();
|
||||
VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance()
|
||||
.addJob(cj).addVehicle(v).build();
|
||||
.addJob(cj).addVehicle(v).build();
|
||||
VehicleRoutingAlgorithm vra = Jsprit.createAlgorithm(vrp);
|
||||
vra.setMaxIterations(10);
|
||||
VehicleRoutingProblemSolution solution = Solutions.bestOf(vra.searchSolutions());
|
||||
|
|
@ -63,15 +63,15 @@ public class FirstCustomJobWithMultipleActivitiesExample {
|
|||
|
||||
@Test
|
||||
public void shouldNotIgnoresCapacity() {
|
||||
CustomJob cj = CustomJob.Builder.newInstance("job")
|
||||
.addPickup(Location.newInstance(10, 0), SizeDimension.Builder.newInstance().addDimension(0, 1).build())
|
||||
.addPickup(Location.newInstance(5, 0), SizeDimension.Builder.newInstance().addDimension(0, 2).build())
|
||||
.addPickup(Location.newInstance(20, 0), SizeDimension.Builder.newInstance().addDimension(0, 1).build())
|
||||
.build();
|
||||
CustomJob cj = new CustomJob.Builder("job")
|
||||
.addPickup(Location.newInstance(10, 0), SizeDimension.Builder.newInstance().addDimension(0, 1).build())
|
||||
.addPickup(Location.newInstance(5, 0), SizeDimension.Builder.newInstance().addDimension(0, 2).build())
|
||||
.addPickup(Location.newInstance(20, 0), SizeDimension.Builder.newInstance().addDimension(0, 1).build())
|
||||
.build();
|
||||
VehicleType type = VehicleTypeImpl.Builder.newInstance("type").addCapacityDimension(0, 2).build();
|
||||
Vehicle v = VehicleImpl.Builder.newInstance("v").setType(type).setStartLocation(Location.newInstance(0, 0)).build();
|
||||
VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance()
|
||||
.addJob(cj).addVehicle(v).build();
|
||||
.addJob(cj).addVehicle(v).build();
|
||||
VehicleRoutingAlgorithm vra = Jsprit.createAlgorithm(vrp);
|
||||
vra.setMaxIterations(10);
|
||||
VehicleRoutingProblemSolution solution = Solutions.bestOf(vra.searchSolutions());
|
||||
|
|
@ -81,15 +81,15 @@ public class FirstCustomJobWithMultipleActivitiesExample {
|
|||
|
||||
@Test
|
||||
public void shouldNotIgnoresCapacityWithMixedPicksAndDeliveries() {
|
||||
CustomJob cj = CustomJob.Builder.newInstance("job")
|
||||
.addPickup(Location.newInstance(10, 0), SizeDimension.Builder.newInstance().addDimension(0, 1).build())
|
||||
.addPickup(Location.newInstance(5, 0), SizeDimension.Builder.newInstance().addDimension(0, 2).build())
|
||||
.addDelivery(Location.newInstance(20, 0), SizeDimension.Builder.newInstance().addDimension(0, 3).build())
|
||||
.build();
|
||||
CustomJob cj = new CustomJob.Builder("job")
|
||||
.addPickup(Location.newInstance(10, 0), SizeDimension.Builder.newInstance().addDimension(0, 1).build())
|
||||
.addPickup(Location.newInstance(5, 0), SizeDimension.Builder.newInstance().addDimension(0, 2).build())
|
||||
.addDelivery(Location.newInstance(20, 0), SizeDimension.Builder.newInstance().addDimension(0, 3).build())
|
||||
.build();
|
||||
VehicleType type = VehicleTypeImpl.Builder.newInstance("type").addCapacityDimension(0, 2).build();
|
||||
Vehicle v = VehicleImpl.Builder.newInstance("v").setType(type).setStartLocation(Location.newInstance(0, 0)).build();
|
||||
VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance()
|
||||
.addJob(cj).addVehicle(v).build();
|
||||
.addJob(cj).addVehicle(v).build();
|
||||
VehicleRoutingAlgorithm vra = Jsprit.createAlgorithm(vrp);
|
||||
vra.setMaxIterations(10);
|
||||
VehicleRoutingProblemSolution solution = Solutions.bestOf(vra.searchSolutions());
|
||||
|
|
@ -99,17 +99,17 @@ public class FirstCustomJobWithMultipleActivitiesExample {
|
|||
|
||||
@Test
|
||||
public void shouldNotIgnoresCapacityWithMixedPicksAndDeliveriesV2() {
|
||||
CustomJob cj = CustomJob.Builder.newInstance("job")
|
||||
.addPickup(Location.newInstance(10, 0), SizeDimension.Builder.newInstance().addDimension(0, 1).build())
|
||||
.addPickup(Location.newInstance(5, 0), SizeDimension.Builder.newInstance().addDimension(0, 2).build())
|
||||
.addDelivery(Location.newInstance(20, 0), SizeDimension.Builder.newInstance().addDimension(0, 3).build())
|
||||
.build();
|
||||
CustomJob cj = new CustomJob.Builder("job")
|
||||
.addPickup(Location.newInstance(10, 0), SizeDimension.Builder.newInstance().addDimension(0, 1).build())
|
||||
.addPickup(Location.newInstance(5, 0), SizeDimension.Builder.newInstance().addDimension(0, 2).build())
|
||||
.addDelivery(Location.newInstance(20, 0), SizeDimension.Builder.newInstance().addDimension(0, 3).build())
|
||||
.build();
|
||||
assertEquals(SizeDimension.Builder.newInstance().addDimension(0, 0).build(), cj.getSizeAtStart());
|
||||
assertEquals(SizeDimension.Builder.newInstance().addDimension(0, 0).build(), cj.getSizeAtEnd());
|
||||
VehicleType type = VehicleTypeImpl.Builder.newInstance("type").addCapacityDimension(0, 3).build();
|
||||
Vehicle v = VehicleImpl.Builder.newInstance("v").setType(type).setStartLocation(Location.newInstance(0, 0)).build();
|
||||
VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance()
|
||||
.addJob(cj).addVehicle(v).build();
|
||||
.addJob(cj).addVehicle(v).build();
|
||||
VehicleRoutingAlgorithm vra = Jsprit.createAlgorithm(vrp);
|
||||
vra.setMaxIterations(10);
|
||||
VehicleRoutingProblemSolution solution = Solutions.bestOf(vra.searchSolutions());
|
||||
|
|
@ -119,15 +119,15 @@ public class FirstCustomJobWithMultipleActivitiesExample {
|
|||
|
||||
@Test
|
||||
public void shouldNotIgnoresCapacityWithExchange() {
|
||||
CustomJob cj = CustomJob.Builder.newInstance("job")
|
||||
.addPickup(Location.newInstance(10, 0), SizeDimension.Builder.newInstance().addDimension(0, 1).addDimension(1, 0).build())
|
||||
.addExchange(Location.newInstance(5, 0), SizeDimension.Builder.newInstance().addDimension(0, -3).addDimension(1, 2).build())
|
||||
.addDelivery(Location.newInstance(20, 0), SizeDimension.Builder.newInstance().addDimension(1, 1).build())
|
||||
.build();
|
||||
CustomJob cj = new CustomJob.Builder("job")
|
||||
.addPickup(Location.newInstance(10, 0), SizeDimension.Builder.newInstance().addDimension(0, 1).addDimension(1, 0).build())
|
||||
.addExchange(Location.newInstance(5, 0), SizeDimension.Builder.newInstance().addDimension(0, -3).addDimension(1, 2).build())
|
||||
.addDelivery(Location.newInstance(20, 0), SizeDimension.Builder.newInstance().addDimension(1, 1).build())
|
||||
.build();
|
||||
VehicleType type = VehicleTypeImpl.Builder.newInstance("type").addCapacityDimension(0, 3).addCapacityDimension(1, 2).build();
|
||||
Vehicle v = VehicleImpl.Builder.newInstance("v").setType(type).setStartLocation(Location.newInstance(0, 0)).build();
|
||||
VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance()
|
||||
.addJob(cj).addVehicle(v).build();
|
||||
.addJob(cj).addVehicle(v).build();
|
||||
VehicleRoutingAlgorithm vra = Jsprit.createAlgorithm(vrp);
|
||||
vra.setMaxIterations(10);
|
||||
VehicleRoutingProblemSolution solution = Solutions.bestOf(vra.searchSolutions());
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ public class LoadConstraintTest {
|
|||
|
||||
@Test
|
||||
public void whenCustomJob_itShouldNotIgnoreCapacity() {
|
||||
CustomJob cj = CustomJob.Builder.newInstance("job")
|
||||
CustomJob cj = new CustomJob.Builder("job")
|
||||
.addPickup(Location.newInstance(10, 0), SizeDimension.Builder.newInstance().addDimension(0, 1).build())
|
||||
.addPickup(Location.newInstance(5, 0), SizeDimension.Builder.newInstance().addDimension(0, 2).build())
|
||||
.addPickup(Location.newInstance(20, 0), SizeDimension.Builder.newInstance().addDimension(0, 1).build())
|
||||
|
|
@ -276,7 +276,7 @@ public class LoadConstraintTest {
|
|||
public void whenPDRouteRouteAndNewDeliveryFitsIn_itShouldReturnFulfilled() {
|
||||
stateManager.informInsertionStarts(Arrays.asList(pickupDeliveryRoute), Collections.emptyList());
|
||||
DeliveryJob s = new DeliveryJob.Builder("del").addSizeDimension(0, 15).setLocation(Location.newInstance(0))
|
||||
.build();
|
||||
.build();
|
||||
ServiceLoadRouteLevelConstraint loadConstraint = new ServiceLoadRouteLevelConstraint(stateManager);
|
||||
JobInsertionContext context = new JobInsertionContext(pickupDeliveryRoute, s, serviceRoute.getVehicle(), null, 0.);
|
||||
assertTrue(loadConstraint.fulfilled(context));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue