пользовательская реализация ScoreHolder в optaplanner

Мой главный вопрос: могу ли я использовать в OptaPlanner индивидуальную реализацию ScoreHolder для подсчета очков слюни? И если да, то как я могу это сделать, поскольку объект scoreHolder неявно вводится в глобальную переменную? Ниже вы можете найти подробную информацию, почему я хотел бы использовать собственную реализацию ScoreHolder.

Во время работы над приложением я обнаружил одну проблему, которая должна оптимизировать стоимость некоторой продукции. У меня есть устройства и по прогнозам я рассчитываю производство для каждого устройства. Я использую OptaPlanner, и у меня есть следующее правило:

when
    $device : Device($deviceId : id)
    $forecast : Forecast(deviceId == $deviceId)
then
    int deviceProduction = $device.calculateProduction($forecast);
    scoreHolder.addSoftConstraintMatch(kcontext, deviceProduction);
end

Таким образом, после этого мягкая оценка будет содержать количество общего производства (totalProduction). Я хочу, чтобы ЗНАЧЕНИЕ общего производства оставалось в мягком рейтинге. Проблема в том, что стоимость продукции - это не просто умножение всего производства на цену. Есть лимит производства, и все сверх лимита имеет отрицательную цену. Итак, мы задали лимит и две цены: положительную (positive_price) и отрицательную (negative_price). Схема расчета стоимости выглядит следующим образом:

if( overallProduction <= limit)
    value = positive_price * overallProduction;
else
    value = positive_price * limit + negative_price * (overallProduction - limit);

Поэтому я думаю, что я не могу включить расчет этого значения в рассчитанное по правилам производство для одного устройства, потому что я могу рассчитать это значение для общего производства только после сбора данных со всех устройств.

Моя единственная идея, как я могу с этим справиться, - это иметь собственную реализацию ScoreHolder, расширяющую HardSoftScoreHolder. Этот настраиваемый ScoreHolder будет храниться внутри, в мягкой оболочке, в целом. Он будет засчитан по правилу, приведенному в начале. И затем правильное значение будет вычислено настраиваемым ScoreHolder непосредственно перед возвратом результата из метода extractScore.

Вопрос в том, могу ли я использовать свой пользовательский ScoreHolder для подсчета очков? Поскольку глобальный объект scoreHolder вводится неявно.

Или, если есть другой способ, как я могу поместить стоимость общего производства в объект оценки?

Спасибо за вашу помощь и с наилучшими пожеланиями,


person Rem    schedule 11.12.2014    source источник
comment
Глобальная переменная не может участвовать в оценке условий правила; факты, однако, могут. Это предполагает, что вы рассчитываете общее производство в правилах и сохраняете это значение в одном факте, постоянно обновляя его, избегая зацикливания (без цикла!). Затем добавьте пару правил для вычисления значения (аналогично оператору if) и используйте значение в оценке. (Я не эксперт в optaplanner, поэтому не ставлю это как ответ.)   -  person laune    schedule 11.12.2014


Ответы (2)


Взлом ScoreHolder - это не способ сделать это (хотя, создав собственный ScoreDefinition, вы можете сделать это таким образом).

Вместо этого ваше правило может использовать insertLogical() для вставки промежуточных результатов в качестве нового факта вместо прямого изменения ScoreHolder. Затем другое правило соответствует этому промежуточному результату (вероятно, с меньшим salience) и соответственно изменяет ScoreHolder. См. Пример в списке медсестер.

Способ Лауне тоже подойдет.

person Geoffrey De Smet    schedule 11.12.2014

Вместо того, чтобы взламывать ScoreHolder, я сделал это так, как предложил Джеффри Де Смет, спасибо!

rule "SingleProduction"
    when
        $device : Device($deviceId : id)
        $forecast : Forecast(deviceId == $deviceId)
    then
        int deviceProduction = $device.calculateProduction($forecast);
        insertLogical(new SingleProduction(deviceProduction));
end

rule "ValueOfTotalProduction"
    when
        ProductionLimit( $limit : value )
        PositivePrice( $positivePrice : value )
        NegativePrice( $negativePrice : value )
        Number( $totalProduction : intValue() )
                 from accumulate( SingleProduction( $value : value ),
                              sum( $value ) )
    then
        int productionValue;
        if($totalProduction <= $limit)
            productionValue = $totalProduction * $positivePrice;
        else
            productionValue = $limit * $positivePrice +
                              ($totalProduction - $limit) * $negativePrice;

        scoreHolder.addSoftConstraintMatch(kcontext, productionValue);
end
person Rem    schedule 13.12.2014