JESS: Re: calculating benefit costs

classic Classic list List threaded Threaded
15 messages Options
Reply | Threaded
Open this post in threaded view
|

JESS: Re: calculating benefit costs

Wolfgang Laun-2
This additional information does not require a fundamentally different approach.

Using the same set of facts CostEmployee/CostSpouse, we can now use
two rules, one calculating the cost for the employee, and the other
one for the spouse.

(defrule calc-self
  ?hbj <- (HrBenefitJoin (hrBenefitConfigId "00001-0000000073")
                 (calculatedCost 0)
                 {relationshipId  == nil}
                 (payingPersonId  ?pPer)
                 (coveredPersonId ?cPer) )
  (Person        (personId        ?cPer) (dob ?dob) )
  (CostEmployee  (lo ?lo&:(<= ?lo (yrs ?dob)))
                 (hi ?hi&:(>= ?hi (yrs ?dob)))(cost ?cost))
=>
  (printout t "Cost for " ?cPer " paid by himself: " ?cost crlf )
)

(defrule calc-other
  ?hbj <- (HrBenefitJoin (hrBenefitConfigId "00001-0000000073")
                 (calculatedCost 0)
                 {relationshipId  != nil}
                 (payingPersonId  ?pPer)
                 (coveredPersonId ?cPer) )
  (Person        (personId        ?cPer) (dob ?dob) )
  (CostSpouse    (lo ?lo&:(<= ?lo (yrs ?dob)))
                 (hi ?hi&:(>= ?hi (yrs ?dob)))(cost ?cost))
=>
  (printout t "Cost for " ?cPer " paid by " ?pPer ": " ?cost crlf )
)

The date calculation is abstracted into a
   (deffunction yrs (?dob) ... (return ?yrs) )

Implementing this in Jess or in Java is a simple programming exercise,
but it presumably it depends on some technical/legal issues, e.g., it
may not be possible to use "today" as a basis for calculating the
difference in years from the person's dob.

Since there's no information what to do with the resulting cost, it's
just printed to standard output, but updating slot calculatedCost in
HrBenefitJoin is straightforward.

Cheers
Wolfgang


On 05/01/2011, Derek Adams <[hidden email]> wrote:

> the facts that I am working with are:
>
> (HrBenefitJoin (hrBenefitConfigId "00001-0000000073")(benefitJoinId
> ?bjid)(calculatedCost ?cost)(OBJECT ?obj)(coveredPersonId
> ?cPer)(payingPersonId ?pPer)(relationshipId ?rel))
> (Person (personId ?cPer)(dob ?dob)(OBJECT ?objP))
>
> ?rel is what identifies the "covered person" as spouse or employee.  If ?rel
> is nil, it's employee, else it's spouse.
>
> So ?objP is my covered person (either spouse or employee).
>
> On Wed, Jan 5, 2011 at 3:36 PM, Wolfgang Laun
> <[hidden email]>wrote:
>
>> With this kind of problem, there are (at least) two approaches. Given that
>> Employee and Spouse are represented as facts:
>>    (deftemplate Spouse   (slot name)(slot age))
>>    (deftemplate Employee (slot name)(slot age)(slot spouse))
>>
>>    (deffacts test-facts
>>       (Employee (name "John Smith")(age 35)(spouse "Jane Smith"))
>>       (Spouse   (name "Jane Smith")(age 28))
>>       (Employee (name "Honey Rider")(age 39)(spouse "James Rider"))
>>       (Spouse   (name "James Rider")(age 45))
>>    )
>>
>> (1) You can write one rule for each possible combination of age brackets.
>>
>> (defrule compute_1_1
>>     (Employee (name ?name){age >= 18 && age <= 29}(spouse ?spouse))
>>     (Spouse   {name == ?spouse}{age >= 18 && age <= 29})
>> =>
>>     (printout t "cost " ?name " " (+  11.55 6.65) crlf)
>> )
>> ... more boring code ...
>> (defrule compute_3_3
>>     (Employee (name ?name){age >= 40 && age <= 49}(spouse ?spouse))
>>     (Spouse   {name == ?spouse}{age >= 40 && age <= 49})
>> =>
>>     (printout t "cost " ?name " " (+  38.35 20.05) crlf)
>> )
>>
>> (2) You can represent the tables for the costs as facts:
>>    (deftemplate CostEmployee (slot lo)(slot hi)(slot cost))
>>    (deftemplate CostSpouse   (slot lo)(slot hi)(slot cost))
>>
>>    (deffacts costs
>>        (CostEmployee (lo 18)(hi 29)(cost 11.55))
>>        (CostEmployee (lo 30)(hi 39)(cost 18.95))
>>        (CostEmployee (lo 40)(hi 49)(cost 38.35))
>>        (CostSpouse   (lo 18)(hi 29)(cost  6.65))
>>        (CostSpouse   (lo 30)(hi 39)(cost 10.35))
>>        (CostSpouse   (lo 40)(hi 49)(cost 20.05))
>>    )
>>
>> and use a single rule:
>>
>>    (defrule compute
>>        (Employee (name ?name)(age ?ageE)(spouse ?spouse))
>>        (Spouse   {name == ?spouse}(age ?ageS))
>>        (CostEmployee {lo <= ?ageE}{hi >= ?ageE}(cost ?costE))
>>        (CostSpouse   {lo <= ?ageS}{hi >= ?ageS}(cost ?costS))
>>    =>
>>        (printout t "cost " ?name " " (+  ?costE ?costS) crlf)
>>    )
>>
>> HTH
>> Wolfgang
>>
>>
>>
>>
>>
>> On 5 January 2011 22:30, Wolfgang Laun <[hidden email]> wrote:
>>
>>> Sent on behalf of Derek Adams:
>>>
>>>
>>> Hey Jess Users!  This is my first post, so I apologize for anything
>>> "noob"
>>> that I say/do...
>>>
>>> I'm very new to Jess.  I understand the basics but applying my knowledge
>>> for the first time is proving more difficult than I anticipated.  Here is
>>> the problem:
>>>
>>> I need to set up a rule in Jess that calculates the cost of a benefit
>>> based on age and enrollees.
>>> *
>>> Example:
>>> The Benefit Configuration is "Employee $10k / Spouse $5k"
>>> The enrollees are the employee (John Smith age 30) and spouse (Jane Smith
>>> and 28).
>>> The costs are calculated as follows:
>>>
>>> Age               Employee            Spouse
>>> 18-29            11.55                    6.65
>>> 30-39            18.95                   10.35
>>> 40-49            38.35                   20.05*
>>>
>>> *So John's cost is 18.95 and Jane's cost is 6.65 for a total of 25.60*.
>>>
>>> Any advice would be greatly appreciated!
>>>
>>> Thanks,
>>>
>>> Derek Adams
>>>
>>
>>
>
>
> --
> *Derek Adams*
> Lead Developer
> Arahant LLC
> Work: 615-376-5500 ext. 314
> Cell: 270-543-0920
>


--------------------------------------------------------------------
To unsubscribe, send the words 'unsubscribe jess-users [hidden email]'
in the BODY of a message to [hidden email], NOT to the list
(use your own address!) List problems? Notify [hidden email].
--------------------------------------------------------------------

Reply | Threaded
Open this post in threaded view
|

Re: JESS: Re: calculating benefit costs

Derek Adams
Thanks for the help guys.  Here is what I ended up with.  This works, but I'm sure it's not the most efficient way to solve the problem.

(defrule setCalculatedCostGCI20k5k
    (HrBenefitJoin (hrBenefitConfigId "00001-0000000076")(benefitJoinId ?bjid)(calculatedCost ?cost)(OBJECT ?obj)(coveredPersonId ?cPer)(payingPersonId ?pPer)(relationshipId ?rel))
    (Person (personId ?cPer)(dob ?dob)(OBJECT ?objP))
=>
    (printout t "age = " (call ?objP calcAgeAsOf(call com.arahant.utils.DateUtils now )) " for " ?bjid " " crlf)

    (if (eq ?rel nil) then
        (if (< (call ?objP calcAgeAsOf(call com.arahant.utils.DateUtils now )) 30) then
            (call ?obj overrideAgeCost 11.55)
         else (if (< (call ?objP calcAgeAsOf(call com.arahant.utils.DateUtils now )) 40) then
                (call ?obj overrideAgeCost 18.95)
              else (if (< (call ?objP calcAgeAsOf(call com.arahant.utils.DateUtils now )) 50) then
                    (call ?obj overrideAgeCost 38.35)
                    else (if (< (call ?objP calcAgeAsOf(call com.arahant.utils.DateUtils now )) 60) then
                        (call ?obj overrideAgeCost 65.95)
                          else (if (< (call ?objP calcAgeAsOf(call com.arahant.utils.DateUtils now )) 70) then
                                    (call ?obj overrideAgeCost 104.35)
                                else
                                    (printout t "age greater than 69 ... " (call ?objP calcAgeAsOf(call com.arahant.utils.DateUtils now )) " for " ?bjid " " crlf))))))
     else (if (neq ?rel nil) then
                (if (< (call ?objP calcAgeAsOf(call com.arahant.utils.DateUtils now )) 30) then
                    (call ?obj overrideAgeCost 4.20)
                 else (if (< (call ?objP calcAgeAsOf(call com.arahant.utils.DateUtils now )) 40) then
                        (call ?obj overrideAgeCost 6.05)
                      else (if (< (call ?objP calcAgeAsOf(call com.arahant.utils.DateUtils now )) 50) then
                            (call ?obj overrideAgeCost 10.90)
                            else (if (< (call ?objP calcAgeAsOf(call com.arahant.utils.DateUtils now )) 60) then
                                (call ?obj overrideAgeCost 17.80)
                                  else (if (< (call ?objP calcAgeAsOf(call com.arahant.utils.DateUtils now )) 70) then
                                            (call ?obj overrideAgeCost 27.40)
                                        else
                                            (printout t "age greater than 69 ... " (call ?objP calcAgeAsOf(call com.arahant.utils.DateUtils now )) " for " ?bjid " " crlf))))))))
    (printout t "setCalculatedCostGCI function fired for " ?bjid ". overrideAgeCost =  " (call ?obj overrideAgeCost) crlf)
;    (printout t "setCalculatedCostGCI function fired for " ?bjid " " crlf)

)

On Thu, Jan 6, 2011 at 10:32 AM, Wolfgang Laun <[hidden email]> wrote:
This additional information does not require a fundamentally different approach.

Using the same set of facts CostEmployee/CostSpouse, we can now use
two rules, one calculating the cost for the employee, and the other
one for the spouse.

(defrule calc-self
 ?hbj <- (HrBenefitJoin (hrBenefitConfigId "00001-0000000073")
                (calculatedCost 0)
                {relationshipId  == nil}
                (payingPersonId  ?pPer)
                (coveredPersonId ?cPer) )
 (Person        (personId        ?cPer) (dob ?dob) )
 (CostEmployee  (lo ?lo&:(<= ?lo (yrs ?dob)))
                (hi ?hi&:(>= ?hi (yrs ?dob)))(cost ?cost))
=>
 (printout t "Cost for " ?cPer " paid by himself: " ?cost crlf )
)

(defrule calc-other
 ?hbj <- (HrBenefitJoin (hrBenefitConfigId "00001-0000000073")
                (calculatedCost 0)
                {relationshipId  != nil}
                (payingPersonId  ?pPer)
                (coveredPersonId ?cPer) )
 (Person        (personId        ?cPer) (dob ?dob) )
 (CostSpouse    (lo ?lo&:(<= ?lo (yrs ?dob)))
                (hi ?hi&:(>= ?hi (yrs ?dob)))(cost ?cost))
=>
 (printout t "Cost for " ?cPer " paid by " ?pPer ": " ?cost crlf )
)

The date calculation is abstracted into a
  (deffunction yrs (?dob) ... (return ?yrs) )

Implementing this in Jess or in Java is a simple programming exercise,
but it presumably it depends on some technical/legal issues, e.g., it
may not be possible to use "today" as a basis for calculating the
difference in years from the person's dob.

Since there's no information what to do with the resulting cost, it's
just printed to standard output, but updating slot calculatedCost in
HrBenefitJoin is straightforward.

Cheers
Wolfgang


