使用TimeWindows在VehicleRouting中忽略规则

时间:2018-07-02 06:30:21

标签: drools optaplanner

我以Optaplanner为例,使用Timewindows计算了VRP的最佳路线,并对代码进行了一些调整以满足我们的需求。

我们有在客户现场工作的技术人员。 每个技术人员都是其自己的“仓库”,因为他们可以在不同的位置开始。 因此,每个仓库只能有一辆车。

在给定的示例中,这非常好用。

现在,我们要添加一条规则,即只有在具有所需资格的情况下(例如,仅允许某些技术人员进行钻研),才应将技术人员仅委托给客户。

客户和技术人员都具有需要匹配的资格。 我们在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);
}

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

1 个答案:

答案 0 :(得分:1)

这可能与“增量分数计算”的工作方式有关(这取决于对流口水事实的称呼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