2

I'm trying to replace Jess with Drools as backward chaining rule engine in our project. I was looking for simple examples about how backward chaining is done with Drools. Interestingly, there's only 1 same example on every site (which I don't get how it's BC but let's forget it for now).

Very trivial example of BC in Jess:

//q is a fact template with a slot named 'n'
//when there's a q with n==8 print something
//I need a q with n==8 to fire a rule so I will insert it myself!

(deftemplate q (slot n))
(do-backward-chaining q)
(defrule printq (q (n 8))   =>  (printout t "n is eight! yeah!" crlf))
(defrule iNeedn8 (need-q (n 8)) => (assert (q (n 8))))
(reset)
(run 1)
//fires printq and prints to console...

Equivalent in Drools:

package com.example;

declare Q
    n : int
end

rule "print q"
when
    Q(n == 8)
then
    System.out.println("n is eight by drools!");
end

//I'M LOST HERE! HELP!

How can I achieve same behaviour with Drools?

uylmz
  • 1,480
  • 2
  • 23
  • 44
  • 2
    Drools BW chaining isn't the same as Jess' BW chaining, and I think both can't do what Prolog is capable of doing. – laune Jun 10 '15 at 17:40
  • Can't I find which fact is missing (Q(n==8)) for a rule to be fired in Drools? (they differ in functionality, jess is more capable in BWC?) – uylmz Jun 10 '15 at 19:27
  • I agree with @laune, the two engines implement BWC quite differently and neither, afaik, has the same capabilities of Prolog in this sense. However, the feature is being worked on. It will be documented officially as soon as stable. – Davide Sottara Jun 12 '15 at 05:39
  • @DavideSottara This "documented officially as stable" sounds nice, but the question is: Will it be **documented**? – laune Jun 12 '15 at 10:56

2 Answers2

1

In Drools, the general idea of BC is to use queries. In addition to your rule "print q" you need:

query noQ( int $num )
    Goal(num==$num) and not Q(num == $num)
end

rule goal when
    Goal( $n: num )
    noQ($n;)
then
    Q q = new Q($n);
    insert( q );
end

rule go when
then
    insert( new Goal( 8 ) );
end

There is no way to instruct Drools to detect the missing fact all by itself; you have to provide the goal and queries to "bridge the gap".

laune
  • 31,114
  • 3
  • 29
  • 42
1

Inspired from the Jess feature, there is an experimental, in-development feature that gives you a similar behavior. Here is how a test would look like:

@Test
public void testFindQ8() {
    String droolsSource =
        " package org.drools.abductive.test;                 " +
        "                                                    " +
        " import " + Abducible.class.getName() + ";          " +
        " global java.util.List list;                     \n " +
        "                                                    " +
        " declare Q                                          " +
        "    @Abducible                                      " +
        "    id : int @key                                   " +
        " end                                             \n " +
        "                                                    " +
        " query foo( int $x )                                " +
        "    @Abductive( target=Q.class )                    " +
        "    not Q( $x; )                                    " +
        " end                                             \n " +
        "                                                    " +
        " rule R1                                            " +
        " when                                               " +
        "    $x := foo( 8 ; )                                " +
        " then                                               " +
        "    System.out.println( 'R1 returned ' + $x );      " +
        " end                                             \n " +
        "                                                    " +
        " rule R2                                            " +
        " when                                               " +
        "    $q : Q( 8; )                                    " +
        " then                                               " +
        "    System.out.println( 'We have 8!' );             " +
        " end                                                ";
    /////////////////////////////////////

    KieHelper kieHelper = new KieHelper();
    kieHelper.addContent( droolsSource, ResourceType.DRL ).build().newKieSession().fireAllRules();


}
lakshayg
  • 2,053
  • 2
  • 20
  • 34
Davide Sottara
  • 221
  • 1
  • 3
  • Thanks , it may be less painful to implement this way. Is there any documentation about @Abductive (how it works), I didn't see any? – uylmz Jun 13 '15 at 18:39
  • And for @Abducible as well? – laune Jun 13 '15 at 18:42
  • 1
    As mentioned, the feature is extremely experimental, so subject to change. Anything documented officially requires the same level of stability of an API. The option of splitting the documentation between "stable" and "experimental" features, to allow for this kind of things, has been discussed – Davide Sottara Jun 14 '15 at 18:33
  • 1
    This said, at the moment, "@Abductive" queries will try to insert an instance of the "target" class, if not already present in the WM, for each result tuple. The instance is constructed using the result tuple itself. Other than this, the TMS does not really support abductive reasoning yet. You can follow updates and new capabilities here on the JIRA ticket https://issues.jboss.org/browse/DROOLS-371 And the unit tests https://github.com/droolsjbpm/drools/blob/master/drools-compiler/src/test/java/org/drools/compiler/beliefsystem/abductive/AbductionTest.java – Davide Sottara Jun 14 '15 at 18:34