Hello,

While attempting to integrate Jess with some existing Java code, I
have stumbled across what I think is a very useful design pattern.  I
want to share this pattern with you guys and get your feedback on it.

Let's consider the following graph of Java objects:

                                                 +----------+
                 +----------------------+        | FuelLine |
                 |        Engine        | -----> +----------+
                 +----------------------+        | pressure |
+-------+        | running              |        +----------+
| Plane | -----> | requiredFuelPressure |
+-------+        +----------------------+        +----------+
                 | start                |        | Ignition |
                 | stop                 | -----> +----------+
                 +----------------------+        | running  |
                                                 +----------+

I want to pass this entire object graph into Jess and have rules
which can match across all of these objects.  I'll start by
defclass'ing all of the classes involved:

(defclass plane airport.Plane)
(defclass engine airport.Engine)
(defclass fuel-line airport.FuelLine)
(defclass ignition airport.Ignition)

Now I need to define rules to start and stop the engine:

1) The fuel-line must maintain a fuel pressure above a certain amount
   while the engine is in operation, or the engine will stall.

2) In order to start the engine, the fuel pressure must be over this
   limit and the ignition system must be engaged.

We need to be able to traverse the whole object graph to implement
each of these rules.  However, the plane is the only object that we
want definstance explicitly in our Java code.  We could try to
implement rule (1) by matching on (plane) and checking the rest of our
conditions with (test) and (call), but this looks quite ugly:

(defrule engine-ignition
  (plane (engine ?e))
  (test (> (call (call ?e getFuelLine) getPressure)
           (call ?e getRequiredFuelPressure)))
  (test (call (call ?e getIgnition) isRunning))
  (test (not (call ?e isRunning)))
=>
  (call ?e start))

I would much prefer to match each object as a separate fact:

(defrule engine-ignition
  (plane (engine ?e))
  (engine (OBJECT ?e)
          (ignition ?i)
          (fuelLine ?f)
          (requiredFuelPressure ?required)
          (running FALSE))
  (ignition (OBJECT ?i)
            (running TRUE))
  (fuel-line (OBJECT ?f)
             (pressure ?pressure))
  (test (> ?pressure ?required))
=>
  (call ?e start))

(defrule engine-stalls
  (plane (engine ?e))
  (engine (OBJECT ?e)
          (fuelLine ?f)
          (requiredFuelPressure ?required)
          (running TRUE))
  (fuel-line (OBJECT ?f)
             (pressure ?pressure))
  (test (< ?pressure ?required))
=>
  (call ?e stop))

In order for this to work, we need to use backward chaining so that
each object is definstance'd when required.  Not only do we need to
turn on backwards-chaining for each class, but we need to add a rule
that looks for need-* facts with an explicit value set in the OBJECT
slot and then uses that value to definstance the object.

(do-backwards-chaining engine)
(defrule allow-navigation-for-engine
  (need-engine (OBJECT ?obj&~nil))
=>
  (definstance ?obj))

Because this code needs to be repeated for each class, I wrote my own
version of (defclass) which does it automatically:

;; Jess Object Graph Navigation
;; Usage:  (jogn-defclass templateName javaClass static|dynamic)
(deffunction jogn-defclass (?type ?c ?dynamic)
  (defclass ?type ?c)
  (do-backward-chaining ?type)
  (eval (str-cat
    "(defrule declare-" ?type
    "  (need-" ?type " (OBJECT ?obj&~nil))"
    " => "
    "  (definstance " ?type " ?obj " ?dynamic "))")))

Is this functionality that should simply be built into Jess?  Is there
ever a time when it would not be valid to automatically definstance an
object when the OBJECT slot is explicitly requested?

If not, is this a useful design pattern?  Or am I missing an easier or
more elegant way to navigate an object graph?

Can anyone think of a clever way to extend this style of rule matching
to support one-to-many associations (e.g., if a plane contained a list
of engines) ? I haven't had much luck with this.

Thanks,
Don


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

Reply via email to