Simulating accumulate will never be performant compared to implementing correctly within Rete. Completing our support for first order logic to make Drools turing complete will be prioritised very early on - we need to do forall and accumulate. Accumulate is not that difficult to do - in fact I recommend you "branch" Drools and look at the 'exists' node as accumulate isn't far from that - the harder part will be hooking this in with the parser and builder. Come onto IRC and we will give you pointers.

If you don't have time for that - as I suspect its 2 to 3 days work for a Drools noobie developer. When I get some time I'll see if I can think of a way to achieve accumulate support, even if it isn't performant - imagine it will be using a combination of rules to count the assertions and the event model to reduce counts on retraction. You will probably have to use hash maps quite extensibly too.

Mark

Juergen wrote:
In the absence of an accumulate in current drools 3 version, I tried to create a set of rules to have some sort of running sum (or any other accumulation function), but it needs as much as 3 helper objects per object qualified for accumulation.

Anybody any ideas on reducing number of helper objects and retracts/asserts? via xor-groups or no-loops?

one helper (price == -3) especially prevents looping of accumulate if sum is modified by de-accumulate if some other object no longer qualifies. Is it possible to have some sort of "no-loop" groups, where RHS changes in working memory will not only not trigger activation of the current rule but all rules in a group?

Integration test listed below.

I misused Cheese as helper object, didn't want to create a new class: type="sum" holds accumulated sum, type="limit reached" is used as flag indicating sum boundary crossings, (type=s, price elem { -1, -2, -3}) state accumulation status of qualified object s (Strings in this case); where s.length() will be accumulated

Is it possible to have some sort of "retraction hook/listener" on asserted objects by letting them implement a special interface? This implementation assumes that if an object does not longer qualify (e.g. is retracted), it will nevertheless be available (via helper, price == -1) for de-accumulation when the rules are fired again.

Juergen


----------------------------------------------------------
/*
    public void testLogicalAssertionsRunningSum() throws Exception {
        PackageBuilder builder = new PackageBuilder();
builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "test_LogicalAssertionsRunningSum.drl" ) ) );
        Package pkg = builder.getPackage();

        RuleBase ruleBase = getRuleBase();
        ruleBase.addPackage( pkg );
        WorkingMemory workingMemory = ruleBase.newWorkingMemory();

//workingMemory.addEventListener(new org.drools.event.DebugAgendaEventListener()); //workingMemory.addEventListener(new org.drools.event.DebugWorkingMemoryEventListener());

        List list;

        Cheese c = new Cheese("sum", 0);

        FactHandle h = workingMemory.assertObject(c);
        FactHandle h1 = workingMemory.assertObject("1");
        workingMemory.fireAllRules();
        assertEquals(1, c.getPrice());
        System.err.println("sum in code=" + c);
        FactHandle h2 = workingMemory.assertObject("123");
        workingMemory.fireAllRules();
        assertEquals(4, c.getPrice());
        System.err.println("sum in code=" + c);
        FactHandle h3 = workingMemory.assertObject("12");
        workingMemory.fireAllRules();
        assertEquals(6, c.getPrice());
        System.err.println("sum in code=" + c);
        workingMemory.retractObject( h1 );
        workingMemory.fireAllRules();
        assertEquals(5, c.getPrice());
        System.err.println("sum in code=" + c);
        workingMemory.retractObject( h2 );
        workingMemory.fireAllRules();
        assertEquals(2, c.getPrice());
        System.err.println("sum in code=" + c);
        workingMemory.retractObject( h3 );
        workingMemory.fireAllRules();
        assertEquals(0, c.getPrice());
        System.err.println("sum in code=" + c);
    }
*/
package org.drools.test;

import java.lang.String;
import org.drools.Cheese;

rule "object qualifies for accumulation"
    when
        s : String()
        eval(s != "sum" && s != "limit reached")
    then
        Cheese c = new Cheese(s, -1);
           assert(c);
           assertLogical(new Cheese(c.getType(), -2));
end

rule "accumulate"
    when
        sum : Cheese(type == "sum")
        Cheese(s : type, price == -1)
        Cheese(type == s, price == -2)
        not Cheese(type == s, price == -3)
    then
        //apply accumulate function
        sum.setPrice(sum.getPrice() + s.length());
modify(sum);
        assert(new Cheese(s, -3));
        System.err.println("+sum=" + sum);
end

rule "de-accumulate"
    when
        sum : Cheese(type == "sum")
        c : Cheese(s : type, price == -1)
        a : Cheese(type == s, price == -3)
        not Cheese(type == s, price == -2)
    then
        //apply inverse function
        sum.setPrice(sum.getPrice() - s.length());
modify(sum);
        retract(c);
        retract(a);
        System.err.println("-sum=" + sum);
end

rule "do-something-when-limit-reached"
    when
        Cheese(type == "sum", price > 3)
        not Cheese(type == "limit reached")
    then
        assert(new Cheese("limit reached", -1));
        System.err.println("limit reached");
end

rule "do-something-when-limit-below"
    when
        Cheese(type == "sum", price <= 3)
        c : Cheese(type == "limit reached")
    then
        retract(c);
        System.err.println("limit below");
end




Reply via email to