next up previous

5.4.8 Logical Conditional Element

The logical conditional element provides a truth maintenance capability for pattern entities (facts or instances) created by rules which use the logical CE. A pattern entity created on the RHS (or as a result of actions performed from the RHS) can be made logically dependent upon the pattern entities which matched the patterns enclosed with the logical CE on the LHS of the rule. The pattern entities matching the LHS logical patterns provide logical support to the facts and instance created by the RHS of the rule. A pattern entity can be logically supported by more than one group of pattern entities from the same or different rules. If any one supporting pattern entities is removed from a group of supporting pattern entities (and there are no other supporting groups), then the pattern entity is removed.

If a pattern entity is created without logical support (e.g., from a deffacts, definstaces, as a toplevel command, or from a rule without any logical patterns), then the pattern entity has unconditional support. Unconditionally supporting a pattern entity removes all logical support (without causing the removal of the pattern entity). In addition, further logical support for an unconditionally supported pattern entity is ignored. Removing a rule that generated logical support for a pattern entity, removes the logical support generated by that rule (but does not cause the removal of the pattern entity if no logical support remains).

Syntax

<logical-CE> ::= (logical <conditional-element>+)

The logical CE groups patterns together exactly as the explicit and CE does. It may be used in conjunction with the and, or, and not CEs. However, only the first N patterns of a rule can have the logical CE applied to them. For example, the following rule is legal

(defrule ok
   (logical (a))
   (logical (b))
   (c)
   =>
   (assert (d)))

whereas the following rules are illegal

(defrule not-ok-1
   (logical (a))
   (b)
   (logical (c))
   =>
   (assert (d)))
(defrule not-ok-2
   (a)
   (logical (b))
   (logical (c))
   =>
   (assert (d)))
(defrule not-ok-3
   (or (a)
       (logical (b)))
   (logical (c))
   =>
   (assert (d)))

Example

Given the following rules,

CLIPS> (clear)
CLIPS>
(defrule rule1
   (logical (a))
   (logical (b))
   (c)
   =>
   (assert (g) (h)))
CLIPS>
(defrule rule2
   (logical (d))
   (logical (e))
   (f)
   =>
   (assert (g) (h)))
CLIPS>

the following commands illustrate how logical dependencies work.

CLIPS> (watch facts)
CLIPS> (watch activations)
CLIPS. (watch rules)
CLIPS> (assert (a) (b) (c) (d) (e) (f))
==> f-0     (a)
==> f-1     (b)
==> f-2     (c)
==> Activation 0      rule1: f-0,f-1,f-2
==> f-3     (d)
==> f-4     (e)
==> f-5     (f)
==> Activation 0      rule2: f-3,f-3,f-5
<Fact-5>
CLIPS> (run)
FIRE    1 rule2: f-3,f-4,f-5 ; 1st rule adds logical support
==> f-6     (g)
==> f-7     (h)
FIRE    2 rule1: f-0,f-1,f-2 ; 2nd rule adds further support
CLIPS> (retract 1)
<== f-0     (a)           ; Removes 1st support for (g) and (h)
CLIPS> (assert (h))       ; (h) is unconditionally supported
FALSE
CLIPS> (retract 3)
<== f-3     (d)              ; Removes 2nd support for (g)
<== f-6     (g)              ; (g) has no more support
CLIPS> (unwatch all)
CLIPS>

As mentioned in section 5.4.1.7, the logical CE can be used with an object pattern to create pattern entities which are logically dependent on changes to specific slots in the matching instance(s) rather than all slots. This cannot be accomplished with template facts because a change to a template fact slot actually involves the retraction of the old template fact and the assertion of a new one, whereas a change to an instance slot is done in place. The example below illustrates this behavior:

CLIPS> (clear)
CLIPS>
(defclass A (is-a USER)
  (role concrete)
  (pattern-match reactive)
  (slot foo (create-accessor write))
  (slot bar (create-accessor write)))
CLIPS>
(deftemplate A
  (slot foo)
  (slot bar))
CLIPS>
(defrule match-A-s
  (logical (object (is-a A) (foo ?))
           (A (foo ?)))
=>
  (assert (new-fact)))
CLIPS> (make-instance a of A)
[a]
CLIPS> (assert (A))
<Fact-0>
CLIPS> (watch facts)
CLIPS> (run)
==> f-1     (new-fact)
CLIPS> (send [a] put-bar 100)
100
CLIPS> (agenda)
CLIPS> (modify 0 (bar 100))
<== f-0     (A (foo nil) (bar nil))
<== f-1     (new-fact)
==> f-2     (A (foo nil) (bar 100))
<Fact-2>
CLIPS> (agenda)
0      match-A-s: [a],f-2
For a total of 1 activation.
CLIPS> (run)
==> f-3     (new-fact)
CLIPS> (send [a] put-foo 100)
<== f-3     (new-fact)
100
CLIPS> (agenda)
0      match-A-s: [a],f-2
For a total of 1 activation.
CLIPS> (unwatch facts)
CLIPS>


next up previous