簡體   English   中英

使用 OptaPlanner 解決具有容量的車輛路線問題

[英]Using OptaPlanner to solve a Vehicle Routing Problem with Capacities

向所有 optaplanner 人員問好。 我是使用 optaplanner 的新手,在這里我有一些關於規划具有重量和體積容量的車輛路線的問題。 感謝您的幫助,我感謝您的任何建議。

我正在實施具有容量的 VRP,但要求按重量和體積確定容量。 我遵循的路徑是以optaplanner為例,在體積和重量上重構車輛容量,在重量和體積上也重構了訪問的需求。 然后我修改了 Constraint Provider,它使用數量處理容量,處理重量,然后我實現了另一個非常相似但處理體積的 Constraint Provider。 從現在開始,我還將需要其他尺寸的車輛容量和訪客(客戶)的負載。

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. 是的,我更喜歡將重量和體積拆分為單獨的約束,以保持它們隔離,這樣更便於維護。 此外,一旦您開始使用 ConstraintMatchTotals 等向用戶“解釋分數”,這肯定會更好。
  • 3 & 4) 典型的方法是將一次客戶訪問拆分為同一地點的多次訪問。 所以分成多個部分。 例如,如果車輛在一個位置拾取了 5 個零件中的 3 個,則這 3 個位置之間的行駛時間為零,並且裝載/卸載時間折疊(請參閱自動折疊設計模式)。 最大的挑戰是在 optaplanner 解決之前確定這些部分的粒度。 這是一個微調練習。 如果您正在移動箱子、托盤、物品等,這很有效。可能的例外是,如果您正在移動水、金錢、天然氣等。在這種情況下,可能會感興趣像 InvestementPortofio 示例那樣進行功率調整而是這樣做了。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM