OK - here is a first cut at an explanation of "parametric, polymorphic
rules"
Please find attached a text file
Thank You
----- Original Message -----
From: <[EMAIL PROTECTED]>
To: <[EMAIL PROTECTED]>
Sent: Tuesday, August 26, 2003 1:19 PM
Subject: Re: JESS: Re: Subrules
> I think Rich Halsey wrote:
>
> > This already exists in JESS whether you match on classes or
> > interfaces, it's just that many people do not even consider using it
> > because it is somewhat abstract (it is definitely NOT "see spot
> > run").
>
> Hmmmm. Can you give us an example of what you're talking about --
> sounds interesting!
>
>
>
> ---------------------------------------------------------
> Ernest Friedman-Hill
> Distributed Systems Research Phone: (925) 294-2154
> Sandia National Labs FAX: (925) 294-2234
> PO Box 969, MS 9012 [EMAIL PROTECTED]
> Livermore, CA 94550 http://herzberg.ca.sandia.gov
>
> --------------------------------------------------------------------
> To unsubscribe, send the words 'unsubscribe jess-users [EMAIL PROTECTED]'
> in the BODY of a message to [EMAIL PROTECTED], NOT to the list
> (use your own address!) List problems? Notify [EMAIL PROTECTED]
> --------------------------------------------------------------------
>
Polymorphic Rules
-----------------
Assume we have some base class such as:
class Animal {
protected boolean hungry = false;
protected String name = null;
protected String sound = null;
protected String food = null;
public Animal(String _name, boolean _hungry, String _sound, String _food) {
name = _name;
hungry = _hungry;
sound = _sound;
food = _food;
}
public boolean isHungry() {
return( hungry );
}
public void speak() {
System.out.println("I am a " + name + " and I say " + sound}
}
public void eats() {
System.out.println("I eat " + food}
}
}
} // end class
and some derived classes with the method speak overridden:
class Dog extends Animal {
public Dog(String _name, boolean _hungry, String _sound, String _food) {
super(_name, _hungry, _sound, _food)
}
} // end class
class Cat extends Animal {
public Cat(String _name, boolean _hungry, String _sound, String _food) {
super(_name, _hungry, _sound, _food)
}
} // end class
class Bird extends Animal {
public Bird(String _name, boolean _hungry, String _sound, String _food) {
super(_name, _hungry, _sound, _food)
}
} // end class
Then if we construct some rule (using pseudocode):
/////////////////////////////////////////////////////////////////////////////////////
Rule AnimalSound {
if
thereExists Animal pet;
then
pet.speak();
}
/////////////////////////////////////////////////////////////////////////////////////
And we assert instantiations of a Dog, Cat, and a Bird into the working memory as in:
RuleEngine.assert( new Dog("Dog", true, "WOOF") );
RuleEngine.assert( new Cat("Cat", true, "MEOW") );
RuleEngine.assert( new Bird("Bird", true, "CHOIP") );
and when we signal the engine to run, our rule system should produce as
output the following lines in some order:
I am a Dog and I say WOOF
I am a Cat and I say MEOW
I am a Bird and I say MEOW
As we can see, there is only a single rule defined and it matches objects by a base
class
on the LHS. Where a match occurs the method "speak()" is invoked on the RHS. If we had
defined
the base class Animal as an interface instead of a class and then implemented this
interface
for the Dog, Cat, and Bird classes the rule would have worked exactly as before.
Obviously,
using an interface instead of a base class for matching has its own design
considerations
for the rules.
This rule "polymorphism" exists in JESS as a byproduct of Java and can be used to
simplify
the implementation of a rule-based system. However, it does add a level of abstraction
since
the rules are NOT explicitly searching for derived classes (interfaces) but match on
the
base class (interface). The abstraction gets deeper as you define deeper hierarchies of
classes (interfaces). As in "there is no free lunch", the tradeoff must be considered
when
building the system - can the people who maintain the resulting rule system understand
the
abstraction or will it overwhelm them ?
Parametric Rules
----------------
If we have a system that uses another rule to match Dog, Cat, or Bird objects to Food
objects and we define a Food class hierarchy as:
class Food {
public Food() {}
} // end class
class Bone extends Food {
public Bone() {
super();
}
} // end class
class Seed extends Food {
public Seed() {
super();
}
} // end class
class Tuna extends Food {
public Tuna() {
super();
}
} // end class
Of course, our pets have a menu to choose from which is based on a decision table
meaning
that they will eat only when certain conditions have been met in the decision table,
as in:
boolean petHungry T F T F
boolean compatibleFoodType T T F F
Knowing this, we prepare a class to hold the situations defined in the decision table.
class MenuDecision {
public boolean petHungry = false;
public boolean compatibleFoodType = false;
public Food foodType = null;
public Animal petType = null;
public MenuDecision(boolean _petHungry, boolean _compatibleFoodType,
Food _foodType, Animal _petType) {
petHungry = _petHungry;
compatibleFoodType = _compatibleFoodType;
foodType = _foodType;
petType = _petType;
}
}
} // end class
Now we assert instantiations of a Dog, Cat, and a Bird into the working memory as in:
RuleEngine.assert( new Dog("Dog", true, "WOOF") );
RuleEngine.assert( new Cat("Cat", true, "MEOW") );
RuleEngine.assert( new Bird("Bird", true, "CHOIP") );
and then we instantiate some food objects:
RuleEngine.assert( new Bone() );
RuleEngine.assert( new Seed() );
RuleEngine.assert( new Tuna() );
and (finally) we instantiate some MenuDecision objects to represent the decision
table situations. Obviously, this may not represent the total picture of what we
are doing, but ... :
RuleEngine.assert( new MenuDecision(true, true, Bone, Dog) );
RuleEngine.assert( new MenuDecision(true, false, Bone, Cat) );
RuleEngine.assert( new MenuDecision(true, false, Tuna, Dog) );
RuleEngine.assert( new MenuDecision(false, false, Tuna, Dog) );
Since this is only for fun, I can claim that I have already defined a rule:
/////////////////////////////////////////////////////////////////////////////////////
Rule AnimalEats {
if
thereExists Animal pet;
thereExists Food petFood;
thereExists MenuDecision menuDecision(
petType == pet;
foodType == petFood;
petHungry == pet.hungry;
compatibleFoodType == true;
;
then
pet.eat();
}
/////////////////////////////////////////////////////////////////////////////////////
Now, we have a one-rule system that analyzes all the possible situations from our
decision table and where the rule matches according to our specification we will
get our results.
I have used 3 pets, 3 foods, and 4 situations which should make 36 possible
combinations
to analyze by one rule. If one can imagine a larger system with, let's say 200 pet
types,
300 types of food, and the same number of situations then one should see that by
raising
the abstraction we can begin to get our arms (and whatever) around the problem. If we
did
not use this kind of abstraction and we also had other rules where forward chaining
comes
into play then we might wish we had taken another career path.
Hopefully, I wrote all of this correctly - no, I did not try to compile it. If there
are
mistakes then maybe we can all try to fix it. I have used this technique very
successfully
on different projects. This was NOT intended for the "guru" class but for the mere
mortals
out here who struggle while trying to fathom the magic of rule based engineering.
If you got this far, thank you for your patience -
Rich Halsey