Re: JESS: Jess Access Control

2011-01-07 Thread Ernest Friedman-Hill


On Jan 7, 2011, at 8:06 PM, Michael Eugene Artz wrote:
 It's a casting error but it doesn't make any sense to me why I  
would be getting that.


userProfiles is a java.util.Set. The method Set.add() returns boolean  
(true means the add() succeeded, false means the object was already in  
the set.) So here you're mapping Integer to Boolean.



 profiles.put(new Integer(1), userProfiles.add(new Profile(1,  
"Mike", "Artz")));
 profiles.put(new Integer(2), userProfiles.add(new Profile(2,  
"Suzy", "Kolber")));
 profiles.put(new Integer(3), userProfiles.add(new Profile(3,  
"Stan", "Mikita")));
 profiles.put(new Integer(4), userProfiles.add(new Profile(4,  
"Nikita", "Kruschev")));




Here you're assuming that the values in profiles are Profile objects,  
but as we said, they're Booleans.




 public Profile getProfile(int profileNumber)
 {
  //return new Profile(1, "Mike", "Artz");
  return (Profile)profiles.get(new Integer(profileNumber));
 }



Which is what the error says: the values are Booleans, not Profiles.  
The trace tells you exactly what line causes the errors, so a  
println() or two would have easily told you the whole story.



java.lang.ClassCastException: java.lang.Boolean cannot be cast to  
Profile

at DemoDatabase.getProfile(DemoDatabase.java:49)
at Demo.processRole(Demo.java:31)
at Demo.main(Demo.java:13)


