使用 TimeWindows 在 VehicleRouting 中忽略规则

Rules are Ignored in VehicleRouting with TimeWindows

我使用 Optaplanner 的示例来计算带有 Timewindows 的 VRP 的最佳路线,并对代码进行了一些修改以满足我们的需求。

我们有技术人员在客户处工作。 每个技术人员都是自己的 "depot",因为他们可以从不同的位置开始。 因此每个仓库只有一辆车。

对于给定的示例,这非常有效。

现在我们要添加一条规则,只有具备所需资格的技术人员才能被安排给客户(例如,只允许部分技术人员进行钻孔)

客户和技术人员的资质都需要匹配。 我们在drl文件中添加了一条规则:

rule "qulificationcorrect"
when
    $vehicle : Vehicle($vehicleQualifications:qualifications)
    $customer : Customer(vehicle==$vehicle,$customerQualification:qualifications)
    $test : Integer(RuleHelper.qualified($vehicleQualifications,$customerQualification)<1)
then
    System.out.println(RuleHelper.qualified($depotQualifications,$customerQualification));
    scoreHolder.addHardConstraintMatch(kcontext, -100L);

Rulehelper 看起来像这样:

public class RuleHelper
{
   public static int qualified(Integer[] vehicle, Integer[] customer)
   {
       if (customer == null || customer.length < 1)
       {
        System.out.println("CUSTOMER EMPTY");

        return 1;
       }
       if (vehicle == null || vehicle.length < 1)
       {
           System.out.println("VEHICLE EMPTY");

           return 0;
       }
       List<Integer> vehicleList = Arrays.asList(vehicle);
       List<Integer> customerList = Arrays.asList(customer);
       System.out.println("VehicleList=" + vehicleList + " CustomerList" + customerList + " rule = " + vehicleList.containsAll(customerList));
       return vehicleList.containsAll(customerList) ? 1 : 0;
   }
}

但是当我查看我的解决方案时,它没有硬分 (0),这是输出:

{
 "solutions" : [
   {
     "employee" : {
       "name" : "Technician 1",
       "qualifications" : [
         1,
         2,
         5,
         999
       ],
       "lat" : 49.70103,
       "lng" : 8.32404,
       "employeeId" : 31,
       "startTime" : 480,
       "endTime" : 1170,
       "maxOrderCount" : 0,
       "solutionId" : 1
     },
     "orders" : [
       {
         "qualifications" : [
           1000
         ],
         "transmittedStart" : 435,
         "transmittedEnd" : 660,
         "startTime" : 480,
         "endTime" : 540,
         "lat" : 49.96685,
         "lng" : 8.0308,
         "orderId" : 638411,
         "fixed" : false,
         "calculatedStart" : 522,
         "calculatedEnd" : 567,
         "solutionId" : 4
       },
       {
         "qualifications" : [
           999
         ],
         "transmittedStart" : 615,
         "transmittedEnd" : 840,
         "startTime" : 660,
         "endTime" : 720,
         "lat" : 49.89585,
         "lng" : 8.0809,
         "orderId" : 637001,
         "fixed" : false,
         "calculatedStart" : 583,
         "calculatedEnd" : 660,
         "solutionId" : 3
       }
     ]
   },
   {
     "employee" : {
       "name" : "Technician 2",
       "qualifications" : [
         3,
         1000
       ],
       "lat" : 49.70103,
       "lng" : 8.32404,
       "employeeId" : 264,
       "startTime" : 480,
       "endTime" : 1170,
       "maxOrderCount" : 0,
       "solutionId" : 2
     },
     "orders" : [ ]
   }
 ]
}

虽然第一个技术员的资格只有1,2,5,999 而不是1000,但基本上第一个技术员获得了两个订单(客户)。第二个技术员没有获得订单,而是获得了资格1000 的订单。

我希望这些信息足以让别人告诉我哪里出了问题...

国王问好

编辑:感谢 Geoffrey De Smet 的帮助 我将规则更改为

rule "qualificationcorrect"
when
    $customer : Customer(hasAllQualifications() == false)
then

    scoreHolder.addHardConstraintMatch(kcontext, -100L);

结束

并且还在客户中实施了 hasAllQualifications:

    public boolean hasAllQualifications()
{
    if (qualifications.length < 1)
    {
            return true;
    }
    if (vehicle == null || vehicle.getQualifications() == null || vehicle.getQualifications().length < 1)
    { 
        return false;
    }
    List<Integer> vehicleList = Arrays.asList(vehicle.getQualifications());
    List<Integer> customerList = Arrays.asList(this.getQualifications());
    return vehicleList.containsAll(customerList);
}

现在解决方案显示了预期的行为 再次感谢您的快速回答

这可能与 "incremental score calculation" 的工作方式有关(它依赖于调用 modify() 流口水事实)。 打开 environmentMode FULL_ASSERT - 如果它抛出分数损坏异常,这就是问题所在。

如果是这样,让我们​​看看你的规则

when
    $vehicle : Vehicle($vehicleQualifications:qualifications)
    // When the Customer.vehicle changes, the rule engine gets notified
    $customer : Customer(vehicle==$vehicle,$customerQualification:qualifications)
    // That should retrigger the evaluation of this line every time a customer's vehicle changes
    $test : Integer(RuleHelper.qualified($vehicleQualifications,$customerQualification)<1)

在任何情况下,您可能都想像这样重写它:

when
    $customer : Customer(hasAllQualifications() == false)

然后 Customer.hasAllQualifications() 看看 Customer.vehicle