Search code examples
optimizationdroolsoptaplanner

optaplanner custom implementation of ScoreHolder


My main question is, if I can use in OptaPlanner custom implementation of ScoreHolder in drools score calculation? And if yes, how I can do it, as the scoreHolder object is injected implicitly to global variable? Below you can find details, why I would like to use custom implementation of ScoreHolder.

I have found one problem during my work on an application that need to optimize value of some production. I have devices and based on forecasts I calculate production for each device. I use OptaPlanner and I have rule like following:

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

So after this, soft score will contain amount of overall production (overallProduction). What I want to have, is to keep VALUE of overall production in the soft score. The problem is, that value of production is not just overallProduction multiplied by price. There is a limit of production and everything over the limit have negative price. So we have given limit and two prices: positive(positive_price) and negative(negative_price). The schema of value calculation looks like following:

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

So I think, I can't include calculation of this value inside rule calculated production for single device, because I'm able to calculate this value of overall production, only after collection of production from all devices.

My only idea how I can handle it, is to have custom implementation of scoreHolder extending HardSoftScoreHolder. This custom ScoreHolder would keep internally, in soft sore, overall production. It will be counted by rule given at the beginning. And then, the proper value will be calculated by custom ScoreHolder, just before returning result from extractScore method.

The question is, if I can use my custom ScoreHolder inside drools score calculation? As global scoreHolder object is injected implicitly..

Or if there is other way how I can put value of overall production into score object?

Thanks for your help and best regards,


Solution

  • Hacking the ScoreHolder is not the way to do this (although by creating a custom ScoreDefinition you can do it that way).

    Instead, your rule can use an insertLogical() to insert the intermediate results as a new fact, instead of modifying the ScoreHolder directly. Then another rule matches on that intermediate result (probably with a lower salience) and modifies the ScoreHolder accordingly. See the nurse rostering example for an example.

    Laune's way would also work.