I wonder if I could this all much simpler and Im just wasting my  
time completely:(





When I assemble a large program like this, I start with a small  
program that does one little thing, and I test it. I then add a little  
more, and test that, and so on. At each step, I make sure all the new  
code does what it's supposed to do. I keep all the test code so it can  
be run at any time to verify that the program still works. That way,  
you never find yourself looking at a big pile of code and wondering  
where the problem is: the problem is always just in that last little  
bit you just coded.


Good luck!


-
Ernest Friedman-Hill
Informatics & Decision Sciences  Phone: (925) 294-2154
Sandia National Labs
PO Box 969, MS 9012ejfr...@sandia.gov
Livermore, CA 94550 http://www.jessrules.com






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.




JESS: Jess Access Control

2011-01-07 Thread Michael Eugene Artz

Hi, Im trying to do a simple Access control program using Jess.  Everything 
pretty much shadows the Pricing example that comes with Jess.  I changed only a 
few variable names and modified a couple of the parts that weren't need, 
because mine should be actually simpler.  All I want to do is have a handfule 
of rules that check for a user info with respect to a certain file and decides 
whether they have read-write priveledges or just read priveledges.  And also to 
assign read-write priveledges to users if they are owners of the respected file 
that they want to access.  I am sorry if its just some simple error, but I have 
been stumped on this for some time, so I don't know what to do.  Right now my 
Java classes  are in seperate files in the same package, but Ill just cut and 
paste them all here so it will be easier to look at them.  The file after all 
the JAva files is my .clp JEss file, then after that is the error I'm getting.  
It's a casting error but it doesn't make any sense
  to me why I would be getting that.  Anyway , they look like:



import java.util.ArrayList;
import java.util.Collection;

public interface Database
{
 public Collection getFiles();
 public Profile getProfile(int profileNumber);
}




import java.util.Iterator;
import jess.JessException;
public class Demo {
 public static void main(String[] args) {
  try {
   DemoDatabase database = new DemoDatabase();
   UserAccessEngine engine = new UserAccessEngine(database);

   processRole(database, engine, 1);
   processRole(database, engine, 2);
   processRole(database, engine, 3);
   processRole(database, engine, 4);
  }
  catch (JessException e)
  {
   e.printStackTrace();
  }
 }
 private static void processRole(DemoDatabase database, UserAccessEngine 
engine, int aID) throws JessException
 {
  //Iterator files, prints out a message prior to getting the needed info
  Iterator roles;
  System.out.println("First and Last Name of User " + aID + ":");
  String firstName = database.getProfile(aID).getfirst();
  String lastName = database.getProfile(aID).getlast();
  System.out.println(firstName + " " + lastName);

  roles = engine.run(aID);
  System.out.println("Roles for " + firstName + ":");
  while (roles.hasNext())
  {
   System.out.println("   " + roles.next());
  }
  System.out.println();
 }
}






import java.util.ArrayList;
import java.util.Map;
import java.util.Collection;
import java.util.HashMap;
/**
 * A toy implementation of the Database interface with some
 * hard-coded file and profile data.
 */

public class DemoDatabase implements Database {
 private ArrayList files;
 private Profile profile;
 private Map profiles;
 public DemoDatabase()
 {
  createFiles();
  createProfiles();
 }

 private void createProfiles()
 {
  profiles = new HashMap();
  ArrayList userProfiles = new ArrayList();
 profiles.put(new Integer(1), userProfiles.add(new Profile(1, "Mike", 
"Artz")));
 profiles.put(new Integer(2), userProfiles.add(new Profile(2, "Suzy", 
"Kolber")));
 profiles.put(new Integer(3), userProfiles.add(new Profile(3, "Stan", 
"Mikita")));
 profiles.put(new Integer(4), userProfiles.add(new Profile(4, "Nikita", 
"Kruschev")));

 }
 private void createFiles() {
  files = new ArrayList();
  files.add(new FileRead("Mike", "Artz", "file.txt", 1));
  files.add(new FileRead("Tom", "Saywer", "picOfYourMom.jpg", 5));
  files.add(new FileRead("Chris", "Webber", "NBAJAMS.exe", 6));
 }
 public Collection getFiles() {
  return files;
 }
 public Profile getProfile(int profileNumber)
 {
  //return new Profile(1, "Mike", "Artz");
  return (Profile)profiles.get(new Integer(profileNumber));
 }
}




public class FilePermission
{
private String fileName;
private int profileNum;
private String last;
private String first;
private String role;


public FilePermission(String aFileName, int aProfileNum, String aLast, String 
aFirst, String aRole)
{
last = aLast;
first = aFirst;
fileName = aFileName;
profileNum = aProfileNum;
role = aRole;
}

public String getfileName()
{
return fileName;
}

public int getprofileNum()
{
return profileNum;
}
public String getlast()
{
return last;
}

public String getfirst()
{
return first;
}

public String getrole()
{
return role;
}
}







public class FileRead
{
private String ownerFirst;
private String ownerLast;
private String file;
private int ownerID;

public FileRead(String aFirst, String aLast, String aFile, int aOwnerID)
{
ownerFirst = aLast;
ownerLast = aFirst;
file = aFile;
ownerID = aOwnerID;
}

 
public String getownerFirst()
{
return ownerFirst;
}

public String getownerLast()
{
return ownerLast;
}

public String getFile()
{
return file;
}

public int getownerID()
{
return ownerID;
}
}


public class Profile
{
private String last;
private String first;
private int idNum;


public Profile(int aID, String aFirst, String aLast)
{
idNum = aID;
last = aLast;
first = aFirst;
}

public String getlast()
{
return last;
}

public String getfirst()
{
return first;
}

public int getidNum()
{
return 

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 (< (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
> 

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: Rule firing during execution of RHS

2011-01-07 Thread Ernest Friedman-Hill
It is atomic with respect to other rules firing; only one rule can be  
firing at a time. It's not atomic with respect to working memory  
changes, though; working memory can be changed by other threads while  
the RHS of a rule is executing.


On Jan 7, 2011, at 12:47 PM, Nguyen, Son wrote:



Hi,

Execution of a rule RHS is sequential. But is it atomic?
In other words, during that time, is it possible that other  
activated rules get fired?
These activated rules include those that had been on the agenda or  
newly activated rules due to pattern matching caused by the RHS  
invocation of modify, assert or retract.


Any feedback is greately appreciated.

Son Nguyen



-
Ernest Friedman-Hill
Informatics & Decision Sciences, Sandia National Laboratories
PO Box 969, MS 9012, Livermore, CA 94550
http://www.jessrules.com








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.




JESS: Rule firing during execution of RHS

2011-01-07 Thread Nguyen, Son

Hi,

Execution of a rule RHS is sequential. But is it atomic?
In other words, during that time, is it possible that other activated
rules get fired?
These activated rules include those that had been on the agenda or newly
activated rules due to pattern matching caused by the RHS invocation of
modify, assert or retract.

Any feedback is greately appreciated.

Son Nguyen


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

JESS: Re: calculating benefit costs

2011-01-07 Thread Wolfgang Laun
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 ?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
> 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  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 calc