Re: JESS: Re: calculating benefit costs

2011-01-10 Thread Peter Lin
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,  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:* owner-jess-us...@sandia.gov on behalf of Peter Lin
> *Sent:* Sun 1/9/2011 9:33 AM
>
> *To:* jess-users@sandia.gov
> *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

Re: JESS: Re: calculating benefit costs

2011-01-10 Thread Wolfgang Laun
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,  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
>
>


RE: JESS: Re: calculating benefit costs

2011-01-09 Thread Debasish . Dalui

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: owner-jess-us...@sandia.gov on behalf of Peter Lin
Sent: Sun 1/9/2011 9:33 AM
To: jess-users@sandia.gov
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  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,
>
>
> (defgloba

Re: JESS: Re: calculating benefit costs

2011-01-09 Thread James Owen
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.) SDGjcoCoFounder DRG 2000CoFounder October Rules Fest 2008/2009CoFounder and Speaker (O)RF 2010/2011

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 becauseI really had no clue what expert systems was or what a knowledge basecan do. I had to learn through trial and error the hard way to realizemany of the techniques described in Gary's book are invaluable. It'sjust that I wasn't able to absorb those ideas and approaches until Ihad acquired sufficient experience.there's definitely a need for a book that applies expert system andknowledge base techniques to business problems. in my bias opinionJess In Action is one of those rare books, but there is a lot morebeyond Jess in Action. For me, it is the best place to start. Mileagewill vary depending on the problem and project requirements obviously.peterOn Sun, Jan 9, 2011 at 9:58 AM, Donald Paul Winston 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 baseand expert systems to get a broader understanding of rule programming.Most of the business rule books out there are really just user manualsand don't go into details on the design patterns used in expertsystems. Gary Riley's book is a great place to start.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.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.

Re: JESS: Re: calculating benefit costs

2011-01-09 Thread 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
 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 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.
> 
>
>





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.




Re: JESS: Re: calculating benefit costs

2011-01-09 Thread Donald Paul 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 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.




Re: JESS: Re: calculating benefit costs

2011-01-09 Thread 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  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 "1-76")
>  (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))
>

Re: JESS: Re: calculating benefit costs

2011-01-08 Thread Wolfgang Laun
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 30405060 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 "1-76")
 (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  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
> consult...@morris-technical-solutions.com
> (517) 304-5883
>


RE: JESS: Re: calculating benefit costs

2011-01-07 Thread Debasish . Dalui

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
 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 "1-76")(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 (< (cal

Re: JESS: Re: calculating benefit costs

2011-01-07 Thread 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
consult...@morris-technical-solutions.com
(517) 304-5883


Re: JESS: Re: calculating benefit costs

2011-01-07 Thread Peter Lin
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
 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 "1-76")(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 
> 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 "1-73")
>> (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 "1-73")
>> (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) )
>>
>> 

Re: JESS: Re: calculating benefit costs

2011-01-07 Thread Donald Paul 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 "1-76")(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  
> 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 "1-73")
> (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 "1-73")
> (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  wrote:
> > the f

Re: JESS: Re: calculating benefit costs

2011-01-07 Thread James Owen
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 "1-76")(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  
> 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 "1-73")
> (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 "1-73")
> (calculatedCost 0)
> {relationshipId  != nil}
> (payingPersonId  ?pPer)
> (coveredPersonId ?cPer) )

Re: JESS: Re: calculating benefit costs

2011-01-07 Thread 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 "1-76")(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 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 "1-73")
> (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 "1-73")
> (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  wrote:
> > the facts that I am working with are:
> >
> > (HrBenefitJoin (hrBenefitConfigId "1-73")(benefitJoinId
> > ?bjid)(calculatedCost ?cost)(OBJECT ?obj)(coveredPersonId
> > ?cPer)(payingPersonId ?pPer)(relationshipId ?rel))
> > (Person (personId ?cP