On 05/01/2011, Derek Adams <[hidden email]> wrote:
> the facts that I am working with are:
>
> (HrBenefitJoin (hrBenefitConfigId "00001-0000000073")(benefitJoinId
> ?bjid)(calculatedCost ?cost)(OBJECT ?obj)(coveredPersonId
> ?cPer)(payingPersonId ?pPer)(relationshipId ?rel))
> (Person (personId ?cPer)(dob ?dob)(OBJECT ?objP))
>
> ?rel is what identifies the "covered person" as spouse or employee.  If ?rel
> is nil, it's employee, else it's spouse.
>
> So ?objP is my covered person (either spouse or employee).
>
> On Wed, Jan 5, 2011 at 3:36 PM, Wolfgang Laun
> <[hidden email]>wrote:
>
>> With this kind of problem, there are (at least) two approaches. Given that
>> Employee and Spouse are represented as facts:
>>    (deftemplate Spouse   (slot name)(slot age))
>>    (deftemplate Employee (slot name)(slot age)(slot spouse))
>>
>>    (deffacts test-facts
>>       (Employee (name "John Smith")(age 35)(spouse "Jane Smith"))
>>       (Spouse   (name "Jane Smith")(age 28))
>>       (Employee (name "Honey Rider")(age 39)(spouse "James Rider"))
>>       (Spouse   (name "James Rider")(age 45))
>>    )
>>
>> (1) You can write one rule for each possible combination of age brackets.
>>
>> (defrule compute_1_1
>>     (Employee (name ?name){age >= 18 && age <= 29}(spouse ?spouse))
>>     (Spouse   {name == ?spouse}{age >= 18 && age <= 29})
>> =>
>>     (printout t "cost " ?name " " (+  11.55 6.65) crlf)
>> )
>> ... more boring code ...
>> (defrule compute_3_3
>>     (Employee (name ?name){age >= 40 && age <= 49}(spouse ?spouse))
>>     (Spouse   {name == ?spouse}{age >= 40 && age <= 49})
>> =>
>>     (printout t "cost " ?name " " (+  38.35 20.05) crlf)
>> )
>>
>> (2) You can represent the tables for the costs as facts:
>>    (deftemplate CostEmployee (slot lo)(slot hi)(slot cost))
>>    (deftemplate CostSpouse   (slot lo)(slot hi)(slot cost))
>>
>>    (deffacts costs
>>        (CostEmployee (lo 18)(hi 29)(cost 11.55))
>>        (CostEmployee (lo 30)(hi 39)(cost 18.95))
>>        (CostEmployee (lo 40)(hi 49)(cost 38.35))
>>        (CostSpouse   (lo 18)(hi 29)(cost  6.65))
>>        (CostSpouse   (lo 30)(hi 39)(cost 10.35))
>>        (CostSpouse   (lo 40)(hi 49)(cost 20.05))
>>    )
>>
>> and use a single rule:
>>
>>    (defrule compute
>>        (Employee (name ?name)(age ?ageE)(spouse ?spouse))
>>        (Spouse   {name == ?spouse}(age ?ageS))
>>        (CostEmployee {lo <= ?ageE}{hi >= ?ageE}(cost ?costE))
>>        (CostSpouse   {lo <= ?ageS}{hi >= ?ageS}(cost ?costS))
>>    =>
>>        (printout t "cost " ?name " " (+  ?costE ?costS) crlf)
>>    )
>>
>> HTH
>> Wolfgang
>>
>>
>>
>>
>>
>> On 5 January 2011 22:30, Wolfgang Laun <[hidden email]> wrote:
>>
>>> Sent on behalf of Derek Adams:
>>>
>>>
>>> Hey Jess Users!  This is my first post, so I apologize for anything
>>> "noob"
>>> that I say/do...
>>>
>>> I'm very new to Jess.  I understand the basics but applying my knowledge
>>> for the first time is proving more difficult than I anticipated.  Here is
>>> the problem:
>>>
>>> I need to set up a rule in Jess that calculates the cost of a benefit
>>> based on age and enrollees.
>>> *
>>> Example:
>>> The Benefit Configuration is "Employee $10k / Spouse $5k"
>>> The enrollees are the employee (John Smith age 30) and spouse (Jane Smith
>>> and 28).
>>> The costs are calculated as follows:
>>>
>>> Age               Employee            Spouse
>>> 18-29            11.55                    6.65
>>> 30-39            18.95                   10.35
>>> 40-49            38.35                   20.05*
>>>
>>> *So John's cost is 18.95 and Jane's cost is 6.65 for a total of 25.60*.
>>>
>>> Any advice would be greatly appreciated!
>>>
>>> Thanks,
>>>
>>> Derek Adams
>>>
>>
>>
>
>
> --
> *Derek Adams*
> Lead Developer
> Arahant LLC
> Work: 615-376-5500 ext. 314
> Cell: 270-543-0920
>


--------------------------------------------------------------------
To unsubscribe, send the words 'unsubscribe jess-users [hidden email]'
in the BODY of a message to [hidden email], NOT to the list
(use your own address!) List problems? Notify [hidden email].
--------------------------------------------------------------------




--
Derek Adams
Lead Developer
Arahant LLC
Work: 615-376-5500 ext. 314
Cell: 270-543-0920
Reply | Threaded
Open this post in threaded view
|

Re: JESS: Re: calculating benefit costs

Donald Winston
So many if else statements on the RHS is "unruly". 

On Jan 7, 2011, at 9:15 AM, Derek Adams wrote:

Thanks for the help guys.  Here is what I ended up with.  This works, but I'm sure it's not the most efficient way to solve the problem.

(defrule setCalculatedCostGCI20k5k
    (HrBenefitJoin (hrBenefitConfigId "00001-0000000076")(benefitJoinId ?bjid)(calculatedCost ?cost)(OBJECT ?obj)(coveredPersonId ?cPer)(payingPersonId ?pPer)(relationshipId ?rel))
    (Person (personId ?cPer)(dob ?dob)(OBJECT ?objP))
=>
    (printout t "age = " (call ?objP calcAgeAsOf(call com.arahant.utils.DateUtils now )) " for " ?bjid " " crlf)

    (if (eq ?rel nil) then
        (if (< (call ?objP calcAgeAsOf(call com.arahant.utils.DateUtils now )) 30) then
            (call ?obj overrideAgeCost 11.55)
         else (if (< (call ?objP calcAgeAsOf(call com.arahant.utils.DateUtils now )) 40) then
                (call ?obj overrideAgeCost 18.95)
              else (if (< (call ?objP calcAgeAsOf(call com.arahant.utils.DateUtils now )) 50) then
                    (call ?obj overrideAgeCost 38.35)
                    else (if (< (call ?objP calcAgeAsOf(call com.arahant.utils.DateUtils now )) 60) then
                        (call ?obj overrideAgeCost 65.95)
                          else (if (< (call ?objP calcAgeAsOf(call com.arahant.utils.DateUtils now )) 70) then
                                    (call ?obj overrideAgeCost 104.35)
                                else
                                    (printout t "age greater than 69 ... " (call ?objP calcAgeAsOf(call com.arahant.utils.DateUtils now )) " for " ?bjid " " crlf))))))
     else (if (neq ?rel nil) then
                (if (< (call ?objP calcAgeAsOf(call com.arahant.utils.DateUtils now )) 30) then
                    (call ?obj overrideAgeCost 4.20)
                 else (if (< (call ?objP calcAgeAsOf(call com.arahant.utils.DateUtils now )) 40) then
                        (call ?obj overrideAgeCost 6.05)
                      else (if (< (call ?objP calcAgeAsOf(call com.arahant.utils.DateUtils now )) 50) then
                            (call ?obj overrideAgeCost 10.90)
                            else (if (< (call ?objP calcAgeAsOf(call com.arahant.utils.DateUtils now )) 60) then
                                (call ?obj overrideAgeCost 17.80)
                                  else (if (< (call ?objP calcAgeAsOf(call com.arahant.utils.DateUtils now )) 70) then
                                            (call ?obj overrideAgeCost 27.40)
                                        else
                                            (printout t "age greater than 69 ... " (call ?objP calcAgeAsOf(call com.arahant.utils.DateUtils now )) " for " ?bjid " " crlf))))))))
    (printout t "setCalculatedCostGCI function fired for " ?bjid ". overrideAgeCost =  " (call ?obj overrideAgeCost) crlf)
;    (printout t "setCalculatedCostGCI function fired for " ?bjid " " crlf)

)

On Thu, Jan 6, 2011 at 10:32 AM, Wolfgang Laun <[hidden email]> wrote:
This additional information does not require a fundamentally different approach.

Using the same set of facts CostEmployee/CostSpouse, we can now use
two rules, one calculating the cost for the employee, and the other
one for the spouse.

(defrule calc-self
 ?hbj <- (HrBenefitJoin (hrBenefitConfigId "00001-0000000073")
                (calculatedCost 0)
                {relationshipId  == nil}
                (payingPersonId  ?pPer)
                (coveredPersonId ?cPer) )
 (Person        (personId        ?cPer) (dob ?dob) )
 (CostEmployee  (lo ?lo&:(<= ?lo (yrs ?dob)))
                (hi ?hi&:(>= ?hi (yrs ?dob)))(cost ?cost))
=>
 (printout t "Cost for " ?cPer " paid by himself: " ?cost crlf )
)

(defrule calc-other
 ?hbj <- (HrBenefitJoin (hrBenefitConfigId "00001-0000000073")
                (calculatedCost 0)
                {relationshipId  != nil}
                (payingPersonId  ?pPer)
                (coveredPersonId ?cPer) )
 (Person        (personId        ?cPer) (dob ?dob) )
 (CostSpouse    (lo ?lo&:(<= ?lo (yrs ?dob)))
                (hi ?hi&:(>= ?hi (yrs ?dob)))(cost ?cost))
=>
 (printout t "Cost for " ?cPer " paid by " ?pPer ": " ?cost crlf )
)

The date calculation is abstracted into a
  (deffunction yrs (?dob) ... (return ?yrs) )

Implementing this in Jess or in Java is a simple programming exercise,
but it presumably it depends on some technical/legal issues, e.g., it
may not be possible to use "today" as a basis for calculating the
difference in years from the person's dob.

Since there's no information what to do with the resulting cost, it's
just printed to standard output, but updating slot calculatedCost in
HrBenefitJoin is straightforward.

Cheers
Wolfgang


On 05/01/2011, Derek Adams <[hidden email]> wrote:
> the facts that I am working with are:
>
> (HrBenefitJoin (hrBenefitConfigId "00001-0000000073")(benefitJoinId
> ?bjid)(calculatedCost ?cost)(OBJECT ?obj)(coveredPersonId
> ?cPer)(payingPersonId ?pPer)(relationshipId ?rel))
> (Person (personId ?cPer)(dob ?dob)(OBJECT ?objP))
>
> ?rel is what identifies the "covered person" as spouse or employee.  If ?rel
> is nil, it's employee, else it's spouse.
>
> So ?objP is my covered person (either spouse or employee).
>
> On Wed, Jan 5, 2011 at 3:36 PM, Wolfgang Laun
> <[hidden email]>wrote:
>
>> With this kind of problem, there are (at least) two approaches. Given that
>> Employee and Spouse are represented as facts:
>>    (deftemplate Spouse   (slot name)(slot age))
>>    (deftemplate Employee (slot name)(slot age)(slot spouse))
>>
>>    (deffacts test-facts
>>       (Employee (name "John Smith")(age 35)(spouse "Jane Smith"))
>>       (Spouse   (name "Jane Smith")(age 28))
>>       (Employee (name "Honey Rider")(age 39)(spouse "James Rider"))
>>       (Spouse   (name "James Rider")(age 45))
>>    )
>>
>> (1) You can write one rule for each possible combination of age brackets.
>>
>> (defrule compute_1_1
>>     (Employee (name ?name){age >= 18 && age <= 29}(spouse ?spouse))
>>     (Spouse   {name == ?spouse}{age >= 18 && age <= 29})
>> =>
>>     (printout t "cost " ?name " " (+  11.55 6.65) crlf)
>> )
>> ... more boring code ...
>> (defrule compute_3_3
>>     (Employee (name ?name){age >= 40 && age <= 49}(spouse ?spouse))
>>     (Spouse   {name == ?spouse}{age >= 40 && age <= 49})
>> =>
>>     (printout t "cost " ?name " " (+  38.35 20.05) crlf)
>> )
>>
>> (2) You can represent the tables for the costs as facts:
>>    (deftemplate CostEmployee (slot lo)(slot hi)(slot cost))
>>    (deftemplate CostSpouse   (slot lo)(slot hi)(slot cost))
>>
>>    (deffacts costs
>>        (CostEmployee (lo 18)(hi 29)(cost 11.55))
>>        (CostEmployee (lo 30)(hi 39)(cost 18.95))
>>        (CostEmployee (lo 40)(hi 49)(cost 38.35))
>>        (CostSpouse   (lo 18)(hi 29)(cost  6.65))
>>        (CostSpouse   (lo 30)(hi 39)(cost 10.35))
>>        (CostSpouse   (lo 40)(hi 49)(cost 20.05))
>>    )
>>
>> and use a single rule:
>>
>>    (defrule compute
>>        (Employee (name ?name)(age ?ageE)(spouse ?spouse))
>>        (Spouse   {name == ?spouse}(age ?ageS))
>>        (CostEmployee {lo <= ?ageE}{hi >= ?ageE}(cost ?costE))
>>        (CostSpouse   {lo <= ?ageS}{hi >= ?ageS}(cost ?costS))
>>    =>
>>        (printout t "cost " ?name " " (+  ?costE ?costS) crlf)
>>    )
>>
>> HTH
>> Wolfgang
>>
>>
>>
>>
>>
>> On 5 January 2011 22:30, Wolfgang Laun <[hidden email]> wrote:
>>
>>> Sent on behalf of Derek Adams:
>>>
>>>
>>> Hey Jess Users!  This is my first post, so I apologize for anything
>>> "noob"
>>> that I say/do...
>>>
>>> I'm very new to Jess.  I understand the basics but applying my knowledge
>>> for the first time is proving more difficult than I anticipated.  Here is
>>> the problem:
>>>
>>> I need to set up a rule in Jess that calculates the cost of a benefit
>>> based on age and enrollees.
>>> *
>>> Example:
>>> The Benefit Configuration is "Employee $10k / Spouse $5k"
>>> The enrollees are the employee (John Smith age 30) and spouse (Jane Smith
>>> and 28).
>>> The costs are calculated as follows:
>>>
>>> Age               Employee            Spouse
>>> 18-29            11.55                    6.65
>>> 30-39            18.95                   10.35
>>> 40-49            38.35                   20.05*
>>>
>>> *So John's cost is 18.95 and Jane's cost is 6.65 for a total of 25.60*.
>>>
>>> Any advice would be greatly appreciated!
>>>
>>> Thanks,
>>>
>>> Derek Adams
>>>
>>
>>
>
>
> --
> *Derek Adams*
> Lead Developer
> Arahant LLC
> Work: 615-376-5500 ext. 314
> Cell: 270-543-0920
>


