Help needed - Problems with forall operator

5 messages Options
Embed this post
Permalink
Tom.E.Murphy

Help needed - Problems with forall operator

Reply Threaded More More options
Print post
Permalink
Some javascript/style in this post has been disabled (why?)
I have the following rule:
rule "somerule"
        when
                forall
                (
                        CreditReport( $parentCreditReport_1_Id : myId)
                        FICO( parentId == $parentCreditReport_1_Id, validScoreIndicator == false)
                )
        then
                System.out.print("Fired");
end
 
The meaning of the rule is that if all the FICO scores on the credit report are invalid, then fire the rule.
My data at run time has three FICO objects related to one CreditReport, two of which have validScoreIndicator set to false, and one of which has it set to true.
The rule fires, and I don’t understand why.
Can anyone enlighten me?
 
 
Tom Murphy
Business Process Consultant
Wells Fargo HCFG - CORE Deal Decisioning Platform
800 S. Jordan Creek Parkway | West Des Moines, IA 50266
MAC:
X2301-01B
Office: 515 324 4853 | Mobile: 941 320 8014
This message may contain confidential and/or privileged information.  If you are not the addressee or authorized to receive this for the addressee, you must not use, copy, disclose, or take any action based on this message or any information herein.  If you have received this message in error, please advise the sender immediately by reply e-mail and delete this message.  Thank you for your cooperation.
 
 
 

_______________________________________________
rules-users mailing list
[hidden email]
https://lists.jboss.org/mailman/listinfo/rules-users
Jared Davis

Re: Help needed - Problems with forall operator

Reply Threaded More More options
Print post
Permalink
I think this usage may work for your case.

rule "somerule"
  when
    report: CreditReport( $parentCreditReport_1_Id : myId)
    forall (
      FICO( parentId == $parentCreditReport_1_Id, validScoreIndicator == false)
    )
  then
    System.out.print("Fired on " + $parentCreditReport_1_Id );
end
 


_______________________________________________
rules-users mailing list
[hidden email]
https://lists.jboss.org/mailman/listinfo/rules-users
Wolfgang Laun-2

Re: Help needed - Problems with forall operator

Reply Threaded More More options
Print post
Permalink
Here's the explanation why Tom's version does not work. The first pattern of a "forall" defines the domain, which is: all CreditReport facts; for each object in this domain, the remaining patterns must match; since the FICO pattern merely ascertains the existence of a single FICO chained to a parent CreditReport with validScoreIndicator false, it fires as soon as there is one for each of the existing CreditReports.

Jared's solution has the CreditReport CE in front of the forall, unadorned with any quantifier, and the innate behavior of Drools makes sure that the hole thing will be tried, once, for any existing CreditReport anyway. Then, the forall domain is now FICOs with that CR's id and valid == false - but what is the CE? I guess that Drool's behavior is somewhat off the definition, using just FICO() - i.e., all existing FICO objects - as the domain. (However, I think that Edson changed this recently for 5.1.0.) Thus, Jared's rule indeed fires only when all FICOs are linked to the CreditReport are false, but it fails to do so as soon as there is at least one other FICO with either a different parent, or valid.

Therefore, to be on the safe side with multiple CreditReport facts and assorted FICO's being in WM at the same time, I propose this rule:

rule "somerule2"
when
    report: CreditReport( $parentCreditReport_1_Id : myId)
    forall ( $f : FICO( parentId == $parentCreditReport_1_Id )
             FICO( this == $f, validScoreIndicator == false) )
then
    System.out.println("somerule2 fired on " + $parentCreditReport_1_Id );
end

Here, the domain is explicitly given as all FICOs of the current CR; and for all of them valid must be false.

Still, this solution is not perfect: It would also fire in the absence of any FICO for some CR. To fix this, add a guard against there being no FICOs for the current CR:

report: CreditReport( $parentCreditReport_1_Id : myId)
            exists FICO( parentId == $parentCreditReport_1_Id )
forall ( $f : FICO( parentId == $parentCreditReport_1_Id )
             FICO( this == $f, validScoreIndicator == false) )

To complete the picture, one might equally well use the negation of forall, which would have to be propagated into the predicate (read '|' as "so that"):
    forall x in D | P(x) => not existst x in D | not P(x)

Now the condition delimiting the domain and the negated predicate can be merged again into one CE:

rule "somerule3"
when
    report: CreditReport( $parentCreditReport_1_Id : myId)
    exists FiCo( parentId == $parentCreditReport_1_Id )
    not ( exists FiCo( parentId == $parentCreditReport_1_Id, validScore == true) )
then
    System.out.println("somerule3 fired on " + $parentCreditReport_1_Id );
end

-W

