Reputation: 61
Hello to all optaplanners. I am a novice in the use of optaplanner and here I have some questions about planning vehicle routes with dimensioned capacities in weight and volume. Thank you for your help, I appreciate any suggestions.
I am implementing a VRP with capacities but require that the capacity be dimensioned in weight and volume. The path I have followed is to take the example of optaplanner and refactor the vehicle capacity in volume and weight, and the demand of the visit also in weight and volume. Then I modified the Constraint Provider that worked the capacities with quantities, to work with weight and then I implemented another Constraint Provider very similar but to work with volume. From now on I will also require other dimensions for the capacity of the vehicle and the load of the visitors (customer).
1- As I am a novice, I would like to know if my suppositions are correct, if I am on the right road?
2- I would like to know if it is right to work with a Constraint Provider for each dimension, or if I should join in a single Constraint Provider all the calculations for Weight and Volume or other. If possible, how can I do it?
3- If I have a vehicle with only a capacity in weight and another vehicle with only a capacity in volume, but I have visits (customer) whose demands require covering a weight and at the same time a volume, therefore I will never obtain a feasible route, since only one vehicle passes through the same visit. How can I solve this problem?
4- How can I manage that when the demands of the visits (customer) exceed the capacity of the vehicle, the vehicle makes more trips to the same visit until it covers the total demand of the visit (customer)?
Here I share my modifications for a better context. Thanks!
Refactored the vehicle capacity:
public class PlanningVehicle implements Standstill {
@PlanningId
private long id;
private int weightCapacity;
private int volumeCapacity;
...
}
Refactored the demand of the visit:
@PlanningEntity(difficultyWeightFactoryClass = DepotAngleVisitDifficultyWeightFactory.class)
public class PlanningVisit implements Standstill {
@PlanningId
private long id;
private PlanningLocation location;
private int weightDemand;
private int volumeDemand;
...
}
I implemented two Hard Scores, one for each dimension (weight and volume):
@ConstraintConfiguration(constraintPackage = "com.router.solver")
public class VehicleRoutingConstraintConfiguration {
...
public static final String VEHICLE_WEIGHT_CAPACITY = "Vehicle capacity in weight";
public static final String VEHICLE_VOLUME_CAPACITY = "Vehicle capacity in volume";
...
@ConstraintWeight(VEHICLE_WEIGHT_CAPACITY)
private HardSoftLongScore vehicleWeightCapacity = HardSoftLongScore.ONE_HARD;
@ConstraintWeight(VEHICLE_VOLUME_CAPACITY)
private HardSoftLongScore vehicleVolumeCapacity = HardSoftLongScore.ONE_HARD;
}
I implemented two separate constraints:
public class FirstConstraintProvider implements ConstraintProvider {
...
protected Constraint vehicleWeightCapacity(ConstraintFactory constraintFactory) {
return constraintFactory.from(TimeWindowedVisit.class)
.groupBy(PlanningVisit::getVehicle, sum(PlanningVisit::getWeightDemand))
.filter((vehicle, demand) -> demand > vehicle.getWeightCapacity())
.penalizeConfigurableLong(
VEHICLE_WEIGHT_CAPACITY,
(vehicle, demand) -> demand - vehicle.getWeightCapacity());
}
protected Constraint vehicleVolumeCapacity(ConstraintFactory constraintFactory) {
return constraintFactory.from(TimeWindowedVisit.class)
.groupBy(PlanningVisit::getVehicle, sum(PlanningVisit::getVolumeDemand))
.filter((vehicle, demand) -> demand > vehicle.getVolumeCapacity())
.penalizeConfigurableLong(
VEHICLE_VOLUME_CAPACITY,
(vehicle, demand) -> demand - vehicle.getVolumeCapacity());
}
...
}
Upvotes: 0
Views: 308
Reputation: 27327
Reading diagonally:
Upvotes: 0