Thursday, June 25, 2009

Complex Logic Formulas #3

In my previous two posts I introduced configurable operators, but maybe some of you noticed that I (willingly) left one out: the negation NOT.

In Drools, negation appears essentially in three places, with slightly different semantics:

  • relational evaluators have their negated counterpart:
    Person( age == 18 , age != 18 )
  • custom evaluators support the "not" prefix keyword:
    Person( age not ~old )
  • the (non) existential quantifier is allowed:
    not Person( age < 18)

In particular, the second and the third case have diffrent meanings.

The negation in "age not old" is a logical negation: it takes the result of the evaluator (be it a boolean or a generalized degree) and inverts it, mapping true to false and vice versa. The quantifier "not", instead, models the condition "when there is NO object matching the pattern...".

In fact, logicians use the term logical negation in the former, and negation as failure in the latter. Due to this ambiguity, in Drools Chance not is still supported with the usual, context-dependent semantics, but is deprecated. Instead, the two operators neg and naf are proposed.

neg can be used both before evaluators and between-pattern evaluators, and can be nested:

rule "NEG"
neg neg neg ( // equivalent to a single neg
$p : Person( age neg ~young )
Car( owner == $p, price neg ~low )
// this rule activates for each pair Person/Car in which
// either the owner is young or their car is expensive

naf, instead, must be used before a sub-formula:

rule "NAF"
naf Person( age < 18 )
// this rule will activate if there are no people who aren't young
// (i.e. all "Person"s are old)

Notice that in Drools the two are connected by the relation naf <-> neg exists.