Tuesday, May 26, 2009

Imperfect Evaluations

This is my first technical dive into Drools Chance and is a follow up to my posting "Take your Chance".

The first step in adding imperfection to a rule is to give up its "boolean" nature. Consider again the example:
$r : Room ( $temp : temperature > 25 )  //r1 

The (literal) restriction on the field temperature wraps an Evaluator, '>' in this case, which is responsible for comparing the actual value $temp to the literal value 25. Of course, assuming that the bean $r models a known Room with a precise thermal sensor...

1) Imperfect Data
In a more realistic scenario, all you have is an imprecise and unreliable sensor: a simple real number is hardly adequate to model the measured value. One could take a measurement error into account, or maybe a "reliability" value if sensors tend to fail and return inconsistent values. To store all the information, one could define a simple bean:

declare UnreliableTemperatureMeasure
mean : float [-20..60]
error : float [0..10]
reliability : Percentage [0..1]

Now the field temperature returns an instance of UnreliableTemperatureMeasure, which has to be compared with a threshold:

$r : Room ( $temp : temperature > $thold )  

The threshold itself could be an instance of the same class, UnreliableTemperatureMeasure, created at some earlier point in the code:

thold = new UnreliableTemperatureMeasure();

The value stored in $thold now represents a reliable, but slightly relaxed "25 +/- 1.5"

Imperfect Evaluators
The main drawback of using UnreliableTemperatureMeasures instead of Numbers (or any other custom class, in any ohter context) is that the standard evaluator '>' is no longer adequate.
Drools, however, allows the definition of custom evaluators:

$r : Room ( $temp : temperature ~above[ params... ] $tHold )  //r3

A custom evaluator is (an instance of) a class holding a piece of business logic. It computes whether - and in which degree - the left operand has a certain property with respect to the optional right operand and some additional initialization parameters.

The full APIs are quite powerful and flexible, but not yet stable. However, one often just needs to define a simple imperfect custom evaluator quickly and get it to work. This can be done in a few steps:

  1. Set the RuleBaseConfiguration property "org.drools.evaluator.[CustomEval]" to the name of a class extending

  2. Such class, e.g. [CustomEvalDefinition], must register an Operator:

    public static final Operator CUSTOM = Operator.addOperatorToRegistry( "custom", false );

    public String[] getEvaluatorIds() {
    return new String[] {"custom"};

  3. ... and define the method getEvaluator, which returns the instance of the Evaluator proper:
    public Evaluator getEvaluator(ValueType type, String operatorId,
    boolean isNegated, String parameterText,
    Target leftTarget, Target rightTarget) {
    return new CustomEval();

  4. The class [CustomEval] extends
    and overrides the method:
    protected abstract IDegree eval(Object left, Object right, IDegreeFactory factory);

Notice that the EvaluatorDefinition creates a decoupling between the Operator - e.g. "above" - and the actual Evaluator. This also means that the same instance of Evaluator could be used to define different operators.

3) Imperfect Degrees

Back to the original problem... Suppose that the probe returns a slightly unreliable (24.3 +/- 2): it's not possible to say whether such value is certainly greater than (25 +/- 1.5).

Given the values, it could seem not very probable: likely it will never be but much greater, but it is possible nevertheless. How to evaluate this is the task of the CustomEvaluator associated to the Operator "above".

Which information to return and how to do it, instead, is yet another degree of freedom. Drools Chance provides an interface, IDegree, which should be implemented by any class modelling the degree of truth/probability/certainty/possibility/... at which a constraint is satisfied.

An IDegree should at least model the concepts of "true", "false" and, possibly, "unknown". So, it is possible to cast an IDegree to boolean and vice versa.

The simplest, and most widely used, type of IDegree is a real number in [0,1], and has been used to model confidence, certainty, fuzzy degrees of truth, simple probabilities, ...

IDegrees are not built directly, but using a concrete object implementing the interface IDegreeFactory. The factory, which can be set using a RuleBase configuration property, ensures that the degrees used in the computation are coherent.

More importantly, using custom pluggable evaluators together with custom pluggable degrees allows to change the behaviour of a rule without changing the abstract idea behind them. For example, the concept of "temperature above threshold" expresses an abstract concept which can be specialized according to different interpretations.