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: owner-jess-us...@sandia.gov on behalf of Peter Lin
Sent: Fri 1/7/2011 11:58 AM
To: jess-users@sandia.gov
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
<satchwins...@yahoo.com> 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 <wolfgang.l...@gmail.com>
> 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 <dad...@arahant.com> 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
>> > <wolfgang.l...@gmail.com>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 <wolfgang.l...@gmail.com> 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 y...@address.com'
>> in the BODY of a message to majord...@sandia.gov, NOT to the list
>> (use your own address!) List problems? Notify owner-jess-us...@sandia.gov.
>> --------------------------------------------------------------------
>>
>
>
>
> --
> Derek Adams
> Lead Developer
> Arahant LLC
> Work: 615-376-5500 ext. 314
> Cell: 270-543-0920
>
>




--------------------------------------------------------------------
To unsubscribe, send the words 'unsubscribe jess-users y...@address.com'
in the BODY of a message to majord...@sandia.gov, NOT to the list
(use your own address!) List problems? Notify owner-jess-us...@sandia.gov.
--------------------------------------------------------------------





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 via email to