On Fri, Nov 6, 2009 at 9:45 PM, Jared Davis <[hidden email]> wrote:
I think this usage may work for your case.

rule "somerule"
 when
   report: CreditReport( $parentCreditReport_1_Id : myId)
   forall (
     FICO( parentId == $parentCreditReport_1_Id, validScoreIndicator == false)
   )
 then
   System.out.print("Fired on " + $parentCreditReport_1_Id );
end



_______________________________________________
rules-users mailing list
[hidden email]
https://lists.jboss.org/mailman/listinfo/rules-users


_______________________________________________
rules-users mailing list
[hidden email]
https://lists.jboss.org/mailman/listinfo/rules-users
Edson Tirelli-4

Re: Help needed - Problems with forall operator

Reply Threaded More More options
Print post
Permalink

   Yap, Wolfgang has the picture right. Just 2 clarifications:

* A single pattern forall in Drools is a syntax sugar to a multi-pattern forall in the following way:

forall( Pattern( <constraints> ) )
=>
forall( $p : Pattern()
         Pattern( this == $p, <constraints> )

   In other words, drools uses the fact type to define the domain and apply the constraints to all objects in that domain.

* "not" is the quantifier CE that means "not exists". If you explicitly write "not( exists ( ) )", the "exists" is redundant, but not eliminated automatically by Drools yet. So, you are wasting quite a lot of performance, since that forces drools to create a subnetwork in Rete. For Drools 5.1 and forward I will automatically eliminate the exists during the logical transformation step, but up to 5.0.x, you need to do it manually.

    Edson


2009/11/7 Wolfgang Laun <[hidden email]>
Here's the explanation why Tom's version does not work. The first pattern of a "forall" defines the domain, which is: all CreditReport facts; for each object in this domain, the remaining patterns must match; since the FICO pattern merely ascertains the existence of a single FICO chained to a parent CreditReport with validScoreIndicator false, it fires as soon as there is one for each of the existing CreditReports.

Jared's solution has the CreditReport CE in front of the forall, unadorned with any quantifier, and the innate behavior of Drools makes sure that the hole thing will be tried, once, for any existing CreditReport anyway. Then, the forall domain is now FICOs with that CR's id and valid == false - but what is the CE? I guess that Drool's behavior is somewhat off the definition, using just FICO() - i.e., all existing FICO objects - as the domain. (However, I think that Edson changed this recently for 5.1.0.) Thus, Jared's rule indeed fires only when all FICOs are linked to the CreditReport are false, but it fails to do so as soon as there is at least one other FICO with either a different parent, or valid.

Therefore, to be on the safe side with multiple CreditReport facts and assorted FICO's being in WM at the same time, I propose this rule:

rule "somerule2"

when
    report: CreditReport( $parentCreditReport_1_Id : myId)
    forall ( $f : FICO( parentId == $parentCreditReport_1_Id )
             FICO( this == $f, validScoreIndicator == false) )
then
    System.out.println("somerule2 fired on " + $parentCreditReport_1_Id );
end

Here, the domain is explicitly given as all FICOs of the current CR; and for all of them valid must be false.

Still, this solution is not perfect: It would also fire in the absence of any FICO for some CR. To fix this, add a guard against there being no FICOs for the current CR:


report: CreditReport( $parentCreditReport_1_Id : myId)
            exists FICO( parentId == $parentCreditReport_1_Id )
forall ( $f : FICO( parentId == $parentCreditReport_1_Id )
             FICO( this == $f, validScoreIndicator == false) )

To complete the picture, one might equally well use the negation of forall, which would have to be propagated into the predicate (read '|' as "so that"):
    forall x in D | P(x) => not existst x in D | not P(x)

Now the condition delimiting the domain and the negated predicate can be merged again into one CE:

rule "somerule3"

when
    report: CreditReport( $parentCreditReport_1_Id : myId)
    exists FiCo( parentId == $parentCreditReport_1_Id )
    not ( exists FiCo( parentId == $parentCreditReport_1_Id, validScore == true) )
then
    System.out.println("somerule3 fired on " + $parentCreditReport_1_Id );
end

-W


On Fri, Nov 6, 2009 at 9:45 PM, Jared Davis <[hidden email]> wrote:
I think this usage may work for your case.

rule "somerule"
 when
   report: CreditReport( $parentCreditReport_1_Id : myId)
   forall (
     FICO( parentId == $parentCreditReport_1_Id, validScoreIndicator == false)
   )
 then
   System.out.print("Fired on " + $parentCreditReport_1_Id );
end



_______________________________________________
rules-users mailing list
[hidden email]
https://lists.jboss.org/mailman/listinfo/rules-users




--
 Edson Tirelli
 JBoss Drools Core Development
 JBoss by Red Hat @ www.jboss.com

_______________________________________________
rules-users mailing list
[hidden email]
https://lists.jboss.org/mailman/listinfo/rules-users
Tom.E.Murphy

Re: Help needed - Problems with forall operator

Reply Threaded More More options
Print post
Permalink
In reply to this post by Tom.E.Murphy
Thanks, everyone, for your insightful responses. You've made my day...

Tom Murphy
Business Process Consultant
Wells Fargo HCFG - CORE Deal Decisioning Platform
800 S. Jordan Creek Parkway | West Des Moines, IA 50266
MAC: X2301-01B
Office: 515 324 4853 | Mobile: 941 320 8014
This message may contain confidential and/or privileged information.  If you are not the addressee or authorized to receive this for the addressee, you must not use, copy, disclose, or take any action based on this message or any information herein.  If you have received this message in error, please advise the sender immediately by reply e-mail and delete this message.  Thank you for your cooperation.

----------------------------------------------------------------------

Message: 1
Date: Sat, 7 Nov 2009 09:55:37 +0100
From: Wolfgang Laun <[hidden email]>
Subject: Re: [rules-users] Help needed - Problems with forall operator
To: Rules Users List <[hidden email]>,
        [hidden email]
Message-ID:
        <[hidden email]>
Content-Type: text/plain; charset="iso-8859-1"

Here's the explanation why Tom's version does not work. The first pattern of
a "forall" defines the domain, which is: all CreditReport facts; for each
object in this domain, the remaining patterns must match; since the FICO
pattern merely ascertains the existence of a single FICO chained to a parent
CreditReport with validScoreIndicator false, it fires as soon as there is
one for each of the existing CreditReports.

Jared's solution has the CreditReport CE in front of the forall, unadorned
with any quantifier, and the innate behavior of Drools makes sure that the
hole thing will be tried, once, for any existing CreditReport anyway. Then,
the forall domain is now FICOs with that CR's id and valid == false - but
what is the CE? I guess that Drool's behavior is somewhat off the
definition, using just FICO() - i.e., all existing FICO objects - as the
domain. (However, I think that Edson changed this recently for 5.1.0.) Thus,
Jared's rule indeed fires only when all FICOs are linked to the CreditReport
are false, but it fails to do so as soon as there is at least one other FICO
with either a different parent, or valid.

Therefore, to be on the safe side with multiple CreditReport facts and
assorted FICO's being in WM at the same time, I propose this rule:

rule "somerule2"
when
    report: CreditReport( $parentCreditReport_1_Id : myId)
    forall ( $f : FICO( parentId == $parentCreditReport_1_Id )
             FICO( this == $f, validScoreIndicator == false) )
then
    System.out.println("somerule2 fired on " + $parentCreditReport_1_Id );
end

Here, the domain is explicitly given as all FICOs of the current CR; and for
all of them valid must be false.

Still, this solution is not perfect: It would also fire in the absence of
any FICO for some CR. To fix this, add a guard against there being no FICOs
for the current CR:

report: CreditReport( $parentCreditReport_1_Id : myId)
            exists FICO( parentId == $parentCreditReport_1_Id )
forall ( $f : FICO( parentId == $parentCreditReport_1_Id )
             FICO( this == $f, validScoreIndicator == false) )

To complete the picture, one might equally well use the negation of forall,
which would have to be propagated into the predicate (read '|' as "so
that"):
    forall x in D | P(x) => not existst x in D | not P(x)

Now the condition delimiting the domain and the negated predicate can be
merged again into one CE:

rule "somerule3"
when
    report: CreditReport( $parentCreditReport_1_Id : myId)
    exists FiCo( parentId == $parentCreditReport_1_Id )
    not ( exists FiCo( parentId == $parentCreditReport_1_Id, validScore ==
true) )
then
    System.out.println("somerule3 fired on " + $parentCreditReport_1_Id );
end

-W

On Fri, Nov 6, 2009 at 9:45 PM, Jared Davis <[hidden email]>wrote:

> I think this usage may work for your case.
>
> rule "somerule"
>  when
>    report: CreditReport( $parentCreditReport_1_Id : myId)
>    forall (
>       FICO( parentId == $parentCreditReport_1_Id, validScoreIndicator ==
> false)
>    )
>  then
>     System.out.print("Fired on " + $parentCreditReport_1_Id );
> end
>
>
>
> _______________________________________________
> rules-users mailing list
> [hidden email]
> https://lists.jboss.org/mailman/listinfo/rules-users
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.jboss.org/pipermail/rules-users/attachments/20091107/9bc576d5/attachment-0001.html 

_______________________________________________
rules-users mailing list
[hidden email]
https://lists.jboss.org/mailman/listinfo/rules-users