--------------------------------------------------------------------
To unsubscribe, send the words 'unsubscribe jess-users [hidden email]'
in the BODY of a message to [hidden email], NOT to the list
(use your own address!) List problems? Notify [hidden email].
--------------------------------------------------------------------




--
Derek Adams
Lead Developer
Arahant LLC
Work: 615-376-5500 ext. 314
Cell: 270-543-0920

Reply | Threaded
Open this post in threaded view
|

Re: JESS: Re: calculating benefit costs

James Owen-3
In reply to this post by Derek Adams
Although most folks won't complain, my only comment here is that the logic is all contained in the action side (RHS) of the rule in the form of if-then-else statements (basic Java) followed by more if-then-else (more basic Java) statements.  This is basically procedural code put into a rulebase in a procedural manner.  This begs the question, "Is a rulebase actually needed for this problem?"  Not the way is has been solved here.  

I kind of like Wolfgang's original solution on 5 Jan which would be more of a rulebase approach and would make maintenance at a later date much easier.  Yes, it has more rules (which is the object of a rulebase), BUT the logic is properly defined on the LHS where it belongs and each rule is independently incremental as it should be.  Also, using the rulebase approach would allow expansion of the basic problem into more complex problems later on.
 

SDG
jco


On Jan 7, 2011, at 8:15 AM, Derek Adams wrote:

Thanks for the help guys.  Here is what I ended up with.  This works, but I'm sure it's not the most efficient way to solve the problem.

(defrule setCalculatedCostGCI20k5k
    (HrBenefitJoin (hrBenefitConfigId "00001-0000000076")(benefitJoinId ?bjid)(calculatedCost ?cost)(OBJECT ?obj)(coveredPersonId ?cPer)(payingPersonId ?pPer)(relationshipId ?rel))
    (Person (personId ?cPer)(dob ?dob)(OBJECT ?objP))
=>
    (printout t "age = " (call ?objP calcAgeAsOf(call com.arahant.utils.DateUtils now )) " for " ?bjid " " crlf)

    (if (eq ?rel nil) then
        (if (< (call ?objP calcAgeAsOf(call com.arahant.utils.DateUtils now )) 30) then
            (call ?obj overrideAgeCost 11.55)
         else (if (< (call ?objP calcAgeAsOf(call com.arahant.utils.DateUtils now )) 40) then
                (call ?obj overrideAgeCost 18.95)
              else (if (< (call ?objP calcAgeAsOf(call com.arahant.utils.DateUtils now )) 50) then
                    (call ?obj overrideAgeCost 38.35)
                    else (if (< (call ?objP calcAgeAsOf(call com.arahant.utils.DateUtils now )) 60) then
                        (call ?obj overrideAgeCost 65.95)
                          else (if (< (call ?objP calcAgeAsOf(call com.arahant.utils.DateUtils now )) 70) then
                                    (call ?obj overrideAgeCost 104.35)
                                else
                                    (printout t "age greater than 69 ... " (call ?objP calcAgeAsOf(call com.arahant.utils.DateUtils now )) " for " ?bjid " " crlf))))))
     else (if (neq ?rel nil) then
                (if (< (call ?objP calcAgeAsOf(call com.arahant.utils.DateUtils now )) 30) then
                    (call ?obj overrideAgeCost 4.20)
                 else (if (< (call ?objP calcAgeAsOf(call com.arahant.utils.DateUtils now )) 40) then
                        (call ?obj overrideAgeCost 6.05)
                      else (if (< (call ?objP calcAgeAsOf(call com.arahant.utils.DateUtils now )) 50) then
                            (call ?obj overrideAgeCost 10.90)
                            else (if (< (call ?objP calcAgeAsOf(call com.arahant.utils.DateUtils now )) 60) then
                                (call ?obj overrideAgeCost 17.80)
                                  else (if (< (call ?objP calcAgeAsOf(call com.arahant.utils.DateUtils now )) 70) then
                                            (call ?obj overrideAgeCost 27.40)
                                        else
                                            (printout t "age greater than 69 ... " (call ?objP calcAgeAsOf(call com.arahant.utils.DateUtils now )) " for " ?bjid " " crlf))))))))
    (printout t "setCalculatedCostGCI function fired for " ?bjid ". overrideAgeCost =  " (call ?obj overrideAgeCost) crlf)
;    (printout t "setCalculatedCostGCI function fired for " ?bjid " " crlf)

)

On Thu, Jan 6, 2011 at 10:32 AM, Wolfgang Laun <[hidden email]> wrote:
This additional information does not require a fundamentally different approach.

Using the same set of facts CostEmployee/CostSpouse, we can now use
two rules, one calculating the cost for the employee, and the other
one for the spouse.

(defrule calc-self
 ?hbj <- (HrBenefitJoin (hrBenefitConfigId "00001-0000000073")
                (calculatedCost 0)
                {relationshipId  == nil}
                (payingPersonId  ?pPer)
                (coveredPersonId ?cPer) )
 (Person        (personId        ?cPer) (dob ?dob) )
 (CostEmployee  (lo ?lo&:(<= ?lo (yrs ?dob)))
                (hi ?hi&:(>= ?hi (yrs ?dob)))(cost ?cost))
=>
 (printout t "Cost for " ?cPer " paid by himself: " ?cost crlf )
)

(defrule calc-other
 ?hbj <- (HrBenefitJoin (hrBenefitConfigId "00001-0000000073")
                (calculatedCost 0)
                {relationshipId  != nil}
                (payingPersonId  ?pPer)
                (coveredPersonId ?cPer) )
 (Person        (personId        ?cPer) (dob ?dob) )
 (CostSpouse    (lo ?lo&:(<= ?lo (yrs ?dob)))
                (hi ?hi&:(>= ?hi (yrs ?dob)))(cost ?cost))
=>
 (printout t "Cost for " ?cPer " paid by " ?pPer ": " ?cost crlf )
)

The date calculation is abstracted into a
  (deffunction yrs (?dob) ... (return ?yrs) )

Implementing this in Jess or in Java is a simple programming exercise,
but it presumably it depends on some technical/legal issues, e.g., it
may not be possible to use "today" as a basis for calculating the
difference in years from the person's dob.

Since there's no information what to do with the resulting cost, it's
just printed to standard output, but updating slot calculatedCost in
HrBenefitJoin is straightforward.

Cheers
Wolfgang


On 05/01/2011, Derek Adams <[hidden email]> wrote:
> the facts that I am working with are:
>
> (HrBenefitJoin (hrBenefitConfigId "00001-0000000073")(benefitJoinId
> ?bjid)(calculatedCost ?cost)(OBJECT ?obj)(coveredPersonId
> ?cPer)(payingPersonId ?pPer)(relationshipId ?rel))
> (Person (personId ?cPer)(dob ?dob)(OBJECT ?objP))
>
> ?rel is what identifies the "covered person" as spouse or employee.  If ?rel
> is nil, it's employee, else it's spouse.
>
> So ?objP is my covered person (either spouse or employee).
>
> On Wed, Jan 5, 2011 at 3:36 PM, Wolfgang Laun
> <[hidden email]>wrote:
>
>> With this kind of problem, there are (at least) two approaches. Given that
>> Employee and Spouse are represented as facts:
>>    (deftemplate Spouse   (slot name)(slot age))
>>    (deftemplate Employee (slot name)(slot age)(slot spouse))
>>
>>    (deffacts test-facts
>>       (Employee (name "John Smith")(age 35)(spouse "Jane Smith"))
>>       (Spouse   (name "Jane Smith")(age 28))
>>       (Employee (name "Honey Rider")(age 39)(spouse "James Rider"))
>>       (Spouse   (name "James Rider")(age 45))
>>    )
>>
>> (1) You can write one rule for each possible combination of age brackets.
>>
>> (defrule compute_1_1
>>     (Employee (name ?name){age >= 18 && age <= 29}(spouse ?spouse))
>>     (Spouse   {name == ?spouse}{age >= 18 && age <= 29})
>> =>
>>     (printout t "cost " ?name " " (+  11.55 6.65) crlf)
>> )
>> ... more boring code ...
>> (defrule compute_3_3
>>     (Employee (name ?name){age >= 40 && age <= 49}(spouse ?spouse))
>>     (Spouse   {name == ?spouse}{age >= 40 && age <= 49})
>> =>
>>     (printout t "cost " ?name " " (+  38.35 20.05) crlf)
>> )
>>
>> (2) You can represent the tables for the costs as facts:
>>    (deftemplate CostEmployee (slot lo)(slot hi)(slot cost))
>>    (deftemplate CostSpouse   (slot lo)(slot hi)(slot cost))
>>
>>    (deffacts costs
>>        (CostEmployee (lo 18)(hi 29)(cost 11.55))
>>        (CostEmployee (lo 30)(hi 39)(cost 18.95))
>>        (CostEmployee (lo 40)(hi 49)(cost 38.35))
>>        (CostSpouse   (lo 18)(hi 29)(cost  6.65))
>>        (CostSpouse   (lo 30)(hi 39)(cost 10.35))
>>        (CostSpouse   (lo 40)(hi 49)(cost 20.05))
>>    )
>>
>> and use a single rule:
>>
>>    (defrule compute
>>        (Employee (name ?name)(age ?ageE)(spouse ?spouse))
>>        (Spouse   {name == ?spouse}(age ?ageS))
>>        (CostEmployee {lo <= ?ageE}{hi >= ?ageE}(cost ?costE))
>>        (CostSpouse   {lo <= ?ageS}{hi >= ?ageS}(cost ?costS))
>>    =>
>>        (printout t "cost " ?name " " (+  ?costE ?costS) crlf)
>>    )
>>
>> HTH
>> Wolfgang
>>
>>
>>
>>
>>
>> On 5 January 2011 22:30, Wolfgang Laun <[hidden email]> wrote:
>>
>>> Sent on behalf of Derek Adams:
>>>
>>>
>>> Hey Jess Users!  This is my first post, so I apologize for anything
>>> "noob"
>>> that I say/do...
>>>
>>> I'm very new to Jess.  I understand the basics but applying my knowledge
>>> for the first time is proving more difficult than I anticipated.  Here is
>>> the problem:
>>>
>>> I need to set up a rule in Jess that calculates the cost of a benefit
>>> based on age and enrollees.
>>> *
>>> Example:
>>> The Benefit Configuration is "Employee $10k / Spouse $5k"
>>> The enrollees are the employee (John Smith age 30) and spouse (Jane Smith
>>> and 28).
>>> The costs are calculated as follows:
>>>
>>> Age               Employee            Spouse
>>> 18-29            11.55                    6.65
>>> 30-39            18.95                   10.35
>>> 40-49            38.35                   20.05*
>>>
>>> *So John's cost is 18.95 and Jane's cost is 6.65 for a total of 25.60*.
>>>
>>> Any advice would be greatly appreciated!
>>>
>>> Thanks,
>>>
>>> Derek Adams
>>>
>>
>>
>
>
> --
> *Derek Adams*
> Lead Developer
> Arahant LLC
> Work: 615-376-5500 ext. 314
> Cell: 270-543-0920
>


