My application requires a notion of equivalence between objects. The
objects are represented as Jess atoms and have some type associated
with them. At first I implemented this as a fact template that
recorded the equivalence of two objects (of a specified type) and a
set of rules to implement the reflexive, symetric and transitive
properties of equality. This led to much fact clutter and it was
tedious to determine which objects were equivalent to one another.
I now implement the equivalence as a multislot in the template
(deftemplate equiv
(slot type)
(multislot set))
where two objects (of a given type) are equivalent if they are equal
or there's an EQUIV fact whose SET slot contains both of them
(or (test (eq ?thing1 ?thing2))
(and (equiv (type $type) (set $?set))
(test (and (member$ ?thing1 $?set)
(member$ ?thing2 $?set)))))
When an EQUIV is asserted, there is a rule that merges EQUIVs if they
share a member:
(defrule equiv-equiv-merge
?fact1 <- (equiv (type ?type) (set $?set1))
?fact2 <- (equiv (type ?type) (set $?set2))
; Avoid symetric firings of this rule by imposing an order on
; the two above facts.
(test (< (call ?fact1 getFactId)
(call ?fact2 getFactId)))
(test (or (> (length$ (intersection$ $?set1 $?set2))
(length$ $?set1))
(> (length$ (intersection$ $?set1 $?set2))
(length$ $?set2))))
=>
(assert (equiv (type ?type)
(set (union$ $?set1 $?set2))))
(retract ?fact1)
(retract ?fact2))
To obtain reflexivity I at first asserted an EQUIV fact for each
object. To decrease fact clutter I've since resorted to the Eqness
test when testing for equivalence.
I wish there were some way to abstract the equivalence test into a
function or something that can be called from the left hand side of a
rule since it's rather cumbersome using it in many places and makning
changes to it like the test for EQness described above.
My current problem is that I now have a rule that requires the
negation of the equivalence test:
(defrule faces-with-two-shared-segments
;; Every face that is common to two different segments is equivalent
;; to every other face that is common to those same two segments.
?fact1 <- (segment-face (edge ?segment1)
(edge-side ?side1)
(face ?face1))
?fact2 <- (segment-face (edge ?segment2)
(edge-side ?side2)
(face ?face2))
(test (not (eq ?segment1 ?segment2)))
(test (> (call ?fact1 getFactId)
(call ?fact2 getFactId)))
;; are ?face1 and ?face2 equivalent?
(or (test (eq ?face1 ?face2))
(and (equiv (type face) (set $?set1))
(test (and (member$ ?face1 $?set1)
(member$ ?face2 $?set1)))))
;; Other faces common to those segments:
(segment-face (edge ?segment1)
(edge-side ?side3)
(face ?face3))
(segment-face (edge ?segment2)
(edge-side ?side4)
(face ?face4))
;; are ?face3 and ?face4 equivalent?
(or (test (eq ?face3 ?face4))
(and (equiv (type face) (set $?set2))
(test (and (member$ ?face3 $?set2)
(member$ ?face4 $?set2)))))
;; ?face2 and ?face3 are not already equivalent
** HERE:
(and (test (neq ?face2 ?face3))
(not (and (equiv (type face) (set $?set3))
(test (and (member$ ?face2 $?set3)
(member$ ?face3 $?set3))))))
=>
(assert-equiv face ?face2 ?face3))
I've tried various transformations of that test (via DeMorgan''s
theorem) but I keep getting an error like this one (for the code
above):
==> f-124 (MAIN::segment-face (face C-face-24) (edge "cord-1[3]") (edge-side
side-40))
Jess exception: Jess reported an error in routine ValueVector.get
while executing (member$ ?face2 ?set3)
while executing (and (member$ ?face2 ?set3) (member$ ?face3 ?set3))
while executing 'test' CE
while executing rule LHS (Node2)
while executing rule LHS (Node2)
while executing rule LHS (Node2)
while executing rule LHS (Node2)
while executing rule LHS (TECT)
while executing (assert (MAIN::opposites circular-direction ?circ7 ?circ8)
(MAIN::opposites segment-side ?side7 ?side8)
(MAIN::cp-circular (crosspoint ?cp)
(segment ?seg-d)
(segment-direction out)
(circular-direction ?circ7)
(face ?face4))
(MAIN::segment-face (face ?face4)
(edge ?seg-d)
(edge-side ?side7))
(MAIN::cp-circular (crosspoint ?cp)
(segment ?seg-a)
(segment-direction in)
(circular-direction ?circ8)
(face ?face4))
(MAIN::segment-face (face ?face4)
(edge ?seg-a)
(edge-side ?side8)))
while executing defrule MAIN::faces-and-segments-at-crosspoint.
Message: Bad index 1 in call to get() on this vector: (MAIN::__not_or_test_CE).
I assume this must have something to do owith the NOT but from my
reading of the documentation I don't see that I'm using it
incorrectly. The only new binding in that clause is for $?set3, and
it's not used outside the clause.
I'm frustrated as it's taken me several weeks so far to come up with a
manageable implementation of equivalence and I/m still not sure I'm
on the right track.
--------------------------------------------------------------------
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]
--------------------------------------------------------------------