首页 > 解决方案 > Optaplanner 中车辆容量的 Drools 规则

问题描述

我正在使用 Optaplanner 进行 CVRP 并进行了一些更改,即想为车辆容量使用多个维度。我开设了一个新班级

public class Load {
protected int[] capacity;
protected int myDimension=1;}

它还有几种管理数据的方法,最重要的是

public void add (Load otherLoad) {
    if (myDimension != otherLoad.myDimension) {
        throw new IllegalArgumentException("Different load dimensions (" + myDimension +" / "+ otherLoad.myDimension + ").");
    } else {
        for (int i=0; i < myDimension; i++) {
            capacity[i]+=otherLoad.capacity[i];
        }
    }
}

public boolean fitsInto (Load otherContainer) {
    if (myDimension != otherContainer.myDimension) {
        throw new IllegalArgumentException("Different load dimensions (" + myDimension +" / "+ otherContainer.myDimension + ").");
    } else {
        for (int i=0; i < myDimension; i++) {
            if (capacity[i]>otherContainer.capacity[i]) return false;
        }
    }
    return true;
}

目前我对 Drools 规则有困难,因为我对此完全陌生。旧规则是:

rule "vehicleCapacity"
when
    $vehicle : Vehicle($capacity : capacity)
    accumulate(
        Customer(
            vehicle == $vehicle,
            $demand : demand);
        $demandTotal : sum($demand);
        $demandTotal > $capacity
    )
then
    scoreHolder.addHardConstraintMatch(kcontext, $capacity - $demandTotal);

结尾

我需要修改它,以便它使用 Load 类而不是整数,但不确定如何。在阅读了一些 Drools 文档后,我的蹩脚实验是这样的

rule "vehicleCapacity"
when
    $demandTotal: Load
    $vehicle : Vehicle($capacity : capacity)
    accumulate(
        Customer(
            vehicle == $vehicle,
            $demand : demand);
        $demandTotal.add($demand);
        not ($demandTotal.fitsInto($capacity))
    )
then
    scoreHolder.addHardConstraintMatch(kcontext, $capacity.sumValues() - $demandTotal.sumValues());

结尾

当然它没有通过,所以我很乐意得到一些提示和建议。谢谢!

标签: classdroolsrulesoptaplanner

解决方案


据我了解,您正在尝试将更多维度添加到demand并因此添加到capacity,其中限制是任何维度的容量都不能被超过。为此,您可以简单地Vehicle修改Customers如下

class Vehicle extends AbstractPersistable implements Standstill{
     protected Location location;
     protected List<Integer> capacities;
     ...
}

class Customer extends AbstractPersistable implements Standstill{
    protected List<Integer> demands;
    ...
}

然后,在 Drools 中,您修改您的规则(绝对未经测试;特别是,您可能必须.intValue()在 get 方法之后添加):

rule "vehicleCapacity"
when
    $vehicle : Vehicle($capacity: capacities.get($loadType:lt))
    accumulate(
        Customer(
            vehicle == $vehicle,
            $demand : demands.get($loadType));
        $demandTotal : sum($demand);
        $demandTotal > $capacity
    )
then
    scoreHolder.addHardConstraintMatch(kcontext, $capacity - $demandTotal);

这将确保如果任何维度的需求超过容量,硬分就会对差异进行惩罚。只需确保使所有列表大小相同,其中的维度对应于 中的相同$loadType维度。capacitiesdemands

您也可以尝试通过更改protected int capacityprotected int[] capacitiesinVehicle和类似地 in Customerwith demand,但我不确定您是否可以绑定到 Drools 中的数组元素。也许值得一试:Drools 规则然后运行(再次绝对未经测试):

rule "vehicleCapacity"
    when
        $vehicle : Vehicle($capacity: capacities[$lt:lt])
        accumulate(
            Customer(
                vehicle == $vehicle,
                $demand : demands[lt]);
            $demandTotal : sum($demand);
            $demandTotal > $capacity
        )
    then
        scoreHolder.addHardConstraintMatch(kcontext, $capacity - $demandTotal);

(那么至少.intValue()不需要)


推荐阅读