使用OptaPlanner解决具有通行能力的车辆路径问题

时间:2020-10-22 19:47:53

标签: optaplanner

您好!我是optaplanner的新手,在这里我对规划重量和体积较大的车辆路线有一些疑问。谢谢您的帮助,感谢您的任何建议。

我正在实施具有容量的VRP,但要求以重量和体积来确定容量。我遵循的路径是以optaplanner为例,以体积和重量来重构车辆的容量,并且以重量和体积来重构访问的需求。然后,我修改了“约束提供程序”,该“约束提供程序”使用容量来处理数量,使用重量来工作,然后我实现了另一个非常类似但要处理体积的“约束提供程序”。从现在开始,我还将要求其他尺寸来满足车辆的容量和访客(客户)的负担。

1-作为我的新手,我想知道我的假设是否正确,如果我走的路正确?

2-我想知道是否适合与每个维度的约束提供者一起使用,或者我是否应该将所有重量和体积或其他所有计算都加入一个约束提供者中。如果可能的话,我该怎么办?

3-如果我有一辆仅具有重量能力的车辆,而另一辆仅具有体积能力的车辆,但是我有拜访(客户),其需求既需要覆盖重量又需要覆盖体积,因此我将永远都不会获得可行的路线,因为只有一辆车会经过同一次访问。我该如何解决这个问题?

4-如何处理拜访(客户)的需求超出车辆的容量时,车辆进行同一次拜访的次数更多,直到其覆盖了拜访(客户)的总需求? >

在这里,我将分享我的修改内容,以使上下文更好。谢谢!

重构的车辆容量:

public class PlanningVehicle implements Standstill {

@PlanningId
private long id;
private int weightCapacity;
private int volumeCapacity;
...
}

重构了访问需求:

@PlanningEntity(difficultyWeightFactoryClass = DepotAngleVisitDifficultyWeightFactory.class)
public class PlanningVisit implements Standstill {

    @PlanningId
    private long id;
    private PlanningLocation location;
    private int weightDemand;
    private int volumeDemand;
    ...
}

我实施了两个硬分,每个维度(重量和体积)一个:

@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;
}

我实现了两个单独的约束:

 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());
      }
     ...
 }

1 个答案:

答案 0 :(得分:0)

对角线阅读:

    1. 是的,我更喜欢将重量和体积分成单独的约束,以使其保持隔离状态,这对于维护更有利。此外,一旦您使用ConstraintMatchTotals等开始向用户“解释分数”,那肯定会更好。
  • 3&4)典型的方法是将一次客户拜访分为同一地点的多次拜访。因此分为多个部分。例如,如果某个车辆在某个位置取走了5个零件中的3个,则这3个位置之间的行驶时间为零,并且装卸时间被折叠(请参见自动折叠设计模式)。最大的挑战是在optaplanner解决之前确定这些零件的粒度。这是一个微调的练习。如果您要移动盒子,托盘,物品等,则效果很好。可能的例外情况是,您要移动水,金钱,天然气等。代替了。