--------------------------------------------------------------------
To unsubscribe, send the words 'unsubscribe jess-users [hidden email]'
in the BODY of a message to [hidden email], NOT to the list
(use your own address!) List problems? Notify [hidden email].
--------------------------------------------------------------------




--
Derek Adams
Lead Developer
Arahant LLC
Work: 615-376-5500 ext. 314
Cell: 270-543-0920

Reply | Threaded
Open this post in threaded view
|

Re: JESS: Re: calculating benefit costs

Peter Lin
In reply to this post by Donald Winston
I couldn't agree more with james and donald.

Having a ton of if/then/else statements in the RHS really should be
avoided. One of the benefits of using a rule-centric approach is it
helps you see the logic. I find that having deeply nested if/then/else
often hides logical flaws that are hard to fix and debug. Think of it
like having small simple methods in your java code versus having a
gigantic java method with thousands of lines.

On Fri, Jan 7, 2011 at 10:35 AM, Donald Paul Winston
<[hidden email]> wrote:

> So many if else statements on the RHS is "unruly".
> On Jan 7, 2011, at 9:15 AM, Derek Adams wrote:
>
> Thanks for the help guys.  Here is what I ended up with.  This works, but
> I'm sure it's not the most efficient way to solve the problem.
>
> (defrule setCalculatedCostGCI20k5k
>     (HrBenefitJoin (hrBenefitConfigId "00001-0000000076")(benefitJoinId
> ?bjid)(calculatedCost ?cost)(OBJECT ?obj)(coveredPersonId
> ?cPer)(payingPersonId ?pPer)(relationshipId ?rel))
>     (Person (personId ?cPer)(dob ?dob)(OBJECT ?objP))
> =>
>     (printout t "age = " (call ?objP calcAgeAsOf(call
> com.arahant.utils.DateUtils now )) " for " ?bjid " " crlf)
>
>     (if (eq ?rel nil) then
>         (if (< (call ?objP calcAgeAsOf(call com.arahant.utils.DateUtils now
> )) 30) then
>             (call ?obj overrideAgeCost 11.55)
>          else (if (< (call ?objP calcAgeAsOf(call
> com.arahant.utils.DateUtils now )) 40) then
>                 (call ?obj overrideAgeCost 18.95)
>               else (if (< (call ?objP calcAgeAsOf(call
> com.arahant.utils.DateUtils now )) 50) then
>                     (call ?obj overrideAgeCost 38.35)
>                     else (if (< (call ?objP calcAgeAsOf(call
> com.arahant.utils.DateUtils now )) 60) then
>                         (call ?obj overrideAgeCost 65.95)
>                           else (if (< (call ?objP calcAgeAsOf(call
> com.arahant.utils.DateUtils now )) 70) then
>                                     (call ?obj overrideAgeCost 104.35)
>                                 else
>                                     (printout t "age greater than 69 ... "
> (call ?objP calcAgeAsOf(call com.arahant.utils.DateUtils now )) " for "
> ?bjid " " crlf))))))
>      else (if (neq ?rel nil) then
>                 (if (< (call ?objP calcAgeAsOf(call
> com.arahant.utils.DateUtils now )) 30) then
>                     (call ?obj overrideAgeCost 4.20)
>                  else (if (< (call ?objP calcAgeAsOf(call
> com.arahant.utils.DateUtils now )) 40) then
>                         (call ?obj overrideAgeCost 6.05)
>                       else (if (< (call ?objP calcAgeAsOf(call
> com.arahant.utils.DateUtils now )) 50) then
>                             (call ?obj overrideAgeCost 10.90)
>                             else (if (< (call ?objP calcAgeAsOf(call
> com.arahant.utils.DateUtils now )) 60) then
>                                 (call ?obj overrideAgeCost 17.80)
>                                   else (if (< (call ?objP calcAgeAsOf(call
> com.arahant.utils.DateUtils now )) 70) then
>                                             (call ?obj overrideAgeCost
> 27.40)
>                                         else
>                                             (printout t "age greater than 69
> ... " (call ?objP calcAgeAsOf(call com.arahant.utils.DateUtils now )) " for
> " ?bjid " " crlf))))))))
>     (printout t "setCalculatedCostGCI function fired for " ?bjid ".
> overrideAgeCost =  " (call ?obj overrideAgeCost) crlf)
> ;    (printout t "setCalculatedCostGCI function fired for " ?bjid " " crlf)
>
> )
>
> On Thu, Jan 6, 2011 at 10:32 AM, Wolfgang Laun <[hidden email]>
> wrote:
>>
>> This additional information does not require a fundamentally different
>> approach.
>>
>> Using the same set of facts CostEmployee/CostSpouse, we can now use
>> two rules, one calculating the cost for the employee, and the other
>> one for the spouse.
>>
>> (defrule calc-self
>>  ?hbj <- (HrBenefitJoin (hrBenefitConfigId "00001-0000000073")
>>                 (calculatedCost 0)
>>                 {relationshipId  == nil}
>>                 (payingPersonId  ?pPer)
>>                 (coveredPersonId ?cPer) )
>>  (Person        (personId        ?cPer) (dob ?dob) )
>>  (CostEmployee  (lo ?lo&:(<= ?lo (yrs ?dob)))
>>                 (hi ?hi&:(>= ?hi (yrs ?dob)))(cost ?cost))
>> =>
>>  (printout t "Cost for " ?cPer " paid by himself: " ?cost crlf )
>> )
>>
>> (defrule calc-other
>>  ?hbj <- (HrBenefitJoin (hrBenefitConfigId "00001-0000000073")
>>                 (calculatedCost 0)
>>                 {relationshipId  != nil}
>>                 (payingPersonId  ?pPer)
>>                 (coveredPersonId ?cPer) )
>>  (Person        (personId        ?cPer) (dob ?dob) )
>>  (CostSpouse    (lo ?lo&:(<= ?lo (yrs ?dob)))
>>                 (hi ?hi&:(>= ?hi (yrs ?dob)))(cost ?cost))
>> =>
>>  (printout t "Cost for " ?cPer " paid by " ?pPer ": " ?cost crlf )
>> )
>>
>> The date calculation is abstracted into a
>>   (deffunction yrs (?dob) ... (return ?yrs) )
>>
>> Implementing this in Jess or in Java is a simple programming exercise,
>> but it presumably it depends on some technical/legal issues, e.g., it
>> may not be possible to use "today" as a basis for calculating the
>> difference in years from the person's dob.
>>
>> Since there's no information what to do with the resulting cost, it's
>> just printed to standard output, but updating slot calculatedCost in
>> HrBenefitJoin is straightforward.
>>
>> Cheers
>> Wolfgang
>>
>>
>> On 05/01/2011, Derek Adams <[hidden email]> wrote:
>> > the facts that I am working with are:
>> >
>> > (HrBenefitJoin (hrBenefitConfigId "00001-0000000073")(benefitJoinId
>> > ?bjid)(calculatedCost ?cost)(OBJECT ?obj)(coveredPersonId
>> > ?cPer)(payingPersonId ?pPer)(relationshipId ?rel))
>> > (Person (personId ?cPer)(dob ?dob)(OBJECT ?objP))
>> >
>> > ?rel is what identifies the "covered person" as spouse or employee.  If
>> > ?rel
>> > is nil, it's employee, else it's spouse.
>> >
>> > So ?objP is my covered person (either spouse or employee).
>> >
>> > On Wed, Jan 5, 2011 at 3:36 PM, Wolfgang Laun
>> > <[hidden email]>wrote:
>> >
>> >> With this kind of problem, there are (at least) two approaches. Given
>> >> that
>> >> Employee and Spouse are represented as facts:
>> >>    (deftemplate Spouse   (slot name)(slot age))
>> >>    (deftemplate Employee (slot name)(slot age)(slot spouse))
>> >>
>> >>    (deffacts test-facts
>> >>       (Employee (name "John Smith")(age 35)(spouse "Jane Smith"))
>> >>       (Spouse   (name "Jane Smith")(age 28))
>> >>       (Employee (name "Honey Rider")(age 39)(spouse "James Rider"))
>> >>       (Spouse   (name "James Rider")(age 45))
>> >>    )
>> >>
>> >> (1) You can write one rule for each possible combination of age
>> >> brackets.
>> >>
>> >> (defrule compute_1_1
>> >>     (Employee (name ?name){age >= 18 && age <= 29}(spouse ?spouse))
>> >>     (Spouse   {name == ?spouse}{age >= 18 && age <= 29})
>> >> =>
>> >>     (printout t "cost " ?name " " (+  11.55 6.65) crlf)
>> >> )
>> >> ... more boring code ...
>> >> (defrule compute_3_3
>> >>     (Employee (name ?name){age >= 40 && age <= 49}(spouse ?spouse))
>> >>     (Spouse   {name == ?spouse}{age >= 40 && age <= 49})
>> >> =>
>> >>     (printout t "cost " ?name " " (+  38.35 20.05) crlf)
>> >> )
>> >>
>> >> (2) You can represent the tables for the costs as facts:
>> >>    (deftemplate CostEmployee (slot lo)(slot hi)(slot cost))
>> >>    (deftemplate CostSpouse   (slot lo)(slot hi)(slot cost))
>> >>
>> >>    (deffacts costs
>> >>        (CostEmployee (lo 18)(hi 29)(cost 11.55))
>> >>        (CostEmployee (lo 30)(hi 39)(cost 18.95))
>> >>        (CostEmployee (lo 40)(hi 49)(cost 38.35))
>> >>        (CostSpouse   (lo 18)(hi 29)(cost  6.65))
>> >>        (CostSpouse   (lo 30)(hi 39)(cost 10.35))
>> >>        (CostSpouse   (lo 40)(hi 49)(cost 20.05))
>> >>    )
>> >>
>> >> and use a single rule:
>> >>
>> >>    (defrule compute
>> >>        (Employee (name ?name)(age ?ageE)(spouse ?spouse))
>> >>        (Spouse   {name == ?spouse}(age ?ageS))
>> >>        (CostEmployee {lo <= ?ageE}{hi >= ?ageE}(cost ?costE))
>> >>        (CostSpouse   {lo <= ?ageS}{hi >= ?ageS}(cost ?costS))
>> >>    =>
>> >>        (printout t "cost " ?name " " (+  ?costE ?costS) crlf)
>> >>    )
>> >>
>> >> HTH
>> >> Wolfgang
>> >>
>> >>
>> >>
>> >>
>> >>
>> >> On 5 January 2011 22:30, Wolfgang Laun <[hidden email]> wrote:
>> >>
>> >>> Sent on behalf of Derek Adams:
>> >>>
>> >>>
>> >>> Hey Jess Users!  This is my first post, so I apologize for anything
>> >>> "noob"
>> >>> that I say/do...
>> >>>
>> >>> I'm very new to Jess.  I understand the basics but applying my
>> >>> knowledge
>> >>> for the first time is proving more difficult than I anticipated.  Here
>> >>> is
>> >>> the problem:
>> >>>
>> >>> I need to set up a rule in Jess that calculates the cost of a benefit
>> >>> based on age and enrollees.
>> >>> *
>> >>> Example:
>> >>> The Benefit Configuration is "Employee $10k / Spouse $5k"
>> >>> The enrollees are the employee (John Smith age 30) and spouse (Jane
>> >>> Smith
>> >>> and 28).
>> >>> The costs are calculated as follows:
>> >>>
>> >>> Age               Employee            Spouse
>> >>> 18-29            11.55                    6.65
>> >>> 30-39            18.95                   10.35
>> >>> 40-49            38.35                   20.05*
>> >>>
>> >>> *So John's cost is 18.95 and Jane's cost is 6.65 for a total of
>> >>> 25.60*.
>> >>>
>> >>> Any advice would be greatly appreciated!
>> >>>
>> >>> Thanks,
>> >>>
>> >>> Derek Adams
>> >>>
>> >>
>> >>
>> >
>> >
>> > --
>> > *Derek Adams*
>> > Lead Developer
>> > Arahant LLC
>> > Work: 615-376-5500 ext. 314
>> > Cell: 270-543-0920
>> >
>>
>>
>> --------------------------------------------------------------------
>> To unsubscribe, send the words 'unsubscribe jess-users [hidden email]'
>> in the BODY of a message to [hidden email], NOT to the list
>> (use your own address!) List problems? Notify [hidden email].
>> --------------------------------------------------------------------
>>
>
>
>
> --
> Derek Adams
> Lead Developer
> Arahant LLC
> Work: 615-376-5500 ext. 314
> Cell: 270-543-0920
>
>




--------------------------------------------------------------------
To unsubscribe, send the words 'unsubscribe jess-users [hidden email]'
in the BODY of a message to [hidden email], NOT to the list
(use your own address!) List problems? Notify [hidden email].
--------------------------------------------------------------------

Reply | Threaded
Open this post in threaded view
|

Re: JESS: Re: calculating benefit costs

Jason Morris
Hi Derek,

OK OK... I wasn't going to say anything either but with Peter and James added to Wolfgang, I have to pile too :-) 

IMHO there are a number of maxims of rule-based programming that you're breaking here.  Ernest has put the first one most succinctly in the past:  Use many smaller rules that do one thing well rather than one Über Rule that boils the ocean.  Declarative programming should say what action(s) are to be performed when certain facts are present, but not attempt to implement those actions directly on the RHS. 

The second, as James and Peter pointed out, is not to do Java programming on the RHS.  If you make the RHS a series of method calls that take the variable bindings from the LHS as arguments, your rules will be much cleaner and maintainable.

Finally -- and this is just a plain programming nit -- I noticed the apparent use of magic numbers in your conditions.  What about all these calls to overrideAgeCost()?  Where are those args coming from?  Are they part of some policy? What if that policy changes?  Then your rules would be in a "dirty" form.  Wouldn't it be better to get those values from some cache or database with most current values?

Something that might help you:
I've been collecting rule-based metaphors lately -- different ways of thinking about using rules.  One metaphor that has been particularly productive has been thinking about "digestion" and the passing of data through a series of modules like a "digestive tract".  Obviously, if you carry the metaphor too far ... well you see where the "garbage in/ garbage out" saying comes into play. :-)  But the idea is that you are moving the data through different states, partially processing it each time a new rule module has a crack at it.  This has precedent in UNIX/LINUX with pipes -- same idea.  Old wine in a new bottle? Perhaps.  But this way, you can clearly separate out concerns, add pre and post processing functions, and test partial results by simply disabling/enabling certain modules in the sequence.

Cheers,
Jason

------------------------------------------------------
Jason Morris
Chairman, Rules Fest 2010/2011 
http://www.rulesfest.org
Morris Technical Solutions LLC
[hidden email]
(517) 304-5883
Reply | Threaded
Open this post in threaded view
|

RE: JESS: Re: calculating benefit costs

Debasish.Dalui
In reply to this post by Peter Lin
Re: JESS: Re: calculating benefit costs
Agree with Peter,  
 
And, there might be another solution (others are already mentioned by Wolfgang), which I believe, is a normal practice for other rule-engines available in the current market, providing the concept of Decision Table/Matrix.
 
So, please do the following exercise before writing the rules in JESS language -  
1.) Represent this rule into excel sheet as decision table/matrix format (combination of conditions/actions).
2.) Try to find the match in conditions block, and merge it first if there is match in condition(s), so that you can easily find the gaps and duplicates (if there is any).
3.) Try to find how you can normalize this single big table into multiples (if possible), i.e. one table might contain few combined conditions and one or minimum actions, and the condition values could be derived/inferred from other decision table/matrics.
 
Now, once done,
1.) Consider each column of a decision table/matrix as one single rule. As mentioned in #3, you can use JESS *saliance* concept to each rule to set the priority relative to all other rule(s)/rulesets, and using this concept, the less priority rules get the *inferred result* as input from the prioritized ones.
2.) Please write all the combined *if* conditions into the LHS side of each rule.
3.) The RHS will include only the call methods which is setting some value to an object (as per the example), and the inferred result will be input for other rules having less priority.
 
Using this concept, you might have a big list of rules, which is easily understandable/maintainable from user/developer point of view. But still one BIG question in my mind, compare to Wolfgang example or in general, is this really a better approach from rule-engine working memory (or any other) perspective?
 
 
Regards
 
DEBASISH DALUI (122816)
----------------------------------------------
Cognizant Technology Solutions US Corp

Cell  : +1-216-835-2902


From: [hidden email] on behalf of Peter Lin
Sent: Fri 1/7/2011 11:58 AM
To: [hidden email]
Subject: Re: JESS: Re: calculating benefit costs

I couldn't agree more with james and donald.

Having a ton of if/then/else statements in the RHS really should be
avoided. One of the benefits of using a rule-centric approach is it
helps you see the logic. I find that having deeply nested if/then/else
often hides logical flaws that are hard to fix and debug. Think of it
like having small simple methods in your java code versus having a
gigantic java method with thousands of lines.

On Fri, Jan 7, 2011 at 10:35 AM, Donald Paul Winston
<[hidden email]> wrote:


> So many if else statements on the RHS is "unruly".
> On Jan 7, 2011, at 9:15 AM, Derek Adams wrote:
>
> Thanks for the help guys.  Here is what I ended up with.  This works, but
> I'm sure it's not the most efficient way to solve the problem.
>
> (defrule setCalculatedCostGCI20k5k
>     (HrBenefitJoin (hrBenefitConfigId "00001-0000000076")(benefitJoinId
> ?bjid)(calculatedCost ?cost)(OBJECT ?obj)(coveredPersonId
> ?cPer)(payingPersonId ?pPer)(relationshipId ?rel))
>     (Person (personId ?cPer)(dob ?dob)(OBJECT ?objP))
> =>
>     (printout t "age = " (call ?objP calcAgeAsOf(call
> com.arahant.utils.DateUtils now )) " for " ?bjid " " crlf)
>
>     (if (eq ?rel nil) then
>         (if (< (call ?objP calcAgeAsOf(call com.arahant.utils.DateUtils now
> )) 30) then
>             (call ?obj overrideAgeCost 11.55)
>          else (if (< (call ?objP calcAgeAsOf(call
> com.arahant.utils.DateUtils now )) 40) then
>                 (call ?obj overrideAgeCost 18.95)
>               else (if (< (call ?objP calcAgeAsOf(call
> com.arahant.utils.DateUtils now )) 50) then
>                     (call ?obj overrideAgeCost 38.35)
>                     else (if (< (call ?objP calcAgeAsOf(call
> com.arahant.utils.DateUtils now )) 60) then
>                         (call ?obj overrideAgeCost 65.95)
>                           else (if (< (call ?objP calcAgeAsOf(call
> com.arahant.utils.DateUtils now )) 70) then
>                                     (call ?obj overrideAgeCost 104.35)
>                                 else
>                                     (printout t "age greater than 69 ... "
> (call ?objP calcAgeAsOf(call com.arahant.utils.DateUtils now )) " for "
> ?bjid " " crlf))))))
>      else (if (neq ?rel nil) then
>                 (if (< (call ?objP calcAgeAsOf(call
> com.arahant.utils.DateUtils now )) 30) then
>                     (call ?obj overrideAgeCost 4.20)
>                  else (if (< (call ?objP calcAgeAsOf(call
> com.arahant.utils.DateUtils now )) 40) then
>                         (call ?obj overrideAgeCost 6.05)
>                       else (if (< (call ?objP calcAgeAsOf(call
> com.arahant.utils.DateUtils now )) 50) then
>                             (call ?obj overrideAgeCost 10.90)
>                             else (if (< (call ?objP calcAgeAsOf(call
> com.arahant.utils.DateUtils now )) 60) then
>                                 (call ?obj overrideAgeCost 17.80)
>                                   else (if (< (call ?objP calcAgeAsOf(call
> com.arahant.utils.DateUtils now )) 70) then
>                                             (call ?obj overrideAgeCost
> 27.40)
>                                         else
>                                             (printout t "age greater than 69
> ... " (call ?objP calcAgeAsOf(call com.arahant.utils.DateUtils now )) " for
> " ?bjid " " crlf))))))))
>     (printout t "setCalculatedCostGCI function fired for " ?bjid ".
> overrideAgeCost =  " (call ?obj overrideAgeCost) crlf)
> ;    (printout t "setCalculatedCostGCI function fired for " ?bjid " " crlf)
>
> )
>
> On Thu, Jan 6, 2011 at 10:32 AM, Wolfgang Laun <[hidden email]>
> wrote:
>>
>> This additional information does not require a fundamentally different
>> approach.
>>
>> Using the same set of facts CostEmployee/CostSpouse, we can now use
>> two rules, one calculating the cost for the employee, and the other
>> one for the spouse.
>>
>> (defrule calc-self
>>  ?hbj <- (HrBenefitJoin (hrBenefitConfigId "00001-0000000073")
>>                 (calculatedCost 0)
>>                 {relationshipId  == nil}
>>                 (payingPersonId  ?pPer)
>>                 (coveredPersonId ?cPer) )
>>  (Person        (personId        ?cPer) (dob ?dob) )
>>  (CostEmployee  (lo ?lo&:(<= ?lo (yrs ?dob)))
>>                 (hi ?hi&:(>= ?hi (yrs ?dob)))(cost ?cost))
>> =>
>>  (printout t "Cost for " ?cPer " paid by himself: " ?cost crlf )
>> )
>>
>> (defrule calc-other
>>  ?hbj <- (HrBenefitJoin (hrBenefitConfigId "00001-0000000073")
>>                 (calculatedCost 0)
>>                 {relationshipId  != nil}
>>                 (payingPersonId  ?pPer)
>>                 (coveredPersonId ?cPer) )
>>  (Person        (personId        ?cPer) (dob ?dob) )
>>  (CostSpouse    (lo ?lo&:(<= ?lo (yrs ?dob)))
>>                 (hi ?hi&:(>= ?hi (yrs ?dob)))(cost ?cost))
>> =>
>>  (printout t "Cost for " ?cPer " paid by " ?pPer ": " ?cost crlf )
>> )
>>
>> The date calculation is abstracted into a
>>   (deffunction yrs (?dob) ... (return ?yrs) )
>>
>> Implementing this in Jess or in Java is a simple programming exercise,
>> but it presumably it depends on some technical/legal issues, e.g., it
>> may not be possible to use "today" as a basis for calculating the
>> difference in years from the person's dob.
>>
>> Since there's no information what to do with the resulting cost, it's
>> just printed to standard output, but updating slot calculatedCost in
>> HrBenefitJoin is straightforward.
>>
>> Cheers
>> Wolfgang
>>
>>
>> On 05/01/2011, Derek Adams <[hidden email]> wrote:
>> > the facts that I am working with are:
>> >
>> > (HrBenefitJoin (hrBenefitConfigId "00001-0000000073")(benefitJoinId
>> > ?bjid)(calculatedCost ?cost)(OBJECT ?obj)(coveredPersonId
>> > ?cPer)(payingPersonId ?pPer)(relationshipId ?rel))
>> > (Person (personId ?cPer)(dob ?dob)(OBJECT ?objP))
>> >
>> > ?rel is what identifies the "covered person" as spouse or employee.  If
>> > ?rel
>> > is nil, it's employee, else it's spouse.
>> >
>> > So ?objP is my covered person (either spouse or employee).
>> >
>> > On Wed, Jan 5, 2011 at 3:36 PM, Wolfgang Laun
>> > <[hidden email]>wrote:
>> >
>> >> With this kind of problem, there are (at least) two approaches. Given
>> >> that
>> >> Employee and Spouse are represented as facts:
>> >>    (deftemplate Spouse   (slot name)(slot age))
>> >>    (deftemplate Employee (slot name)(slot age)(slot spouse))
>> >>
>> >>    (deffacts test-facts
>> >>       (Employee (name "John Smith")(age 35)(spouse "Jane Smith"))
>> >>       (Spouse   (name "Jane Smith")(age 28))
>> >>       (Employee (name "Honey Rider")(age 39)(spouse "James Rider"))
>> >>       (Spouse   (name "James Rider")(age 45))
>> >>    )
>> >>
>> >> (1) You can write one rule for each possible combination of age
>> >> brackets.
>> >>
>> >> (defrule compute_1_1
>> >>     (Employee (name ?name){age >= 18 && age <= 29}(spouse ?spouse))
>> >>     (Spouse   {name == ?spouse}{age >= 18 && age <= 29})
>> >> =>
>> >>     (printout t "cost " ?name " " (+  11.55 6.65) crlf)
>> >> )
>> >> ... more boring code ...
>> >> (defrule compute_3_3
>> >>     (Employee (name ?name){age >= 40 && age <= 49}(spouse ?spouse))
>> >>     (Spouse   {name == ?spouse}{age >= 40 && age <= 49})
>> >> =>
>> >>     (printout t "cost " ?name " " (+  38.35 20.05) crlf)
>> >> )
>> >>
>> >> (2) You can represent the tables for the costs as facts:
>> >>    (deftemplate CostEmployee (slot lo)(slot hi)(slot cost))
>> >>    (deftemplate CostSpouse   (slot lo)(slot hi)(slot cost))
>> >>
>> >>    (deffacts costs
>> >>        (CostEmployee (lo 18)(hi 29)(cost 11.55))
>> >>        (CostEmployee (lo 30)(hi 39)(cost 18.95))
>> >>        (CostEmployee (lo 40)(hi 49)(cost 38.35))
>> >>        (CostSpouse   (lo 18)(hi 29)(cost  6.65))
>> >>        (CostSpouse   (lo 30)(hi 39)(cost 10.35))
>> >>        (CostSpouse   (lo 40)(hi 49)(cost 20.05))
>> >>    )
>> >>
>> >> and use a single rule:
>> >>
>> >>    (defrule compute
>> >>        (Employee (name ?name)(age ?ageE)(spouse ?spouse))
>> >>        (Spouse   {name == ?spouse}(age ?ageS))
>> >>        (CostEmployee {lo <= ?ageE}{hi >= ?ageE}(cost ?costE))
>> >>        (CostSpouse   {lo <= ?ageS}{hi >= ?ageS}(cost ?costS))
>> >>    =>
>> >>        (printout t "cost " ?name " " (+  ?costE ?costS) crlf)
>> >>    )
>> >>
>> >> HTH
>> >> Wolfgang
>> >>
>> >>
>> >>
>> >>
>> >>
>> >> On 5 January 2011 22:30, Wolfgang Laun <[hidden email]> wrote:
>> >>
>> >>> Sent on behalf of Derek Adams:
>> >>>
>> >>>
>> >>> Hey Jess Users!  This is my first post, so I apologize for anything
>> >>> "noob"
>> >>> that I say/do...
>> >>>
>> >>> I'm very new to Jess.  I understand the basics but applying my
>> >>> knowledge
>> >>> for the first time is proving more difficult than I anticipated.  Here
>> >>> is
>> >>> the problem:
>> >>>
>> >>> I need to set up a rule in Jess that calculates the cost of a benefit
>> >>> based on age and enrollees.
>> >>> *
>> >>> Example:
>> >>> The Benefit Configuration is "Employee $10k / Spouse $5k"
>> >>> The enrollees are the employee (John Smith age 30) and spouse (Jane
>> >>> Smith
>> >>> and 28).
>> >>> The costs are calculated as follows:
>> >>>
>> >>> Age               Employee            Spouse
>> >>> 18-29            11.55                    6.65
>> >>> 30-39            18.95                   10.35
>> >>> 40-49            38.35                   20.05*
>> >>>
>> >>> *So John's cost is 18.95 and Jane's cost is 6.65 for a total of
>> >>> 25.60*.
>> >>>
>> >>> Any advice would be greatly appreciated!
>> >>>
>> >>> Thanks,
>> >>>
>> >>> Derek Adams
>> >>>
>> >>
>> >>
>> >
>> >
>> > --
>> > *Derek Adams*
>> > Lead Developer
>> > Arahant LLC
>> > Work: 615-376-5500 ext. 314
>> > Cell: 270-543-0920
>> >
>>
>>
>> --------------------------------------------------------------------
>> To unsubscribe, send the words 'unsubscribe jess-users [hidden email]'
>> in the BODY of a message to [hidden email], NOT to the list
>> (use your own address!) List problems? Notify [hidden email].
>> --------------------------------------------------------------------
>>
>
>
>
> --
> Derek Adams
> Lead Developer
> Arahant LLC
> Work: 615-376-5500 ext. 314
> Cell: 270-543-0920
>
>




--------------------------------------------------------------------
To unsubscribe, send the words 'unsubscribe jess-users [hidden email]'
in the BODY of a message to [hidden email], NOT to the list
(use your own address!) List problems? Notify [hidden email].
--------------------------------------------------------------------

This e-mail and any files transmitted with it are for the sole use of the intended recipient(s) and may contain confidential and privileged information.
If you are not the intended recipient, please contact the sender by reply e-mail and destroy all copies of the original message.
Any unauthorised review, use, disclosure, dissemination, forwarding, printing or copying of this email or any action taken in reliance on this e-mail is strictly
prohibited and may be unlawful.
Reply | Threaded
Open this post in threaded view
|

Re: JESS: Re: calculating benefit costs

Wolfgang Laun-2
In reply to this post by Jason Morris
All the pundits advocate to put the decision logic into the LHS. Opinions vary a little wrt. to the use of static facts to
reduce the number of rules. Some say, "The more rules the merrier." I feel that using static facts for lookup of data is justified, considering this:
  • Fact data is easier to change than rule code.
  • Putting the data into facts is one way of avoiding hard coded constants.
  • Less code means less room for bugs.
Now to the one rule that does it all, posted by Derek, with the cascading if on the RHS. Looking at the code, I've seen a few things which might be worth noting.
  • calcAgeAsOf is called many times. Why not call once and save the result?
  • Age limits and costs should be kept in a list to avoi code repetition by using a loop. globals are one way of making such data available.
  • Setting a variable depending on ?rel and a single logic avoids code duplication.
  • The cost result is stored in the object using a call of some Java method. But bypassing Jess when modifying facts is not a good idea, most of the time.
Below is the much reduced code. Of course, it still has the major defeciency of too much logic on the RHS,


(defglobal ?*limAge* = (list 30    40    50    60     70   )
           ?*cstEmp* = (list 11.55 18.95 38.35 65.95 104.35)
           ?*cstRel* = (list  4.20  6.05 10.90 17.80  27.40)
)          

(defrule setCalculatedCostGCI20k5k
  ?hbj <- (HrBenefitJoin (hrBenefitConfigId "00001-0000000076")
             (benefitJoinId ?bjid)
;;           (calculatedCost ?cost)
             (calculatedCost 0)
;;           (OBJECT ?obj)
             (coveredPersonId ?cPer)
             (payingPersonId ?pPer)
             (relationshipId ?rel))
    (Person (personId ?cPer)
            (dob ?dob)
;;          (OBJECT ?objP)
    )
=>
; call once, bind result     
  (bind ?years (call ?objP calcAgeAsOf(call com.arahant.utils.DateUtils now )))

; avoids cut-and-paste repettion of code
  (bind ?costs  (if (eq ?rel nil) then ?*cstEmp* else ?*cstRel* fi))

  (bind ?cost nil)
  (for (bind ?i 1) (<= ?i (length$  ?*limAge*)) (++ ?i)
    (if (< ?years (nth$ ?i ?*limAge*)) then
      (bind ?cost (nth$ ?i ?costs))
      (break)
    )
  )

  (if (eq ?cost nil) then
    (printout t "age greater than 69... " ?years " for " ?bjid " " crlf)
   else
;  Bypassing Jess when modifying is not a good idea, most of the time.
;   (call ?obj overrideAgeCost ?cost)
    (modify ?hbj (calculatedCost ?cost))
  )
)

-W


On 7 January 2011 19:44, Jason Morris <[hidden email]> wrote:
Hi Derek,

OK OK... I wasn't going to say anything either but with Peter and James added to Wolfgang, I have to pile too :-) 

IMHO there are a number of maxims of rule-based programming that you're breaking here.  Ernest has put the first one most succinctly in the past:  Use many smaller rules that do one thing well rather than one Über Rule that boils the ocean.  Declarative programming should say what action(s) are to be performed when certain facts are present, but not attempt to implement those actions directly on the RHS. 

The second, as James and Peter pointed out, is not to do Java programming on the RHS.  If you make the RHS a series of method calls that take the variable bindings from the LHS as arguments, your rules will be much cleaner and maintainable.

Finally -- and this is just a plain programming nit -- I noticed the apparent use of magic numbers in your conditions.  What about all these calls to overrideAgeCost()?  Where are those args coming from?  Are they part of some policy? What if that policy changes?  Then your rules would be in a "dirty" form.  Wouldn't it be better to get those values from some cache or database with most current values?

Something that might help you:
I've been collecting rule-based metaphors lately -- different ways of thinking about using rules.  One metaphor that has been particularly productive has been thinking about "digestion" and the passing of data through a series of modules like a "digestive tract".  Obviously, if you carry the metaphor too far ... well you see where the "garbage in/ garbage out" saying comes into play. :-)  But the idea is that you are moving the data through different states, partially processing it each time a new rule module has a crack at it.  This has precedent in UNIX/LINUX with pipes -- same idea.  Old wine in a new bottle? Perhaps.  But this way, you can clearly separate out concerns, add pre and post processing functions, and test partial results by simply disabling/enabling certain modules in the sequence.

Cheers,
Jason

------------------------------------------------------
Jason Morris
Chairman, Rules Fest 2010/2011 
http://www.rulesfest.org
Morris Technical Solutions LLC
[hidden email]
(517) 304-5883

Reply | Threaded
Open this post in threaded view
|

Re: JESS: Re: calculating benefit costs

Peter Lin
In the interest of exploration and education, here's a few random thoughts.

The approach wolfgang mentions is an old knowledge base technique. I
like to use it for data that is "constant-like". Things like code
reference tables. One example of this is auto insurance rating. Many
companies rate based on zip code and assign a numeric value for each
zip code.

If a developer hard codes the constant in the rule, it means every
time the value changes, the rule would need to be updated. The problem
is actually worse than that. Say a company sells insurance in 5 states
and there's a total of 500 zip codes. Using the hard coded approach,
the developer would need to write 500 rules. If on the other hand, the
developer uses facts to match the insurance policy to a zip code
rating fact, we can easily change the rating value for a zipcode and
not affect the rules.

The downside is we need to have good management tools for editing the
reference data. All of the reference data should be versioned and
basic validation should be performed on the data before it is deployed
to production. Unfortunately, all of the products on the market today
do not provide robust tools for managing knowledge base data. In the
past, I've written custom applications for managing knowledge data in
financial applications.

For applications that have lots of code reference data that changes
regularly, I strongly recommend using fact data instead of hard coding
constants. The other benefit is tends to reduce lots of procedural
code in the RHS of the rule. Instead of using lots of if/then/else,
the rule tends to match the facts in the LHS and use the reference
data in the RHS. To put it another way, some of the calculations have
become pre-calculated codes. This can make the rules easier to read
and maintain. Also, by precalculating some of the data, we reduce the
amount of work the rule engine has to perform each time.

Using these types of knowledge base techniques also makes it easier to
write proof and validation routines to make sure the pre-calculated
tables are accurate. I would recommend reading books on knowledge base
and expert systems to get a broader understanding of rule programming.
Most of the business rule books out there are really just user manuals
and don't go into details on the design patterns used in expert
systems. Gary Riley's book is a great place to start.


As wolfgang stated,

On Sat, Jan 8, 2011 at 10:39 AM, Wolfgang Laun <[hidden email]> wrote:

> All the pundits advocate to put the decision logic into the LHS. Opinions
> vary a little wrt. to the use of static facts to
> reduce the number of rules. Some say, "The more rules the merrier." I feel
> that using static facts for lookup of data is justified, considering this:
>
> Fact data is easier to change than rule code.
> Putting the data into facts is one way of avoiding hard coded constants.
> Less code means less room for bugs.
>
> Now to the one rule that does it all, posted by Derek, with the cascading if
> on the RHS. Looking at the code, I've seen a few things which might be worth
> noting.
>
> calcAgeAsOf is called many times. Why not call once and save the result?
> Age limits and costs should be kept in a list to avoi code repetition by
> using a loop. globals are one way of making such data available.
> Setting a variable depending on ?rel and a single logic avoids code
> duplication.
> The cost result is stored in the object using a call of some Java method.
> But bypassing Jess when modifying facts is not a good idea, most of the
> time.
>
> Below is the much reduced code. Of course, it still has the major defeciency
> of too much logic on the RHS,
>
>
> (defglobal ?*limAge* = (list 30    40    50    60     70   )
>            ?*cstEmp* = (list 11.55 18.95 38.35 65.95 104.35)
>            ?*cstRel* = (list  4.20  6.05 10.90 17.80  27.40)
> )
>
> (defrule setCalculatedCostGCI20k5k
>   ?hbj <- (HrBenefitJoin (hrBenefitConfigId "00001-0000000076")
>              (benefitJoinId ?bjid)
> ;;           (calculatedCost ?cost)
>              (calculatedCost 0)
> ;;           (OBJECT ?obj)
>              (coveredPersonId ?cPer)
>              (payingPersonId ?pPer)
>              (relationshipId ?rel))
>     (Person (personId ?cPer)
>             (dob ?dob)
> ;;          (OBJECT ?objP)
>     )
> =>
> ; call once, bind result
>   (bind ?years (call ?objP calcAgeAsOf(call com.arahant.utils.DateUtils now
> )))
>
> ; avoids cut-and-paste repettion of code
>   (bind ?costs  (if (eq ?rel nil) then ?*cstEmp* else ?*cstRel* fi))
>
>   (bind ?cost nil)
>   (for (bind ?i 1) (<= ?i (length$  ?*limAge*)) (++ ?i)
>     (if (< ?years (nth$ ?i ?*limAge*)) then
>       (bind ?cost (nth$ ?i ?costs))
>       (break)
>     )
>   )
>
>   (if (eq ?cost nil) then
>     (printout t "age greater than 69... " ?years " for " ?bjid " " crlf)
>    else
> ;  Bypassing Jess when modifying is not a good idea, most of the time.
> ;   (call ?obj overrideAgeCost ?cost)
>     (modify ?hbj (calculatedCost ?cost))
>   )
> )
>
> -W
>
>
> On 7 January 2011 19:44, Jason Morris <[hidden email]> wrote:
>>
>> Hi Derek,
>>
>> OK OK... I wasn't going to say anything either but with Peter and James
>> added to Wolfgang, I have to pile too :-)
>>
>> IMHO there are a number of maxims of rule-based programming that you're
>> breaking here.  Ernest has put the first one most succinctly in the past:
>> Use many smaller rules that do one thing well rather than one Über Rule that
>> boils the ocean.  Declarative programming should say what action(s) are to
>> be performed when certain facts are present, but not attempt to implement
>> those actions directly on the RHS.
>>
>> The second, as James and Peter pointed out, is not to do Java programming
>> on the RHS.  If you make the RHS a series of method calls that take the
>> variable bindings from the LHS as arguments, your rules will be much cleaner
>> and maintainable.
>>
>> Finally -- and this is just a plain programming nit -- I noticed the
>> apparent use of magic numbers in your conditions.  What about all these
>> calls to overrideAgeCost()?  Where are those args coming from?  Are they
>> part of some policy? What if that policy changes?  Then your rules would be
>> in a "dirty" form.  Wouldn't it be better to get those values from some
>> cache or database with most current values?
>>
>> Something that might help you:
>> I've been collecting rule-based metaphors lately -- different ways of
>> thinking about using rules.  One metaphor that has been particularly
>> productive has been thinking about "digestion" and the passing of data
>> through a series of modules like a "digestive tract".  Obviously, if you
>> carry the metaphor too far ... well you see where the "garbage in/ garbage
>> out" saying comes into play. :-)  But the idea is that you are moving the
>> data through different states, partially processing it each time a new rule
>> module has a crack at it.  This has precedent in UNIX/LINUX with pipes --
>> same idea.  Old wine in a new bottle? Perhaps.  But this way, you can
>> clearly separate out concerns, add pre and post processing functions, and
>> test partial results by simply disabling/enabling certain modules in the
>> sequence.
>>
>> Cheers,
>> Jason
>>
>> ------------------------------------------------------
>> Jason Morris
>> Chairman, Rules Fest 2010/2011
>> http://www.rulesfest.org
>> Morris Technical Solutions LLC
>> [hidden email]
>> (517) 304-5883
>
>




--------------------------------------------------------------------
To unsubscribe, send the words 'unsubscribe jess-users [hidden email]'
in the BODY of a message to [hidden email], NOT to the list
(use your own address!) List problems? Notify [hidden email].
--------------------------------------------------------------------

Reply | Threaded
Open this post in threaded view
|

Re: JESS: Re: calculating benefit costs

Donald Winston
I found this book (Giarratanno & Riley) to be of very low value for my purposes. I have yet to find a decent book about rule base programming. "Jess In Action" is the only one that's been useful for me. A couple of Drools books I've read were ridiculous. Most AI and knowledge base books are 95% fluff.

On Jan 9, 2011, at 9:33 AM, Peter Lin wrote:

> I would recommend reading books on knowledge base
> and expert systems to get a broader understanding of rule programming.
> Most of the business rule books out there are really just user manuals
> and don't go into details on the design patterns used in expert
> systems. Gary Riley's book is a great place to start.





--------------------------------------------------------------------
To unsubscribe, send the words 'unsubscribe jess-users [hidden email]'
in the BODY of a message to [hidden email], NOT to the list
(use your own address!) List problems? Notify [hidden email].
--------------------------------------------------------------------

Reply | Threaded
Open this post in threaded view
|

Re: JESS: Re: calculating benefit costs

Peter Lin
when I first started learning JESS back in 2000, I felt the same way,
but over time I've come to change my mind. In my case, it was because
I really had no clue what expert systems was or what a knowledge base
can do. I had to learn through trial and error the hard way to realize
many of the techniques described in Gary's book are invaluable. It's
just that I wasn't able to absorb those ideas and approaches until I
had acquired sufficient experience.

there's definitely a need for a book that applies expert system and
knowledge base techniques to business problems. in my bias opinion
Jess In Action is one of those rare books, but there is a lot more
beyond Jess in Action. For me, it is the best place to start. Mileage
will vary depending on the problem and project requirements obviously.

peter

On Sun, Jan 9, 2011 at 9:58 AM, Donald Paul Winston
<[hidden email]> wrote:

> I found this book (Giarratanno & Riley) to be of very low value for my purposes. I have yet to find a decent book about rule base programming. "Jess In Action" is the only one that's been useful for me. A couple of Drools books I've read were ridiculous. Most AI and knowledge base books are 95% fluff.
>
> On Jan 9, 2011, at 9:33 AM, Peter Lin wrote:
>
>> I would recommend reading books on knowledge base
>> and expert systems to get a broader understanding of rule programming.
>> Most of the business rule books out there are really just user manuals
>> and don't go into details on the design patterns used in expert
>> systems. Gary Riley's book is a great place to start.
>
>
>
>
>
> --------------------------------------------------------------------
> To unsubscribe, send the words 'unsubscribe jess-users [hidden email]'
> in the BODY of a message to [hidden email], NOT to the list
> (use your own address!) List problems? Notify [hidden email].
> --------------------------------------------------------------------
>
>




--------------------------------------------------------------------
To unsubscribe, send the words 'unsubscribe jess-users [hidden email]'
in the BODY of a message to [hidden email], NOT to the list
(use your own address!) List problems? Notify [hidden email].
--------------------------------------------------------------------

Reply | Threaded
Open this post in threaded view
|

Re: JESS: Re: calculating benefit costs

James Owen-3
Greetings:

Normally I use the Girratano and Riley book when teaching either CLIPS or Jess for the simple reason that the Jess book is not quite up to date.  Neither is the CLIPS book but CLIPS itself is fairly static and doesn't change much over time making the book more in-synch.  HOWEVER, if I'm teaching Jess I would prefer to at least start with the G&R book through the first five or six chapters because they can apply to almost any rulebased system.  The, if teaching Jess, I move over to the "Jess In Action" book for more Jess-oriented details and examples.

One other reason for teaching CLIPS or CLIPS/R2:  The iPhone and iPad both use Objective C making those the only two rulebased systems that I might think about using in that environment.  Even though Apple (MacIntosh) recognizes Java it never has "married" the language.  I think that is due to its NeXt heritage that came with both Common LISP and lots of tools for X-Code development; still does.  Maybe it had Franz LISP included as well - don't remember.  I really lusted for a NeXt machine, maybe it was the brushed aluminum square box, but they cost WAY more than this poor grad student had at the time.

As far as other books, there is a list of some really EXCELLENT books, in order of preference, located at http://www.kbsc.com/aibooks.html - I need to update it but just haven't had the time.  Maybe next week???  Maybe...  For a really heavy read try the MYCIN book (if you can find it) that is only 850+ pages.  But only about 600 or so is rulebase stuff that is directly applicable.  The rest deals with tutorials, add-ons, etc.  I wish that they had published the entire code somewhere but, so far, I haven't found it.  MYCIN is one of the few to use probability of belief and disbelief etc. in the formation of the rules rather than straight-up boolean Yes or No.  (Yes, we have fuzzy Jess and - somewhere - fuzzy CLIPS, but this was built into the system from the beginning.)
 


SDG
jco
CoFounder October Rules Fest 2008/2009

On Jan 9, 2011, at 6:07 PM, Peter Lin wrote:

when I first started learning JESS back in 2000, I felt the same way,
but over time I've come to change my mind. In my case, it was because
I really had no clue what expert systems was or what a knowledge base
can do. I had to learn through trial and error the hard way to realize
many of the techniques described in Gary's book are invaluable. It's
just that I wasn't able to absorb those ideas and approaches until I
had acquired sufficient experience.

there's definitely a need for a book that applies expert system and
knowledge base techniques to business problems. in my bias opinion
Jess In Action is one of those rare books, but there is a lot more
beyond Jess in Action. For me, it is the best place to start. Mileage
will vary depending on the problem and project requirements obviously.

peter

On Sun, Jan 9, 2011 at 9:58 AM, Donald Paul Winston
<[hidden email]> wrote:
I found this book (Giarratanno & Riley) to be of very low value for my purposes. I have yet to find a decent book about rule base programming. "Jess In Action" is the only one that's been useful for me. A couple of Drools books I've read were ridiculous. Most AI and knowledge base books are 95% fluff.

On Jan 9, 2011, at 9:33 AM, Peter Lin wrote:

I would recommend reading books on knowledge base
and expert systems to get a broader understanding of rule programming.
Most of the business rule books out there are really just user manuals
and don't go into details on the design patterns used in expert
systems. Gary Riley's book is a great place to start.





--------------------------------------------------------------------
To unsubscribe, send the words 'unsubscribe jess-users [hidden email]'
in the BODY of a message to [hidden email], NOT to the list
(use your own address!) List problems? Notify [hidden email].
--------------------------------------------------------------------






--------------------------------------------------------------------
To unsubscribe, send the words 'unsubscribe jess-users [hidden email]'
in the BODY of a message to [hidden email], NOT to the list
(use your own address!) List problems? Notify [hidden email].
--------------------------------------------------------------------


Reply | Threaded
Open this post in threaded view
|

RE: JESS: Re: calculating benefit costs

Debasish.Dalui
In reply to this post by Peter Lin
Re: JESS: Re: calculating benefit costs
Hi all,
 
Thanks a lot for the detail clarification of using the concept of 'fact-data' instead of hard-coding constants inside the rule (as you have explaned in your example, and rules in this scenario looks homogeneous, and only difference is the hard-code constant part).
 
Now, we know how to do it using JESS, and concern is with other available rule engine vendors - how they are managing this situation, since this is pretty much common issue in most of IT-service industry projects using rule-engine for some business decision; and as of today, vendors are suggesting to use Decision Table concept to handle this homogeneous type rules. To my understanding, this is nothing but the representing of 'n' number of homogeneous type rules with different hard-coded constant values.
 
Please make my understanding correct.
 
 
Regards
 
DEBASISH DALUI (122816)
----------------------------------------------
Cognizant Technology Solutions US Corp

Cell  : +1-216-835-2902


From: [hidden email] on behalf of Peter Lin
Sent: Sun 1/9/2011 9:33 AM
To: [hidden email]
Subject: Re: JESS: Re: calculating benefit costs

In the interest of exploration and education, here's a few random thoughts.

The approach wolfgang mentions is an old knowledge base technique. I
like to use it for data that is "constant-like". Things like code
reference tables. One example of this is auto insurance rating. Many
companies rate based on zip code and assign a numeric value for each
zip code.

If a developer hard codes the constant in the rule, it means every
time the value changes, the rule would need to be updated. The problem
is actually worse than that. Say a company sells insurance in 5 states
and there's a total of 500 zip codes. Using the hard coded approach,
the developer would need to write 500 rules. If on the other hand, the
developer uses facts to match the insurance policy to a zip code
rating fact, we can easily change the rating value for a zipcode and
not affect the rules.

The downside is we need to have good management tools for editing the
reference data. All of the reference data should be versioned and
basic validation should be performed on the data before it is deployed
to production. Unfortunately, all of the products on the market today
do not provide robust tools for managing knowledge base data. In the
past, I've written custom applications for managing knowledge data in
financial applications.

For applications that have lots of code reference data that changes
regularly, I strongly recommend using fact data instead of hard coding
constants. The other benefit is tends to reduce lots of procedural
code in the RHS of the rule. Instead of using lots of if/then/else,
the rule tends to match the facts in the LHS and use the reference
data in the RHS. To put it another way, some of the calculations have
become pre-calculated codes. This can make the rules easier to read
and maintain. Also, by precalculating some of the data, we reduce the
amount of work the rule engine has to perform each time.

Using these types of knowledge base techniques also makes it easier to
write proof and validation routines to make sure the pre-calculated
tables are accurate. I would recommend reading books on knowledge base
and expert systems to get a broader understanding of rule programming.
Most of the business rule books out there are really just user manuals
and don't go into details on the design patterns used in expert
systems. Gary Riley's book is a great place to start.


As wolfgang stated,

On Sat, Jan 8, 2011 at 10:39 AM, Wolfgang Laun <[hidden email]> wrote:


> All the pundits advocate to put the decision logic into the LHS. Opinions
> vary a little wrt. to the use of static facts to
> reduce the number of rules. Some say, "The more rules the merrier." I feel
> that using static facts for lookup of data is justified, considering this:
>
> Fact data is easier to change than rule code.
> Putting the data into facts is one way of avoiding hard coded constants.
> Less code means less room for bugs.
>
> Now to the one rule that does it all, posted by Derek, with the cascading if
> on the RHS. Looking at the code, I've seen a few things which might be worth
> noting.
>
> calcAgeAsOf is called many times. Why not call once and save the result?
> Age limits and costs should be kept in a list to avoi code repetition by
> using a loop. globals are one way of making such data available.
> Setting a variable depending on ?rel and a single logic avoids code
> duplication.
> The cost result is stored in the object using a call of some Java method.
> But bypassing Jess when modifying facts is not a good idea, most of the
> time.
>
> Below is the much reduced code. Of course, it still has the major defeciency
> of too much logic on the RHS,
>
>
> (defglobal ?*limAge* = (list 30    40    50    60     70   )
>            ?*cstEmp* = (list 11.55 18.95 38.35 65.95 104.35)
>            ?*cstRel* = (list  4.20  6.05 10.90 17.80  27.40)
> )
>
> (defrule setCalculatedCostGCI20k5k
>   ?hbj <- (HrBenefitJoin (hrBenefitConfigId "00001-0000000076")
>              (benefitJoinId ?bjid)
> ;;           (calculatedCost ?cost)
>              (calculatedCost 0)
> ;;           (OBJECT ?obj)
>              (coveredPersonId ?cPer)
>              (payingPersonId ?pPer)
>              (relationshipId ?rel))
>     (Person (personId ?cPer)
>             (dob ?dob)
> ;;          (OBJECT ?objP)
>     )
> =>
> ; call once, bind result
>   (bind ?years (call ?objP calcAgeAsOf(call com.arahant.utils.DateUtils now
> )))
>
> ; avoids cut-and-paste repettion of code
>   (bind ?costs  (if (eq ?rel nil) then ?*cstEmp* else ?*cstRel* fi))
>
>   (bind ?cost nil)
>   (for (bind ?i 1) (<= ?i (length$  ?*limAge*)) (++ ?i)
>     (if (< ?years (nth$ ?i ?*limAge*)) then
>       (bind ?cost (nth$ ?i ?costs))
>       (break)
>     )
>   )
>
>   (if (eq ?cost nil) then
>     (printout t "age greater than 69... " ?years " for " ?bjid " " crlf)
>    else
> ;  Bypassing Jess when modifying is not a good idea, most of the time.
> ;   (call ?obj overrideAgeCost ?cost)
>     (modify ?hbj (calculatedCost ?cost))
>   )
> )
>
> -W
>
>
> On 7 January 2011 19:44, Jason Morris <[hidden email]> wrote:
>>
>> Hi Derek,
>>
>> OK OK... I wasn't going to say anything either but with Peter and James
>> added to Wolfgang, I have to pile too :-)
>>
>> IMHO there are a number of maxims of rule-based programming that you're
>> breaking here.  Ernest has put the first one most succinctly in the past:
>> Use many smaller rules that do one thing well rather than one Über Rule that
>> boils the ocean.  Declarative programming should say what action(s) are to
>> be performed when certain facts are present, but not attempt to implement
>> those actions directly on the RHS.
>>
>> The second, as James and Peter pointed out, is not to do Java programming
>> on the RHS.  If you make the RHS a series of method calls that take the
>> variable bindings from the LHS as arguments, your rules will be much cleaner
>> and maintainable.
>>
>> Finally -- and this is just a plain programming nit -- I noticed the
>> apparent use of magic numbers in your conditions.  What about all these
>> calls to overrideAgeCost()?  Where are those args coming from?  Are they
>> part of some policy? What if that policy changes?  Then your rules would be
>> in a "dirty" form.  Wouldn't it be better to get those values from some
>> cache or database with most current values?
>>
>> Something that might help you:
>> I've been collecting rule-based metaphors lately -- different ways of
>> thinking about using rules.  One metaphor that has been particularly
>> productive has been thinking about "digestion" and the passing of data
>> through a series of modules like a "digestive tract".  Obviously, if you
>> carry the metaphor too far ... well you see where the "garbage in/ garbage
>> out" saying comes into play. :-)  But the idea is that you are moving the
>> data through different states, partially processing it each time a new rule
>> module has a crack at it.  This has precedent in UNIX/LINUX with pipes --
>> same idea.  Old wine in a new bottle? Perhaps.  But this way, you can
>> clearly separate out concerns, add pre and post processing functions, and
>> test partial results by simply disabling/enabling certain modules in the
>> sequence.
>>
>> Cheers,
>> Jason
>>
>> ------------------------------------------------------
>> Jason Morris
>> Chairman, Rules Fest 2010/2011
>> http://www.rulesfest.org
>> Morris Technical Solutions LLC
>> [hidden email]
>> (517) 304-5883
>
>




--------------------------------------------------------------------
To unsubscribe, send the words 'unsubscribe jess-users [hidden email]'
in the BODY of a message to [hidden email], NOT to the list
(use your own address!) List problems? Notify [hidden email].
--------------------------------------------------------------------

This e-mail and any files transmitted with it are for the sole use of the intended recipient(s) and may contain confidential and privileged information.
If you are not the intended recipient, please contact the sender by reply e-mail and destroy all copies of the original message.
Any unauthorised review, use, disclosure, dissemination, forwarding, printing or copying of this email or any action taken in reliance on this e-mail is strictly
prohibited and may be unlawful.
Reply | Threaded
Open this post in threaded view
|

Re: JESS: Re: calculating benefit costs

Wolfgang Laun-2
Decision tables are an old design techniques, popular with business analysts since the 60s. Automated translation into code is what makes this approach so valuable, from a representation of tables as a spreadsheet, or in some other way. But consider (what is not an exhaustive analysis):
  • If you do not have automatic translation into rules, decision tables are a good means for specifying requirements. But this does not mean that manually mimicking a translator is a good implementation technique.
  • Implementing a spreadsheet-to-rule translator is not too difficult, provided you know your target language very well. (But read on.)
  • On principle, decision tables restrict the rule language to a selective and parameterized conjunctive combination of patterns and constraints. (Table rows (or columns) is linear, condition grammar is recursive.)
  • One decision table must result in a number of structurally similar rules. To fully exploit the power of a production system such as Jess, you'll need more than one table or additional hand-written rules.
  • Apparently, the spreadsheet as a file defining constants for constraints mitigates the issue of hard coded constants, but it doesn't really solve it. For one thing, you cannot use (additional) rules for their validation, as you mght do with a set of "constant facts".
Decision tables are just one technique among several for hiding or cushioning the intricacies of a rule language from greenhorn rule authors. But, at the bottom of it, designing and writing rules is a (sometimes taxing) work for programmers with experience, and no matter what the sales spiel of some rule vendor says: it's only simple things that really are simple.

-W



On 10 January 2011 04:04, <[hidden email]> wrote:

Now, we know how to do it using JESS, and concern is with other available rule engine vendors - how they are managing this situation, since this is pretty much common issue in most of IT-service industry projects using rule-engine for some business decision; and as of today, vendors are suggesting to use Decision Table concept to handle this homogeneous type rules. To my understanding, this is nothing but the representing of 'n' number of homogeneous type rules with different hard-coded constant values.
 
Please make my understanding correct.
 
 
Regards
 
DEBASISH DALUI (122816)
----------------------------------------------
Cognizant Technology Solutions US Corp

Cell  : +1-216-835-2902


Reply | Threaded
Open this post in threaded view
|

Re: JESS: Re: calculating benefit costs

Peter Lin
In reply to this post by Debasish.Dalui
from first hand experience and those of other seasoned rule consultants,
here's the pros/cons of using decision table.

pros

1. it's easy for a non-technical user to use if they are familiar with ms
office
2. it's easy if there's 2 dozen columns or less
3. the learning curve is lower
4. good fit for situations with a few rules


cons

1. tables with columns that require scrolling left/right become hard to
understand, even for business users. usually, this means too much business
logic is being jammed into a single table when the logic should be broken
into smaller pieces
2. tables with thousands of rows become difficult to understand and maintain
3. without good rule validation tools, it's easy to create invalid rules
that conflict with other rows in the decision table
4. tables are poor at expressing more complex rules that require
calculations or lookup code reference data


Lots of people have seen situations where a decision table had tens of
thousands of rows. I've personally seen cases where 50,000 rows of decision
table rules could be translated to several hundred rules. The key was taking
time to understand what the business wanted and making it easier to author
and manage. In this particular case, I built a pre-trade compliance engine
for a securities order management system.

As usual, the key to building a maintainable application is taking time to
understand the problem. If the application will never have more than a dozen
rules with a half dozen columns, decision table is a perfectly fine
solution.



On Sun, Jan 9, 2011 at 10:04 PM, <[hidden email]> wrote:

>  Hi all,
>
> Thanks a lot for the detail clarification of using the concept of
> 'fact-data' instead of hard-coding constants inside the rule (as you have
> explaned in your example, and rules in this scenario looks homogeneous, and
> only difference is the hard-code constant part).
>
> Now, we know how to do it using JESS, and concern is with other available
> rule engine vendors - how they are managing this situation, since this is
> pretty much common issue in most of IT-service industry projects using
> rule-engine for some business decision; and as of today, vendors are
> suggesting to use Decision Table concept to handle this homogeneous type
> rules. To my understanding, this is nothing but the representing of 'n'
> number of homogeneous type rules with different hard-coded constant values.
>
> Please make my understanding correct.
>
>
>     Regards
>
> DEBASISH DALUI (122816)
> ----------------------------------------------
> Cognizant Technology Solutions US Corp
> Cell  : +1-216-835-2902
>
> ------------------------------
> *From:* [hidden email] on behalf of Peter Lin
> *Sent:* Sun 1/9/2011 9:33 AM
>
> *To:* [hidden email]
> *Subject:* Re: JESS: Re: calculating benefit costs
>
>  In the interest of exploration and education, here's a few random
> thoughts.
>
> The approach wolfgang mentions is an old knowledge base technique. I
> like to use it for data that is "constant-like". Things like code
> reference tables. One example of this is auto insurance rating. Many
> companies rate based on zip code and assign a numeric value for each
> zip code.
>
> If a developer hard codes the constant in the rule, it means every
> time the value changes, the rule would need to be updated. The problem
> is actually worse than that. Say a company sells insurance in 5 states
> and there's a total of 500 zip codes. Using the hard coded approach,
> the developer would need to write 500 rules. If on the other hand, the
> developer uses facts to match the insurance policy to a zip code
> rating fact, we can easily change the rating value for a zipcode and
> not affect the rules.
>
> The downside is we need to have good management tools for editing the
> reference data. All of the reference data should be versioned and
> basic validation should be performed on the data before it is deployed
> to production. Unfortunately, all of the products on the market today
> do not provide robust tools for managing knowledge base data. In the
> past, I've written custom applications for managing knowledge data in
> financial applications.
>
> For applications that have lots of code reference data that changes
> regularly, I strongly recommend using fact data instead of hard coding
> constants. The other benefit is tends to reduce lots of procedural
> code in the RHS of the rule. Instead of using lots of if/then/else,
> the rule tends to match the facts in the LHS and use the reference
> data in the RHS. To put it another way, some of the calculations have
> become pre-calculated codes. This can make the rules easier to read
> and maintain. Also, by precalculating some of the data, we reduce the
> amount of work the rule engine has to perform each time.
>
> Using these types of knowledge base techniques also makes it easier to
> write proof and validation routines to make sure the pre-calculated
> tables are accurate. I would recommend reading books on knowledge base
> and expert systems to get a broader understanding of rule programming.
> Most of the business rule books out there are really just user manuals
> and don't go into details on the design patterns used in expert
> systems. Gary Riley's book is a great place to start.
>
>
> As wolfgang stated,
>
> On Sat, Jan 8, 2011 at 10:39 AM, Wolfgang Laun <[hidden email]>
> wrote:
> > All the pundits advocate to put the decision logic into the LHS. Opinions
> > vary a little wrt. to the use of static facts to
> > reduce the number of rules. Some say, "The more rules the merrier." I
> feel
> > that using static facts for lookup of data is justified, considering
> this:
> >
> > Fact data is easier to change than rule code.
> > Putting the data into facts is one way of avoiding hard coded constants