;; -*-Mode: Lisp-*- 
;; $Id: rules.lsp,v 1.11 2001/04/25 22:27:46 moltmans Exp $
;; rules.lsp -- 
;; Author: Michael Oltmans <moltmans@ai.mit.edu> 
;; Created: <Wed Jan 24 18:21:04 2001> 
;; Time-stamp: <2001-04-13 14:03:14 moltmans> 

;; Should consider an energy based model.  Every event is the
;; consumption/transfer of energy.  Springs, gravity, exogenous
;; forces, contacting bodies

;; Need a mechanism to detect actual contradictions between the world
;; and the explanation and tell the user that they want something that
;; we don't think makes sense.  For example, they want an anchored
;; body to move.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Bodies can move until indicated otherwise
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(rule ((:INTERN (body ?body) :VAR ?f1))
  (rassert! (:IFF (can-move ?body)
		  (:OR (can-translate ?body)
		       (can-rotate ?body)))
	    :BODIES-CAN-MOVE-IFF-THEY-CAN-TRANSLATE-OR-ROTATE))

;; If a body can move it must be able to rotate or translate.  This
;; makes a contradiction if someone tries to move an anchored body
(rule ((:INTERN (moves ?body ?id) :VAR ?f1))
  (rassert! (:IFF ?f1
		  (:OR (translates ?body ?id)
		       (rotates ?body ?id)))
	    :MOTION-IS-ROTATION-OR-TRANSLATION))

;; need somthing to say that if moves and not can-rotate then can-translate
;; and vice versa
(rule ((:TRUE (moves ?body ?id) :VAR ?f1))
  (rule ((:FALSE (can-rotate ?body) :VAR ?f2))
    (rassert! (:IMPLIES (:AND ?f1 (:NOT ?f2)) (:NOT (rotates ?body ?id)))
	      :CANNOT-ROTATE-IF-CANNOT-ROTATE))
  (rule ((:FALSE (can-translate ?body) :VAR ?f2))
    (rassert! (:IMPLIES (:AND ?f1 (:NOT ?f2)) (:NOT (translates ?body ?id)))
	      :CANNOT-TRANSLATE-IF-CANNOT-TRANSLATE)))

;; This is necessary to enforce the contradtiction of the user
;; indicating the motion of an unmoveable object
; (rule ((:INTERN (moves ?body ?id) :VAR ?moves)
;        (:INTERN (can-move ?body) :VAR ?can-move))
;   (rassert! (:IMPLIES ?moves ?can-move)
; 	    :IF-IT-MOVES-IT-CLEARLY-CAN-MOVE))

;; Anchored bodies cannot move
(rule ((:INTERN (attaches ?anchor ?body) :VAR ?f1)
       (:INTERN (body ?body) :VAR ?f2)
       (:INTERN (anchor ?anchor) :VAR ?f3))
      (rassert! (:IMPLIES (:AND ?f1 ?f2 ?f3)
			  (:NOT (:OR (can-translate ?body)
				     (can-rotate ?body))))
		:ANCHOR-STOPS-TRANSLATION))

(assume! '(:NOT (can-move background)) :BACKGROUND-IS-FIXED-BY-DEFINITION)

;; Jointed bodies don't move if they are attached to immobile objects
(rule ((:TRUE (attaches ?pin ?body1) :VAR ?f1)
       (:TRUE (attaches ?pin ?body2) :TEST (not (eq ?body1 ?body2))
	      :VAR ?f2)
       (:TRUE (body ?body2) :VAR ?f3)
       (:TRUE (pin-joint ?pin) :VAR ?f4)
       (:INTERN (can-move ?body1) :VAR ?f5))
  (rassert! (:IMPLIES (:AND ?f1 ?f2 ?f3 ?f4 (:NOT ?f5))
		      (:NOT (can-translate ?body2)))
	    :CANNOT-TRANSLATE-IF-JOINTED-TO-IMMOBILE-BODY))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Arrows
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; Arrow->motion
(rule ((:TRUE (arrow ?arrow) :VAR ?f1)
       (:TRUE (arrow-referent ?arrow ?body) :VAR ?f2)
       (:TRUE (can-move ?body) :VAR ?f3)
       (:TRUE (name ?name ?body))) ;; just for a nice name...
  (assert-moves! ?body ?arrow (list ?f1 ?f2 ?f3) :ARROW-IS-MOTION ?name))

;;; arrow motion causes nearby objects to move

(rule ((:INTERN (moves ?b1 ?id1) :VAR ?f1)
       (:INTERN (arrow ?a1) :VAR ?f2)
       (:INTERN (arrow-referent ?a1 ?b1) :VAR ?f3)
       (:INTERN (moves ?b2 ?id2)
		    :TEST (not (eq ?b1 ?b2)) :VAR ?f4))
  (query-java (list 'arrow-path-close-by ?a1 ?b1 ?b2)
	      `(:IMPLIES (:AND ,?f1 ,?f2 ,?f3 ,?f4)
			(arrow-path-close-by ,?a1 ,?b1 ,?b2))
	      :JAVA-QUERY-ARROW-PATH-CLOSE-BY)
  (rule ((:INTERN (arrow-path-close-by ?a1 ?b1 ?b2) :VAR ?f5))
    (rassert! (:IMPLIES (:AND ?f1 ?f2 ?f3 ?f4 ?f5)
			(can-cause ?id1 ?id2))
	      :arrow-causes-other-motions)))


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Utterances
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; Motion sentence implies motion
(rule ((:TRUE (u-moves ?move ?moves-roots ?u-id1) :VAR ?f1)
       (:TRUE (u-simple_sentence ?simple ?roots ?sent-id)
	    :TEST (member ?sent-id ?moves-roots)
	    :VAR ?f2)
       (:TRUE (u-subject ?name ?subj-roots ?u-id2)
	    :TEST (member ?sent-id ?subj-roots)
	    :VAR ?f3)
       (:TRUE (name ?name ?body) :VAR ?f4))
;; explicitly leave this out since it is a contradiction and we
;; should tell the user that he/she wants the impossible...
;;       (:TRUE (can-move ?body) :VAR ?f5))
  (assert-moves! ?body ?sent-id
		 (list ?f1 ?f2 ?f3 ?f4) :MOVES-UTTERANCE ?name))

;; Conditional sentences have two clauses which represent events which
;; are connected by a causal link
;;
;; sometimes a clause describes multiple events so we want to make
;; sure that something in the causal chain of those events is the
;; cause of something in the second clause.
(rule ((:INTERN (u-conditional_phrase ?conditional ?cond-roots ?cond-id)
	    :VAR ?f1)
       (:INTERN (u-clause1 ?clause1 ?c1-roots ?clause1-id)
	    :TEST (member ?cond-id ?c1-roots)
	    :VAR ?f2)
       (:INTERN (u-clause2 ?clause2 ?c2-roots ?clause2-id)
	    :TEST (member ?cond-id ?c2-roots)
	    :VAR ?f3))
  (rassert! (:IMPLIES (:AND ?f1 ?f2 ?f3)
		      (conditional ?clause1-id ?clause2-id))
	    :CONDITIONAL-CLAUSES-NEED-ATTENTION)
  (rule ((:INTERN (describes ?clause1-id ?event1) :VAR ?f4) 
	 (:INTERN (describes ?clause2-id ?event2) :VAR ?f5))
    (rassert! (:IMPLIES (:AND ?f1 ?f2 ?f3 ?f4 ?f5)
			(can-cause ?event1 ?event2))
	      :CONDITIONAL-SENTENCE)))

;;; spring releases utterance
(rule ((:INTERN (u-releases ?release ?release-roots ?release-id)
	      :VAR ?f1)
       (:INTERN (u-simple_sentence ?sent ?roots ?sent-id)
	      :TEST (member ?sent-id ?release-roots)
	      :VAR ?f2)
       (:INTERN (u-subject ?spring-name ?subj-roots ?subj-id)
	      :TEST (member ?sent-id ?subj-roots)
	      :VAR ?f3)
       (:INTERN (name ?spring-name ?spring) :VAR ?f4)
       (:INTERN (spring ?spring) :VAR ?spr)
       (:INTERN (attaches ?spring ?body) :VAR ?f5)
       (:INTERN (can-move ?body) :VAR ?f6)
       (:INTERN (name ?body-name ?body))) ;; to make a nice variable name...
  (assert-moves! ?body ?sent-id
		(list ?f1 ?f2 ?f3 ?f4 ?f5 ?f6 ?spr)
		:SPRING-RELEASES ?body-name))

;;; propels utterance => 2 motions and a causal link
(rule ((:INTERN (u-propels ?propel ?propel-roots ?propel-id)
	      :VAR ?f1)
       (:INTERN (u-simple_sentence ?sent ?roots ?sent-id)
	      :TEST (member ?sent-id ?propel-roots)
	      :VAR ?f2)
       (:INTERN (u-subject ?subj ?subj-roots ?subj-id)
	      :TEST (member ?sent-id ?subj-roots)
	      :VAR ?f3)
       (:INTERN (u-direct_object ?d-obj ?d-obj-roots ?d-obj-id)
	      :TEST (member ?sent-id ?d-obj-roots)
	      :VAR ?f4)
       (:INTERN (name ?subj ?b1) :VAR ?f5)
       (:INTERN (name ?d-obj ?b2) :VAR ?f6))
;; explicitly leave these out since it is a contradiction and we
;; should tell the user that they want the impossible to happen...
;       (:INTERN (can-move ?subj) :VAR ?f7)
;       (:INTERN (can-move ?d-obj) :VAR ?f8)
  (rlet ((?pre (?f1 ?f2 ?f3 ?f4 ?f5 ?f6)))
    (assert-moves! ?b1 ?sent-id ?pre :PROPELS-UTTERANCE ?subj)
    (assert-moves! ?b2 ?sent-id ?pre :PROPELS-UTTERANCE ?d-obj)

    (rule ((:INTERN (moves ?b1 ?event1) :VAR ?move-1)
	   (:INTERN (moves ?b2 ?event2) :VAR ?move-2))
      (assert! `(:IMPLIES
		 (:AND ,@?pre ,?move-1 ,?move-2)
		 (composite-event ,?sent-id (,?move-1 ,?move-2)))
	       :ONE-ANNOTATION-2-EVENTS)
      
      (assert! `(:IMPLIES (:AND ,@?pre ,?move-1 ,?move-2)
			  (causes ,?event1 ,?event2))
	       :PROPELS-EVENTS-CAUSE-ON-ANOTHER))))


;;; ropes through pulleys move on both ends
(rule ((:TRUE (pulley ?pulley) :VAR ?f1)
       (:TRUE (attaches ?pulley ?body1) :VAR ?f2)
       (:TRUE (attaches ?pulley ?body2)
	      :TEST (not (eq ?body1 ?body2))
	      :VAR ?f3)
       (:INTERN (moves ?body1 ?id1) :VAR ?f4)
       (:INTERN (moves ?body2 ?id2) :VAR ?f5))
  (rassert! (:IMPLIES (:AND ?f1 ?f2 ?f3)
		      (can-cause ?id1 ?id2))
	    :ROPES-CAN-MOVE-BOTH-ENDS))

;;; rods move on both ends
(rule ((:TRUE (rod ?rod) :VAR ?f1)
       (:TRUE (attaches ?rod ?body1) :VAR ?f2)
       (:TRUE (attaches ?rod ?body2)
	      :TEST (not (eq ?body1 ?body2))
	      :VAR ?f3)
       (:INTERN (moves ?body1 ?id1) :VAR ?f4)
       (:INTERN (moves ?body2 ?id2) :VAR ?f5))
  (rassert! (:IMPLIES (:AND ?f1 ?f2 ?f3)
		      (can-cause ?id1 ?id2))
	    :RODS-MOVE-BOTH-ENDS))



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Dealing with equivalent event representations
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; Provide abstraction to support multiple event types.
(rule ((:INTERN (moves ?body ?id) :VAR ?moves))
  (rassert! (:IFF ?moves (event ?moves))
	    :MOVES-IS-AN-EVNET))

;; merge equivalent motion events
(rule ((:INTERN (moves ?b1 ?id1) :VAR ?f1)
       (:INTERN (moves ?b1 ?id2) :TEST (not (eq ?id1 ?id2)) :VAR ?f2))
  (rassert! (:IMPLIES (:AND ?f1 ?f2)
		      (same-event ?id1 ?id2))
	    :MERGE-MOTIONS))

;; if one event is in a set and another event is equivalent to it they
;; should be in the same set
(rule ((:TRUE (set (event ?id)) :VAR ?set)
       (:TRUE ((event ?id) has-member ?event1) :VAR ?member)
       (:TRUE (same-event ?event1 ?event2) :VAR ?same))
  (rassert! (:IMPLIES (:AND ?set ?member ?same)
		      ((event ?id) has-member ?event2))
	    :SAME-EVENT-SAME-SET))

;; can only be in one event equivalence set
(rule ((:TRUE (set (event ?id1)))
       (:TRUE (set (event ?id2)) :TEST (not (eq ?id1 ?id2)))
       (:TRUE ((event ?id1) has-member ?event) :VAR ?f1)
       (:TRUE ((event ?id2) has-member ?event) :VAR ?f2))
  (rassert! (:NOT (:AND ?f1 ?f2)) :CANNOT-BE-IN-TWO-SETS))

;; if an event causes another event then the same is true of the
;; equivalence classes that contain those events
(rule ((:TRUE (can-cause ?id1 ?id2) :VAR ?causes)
       (:TRUE ((event ?sid1) has-member ?id1) :VAR ?evt1)
       (:TRUE ((event ?sid2) has-member ?id2) :VAR ?evt2))
  (rassert! (:IMPLIES (:AND ?causes ?evt1 ?evt2)
		      (can-cause (event ?sid1) (event ?sid2)))
	    :MULTIPLE-REP-PROPAGATES-CAUSES-TO-PARENTS))

;; if an event causes another event then the same is true of the
;; equivalence classes that contain those events
(rule ((:TRUE (causes ?id1 ?id2) :VAR ?cs)
       (:TRUE ((event ?sid1) has-member ?id1) :VAR ?evt1)
       (:TRUE ((event ?sid2) has-member ?id2) :VAR ?evt2))
  (rassert! (:IMPLIES (:AND ?cs ?evt1 ?evt2)
		      (causes (event ?sid1) (event ?sid2)))
	    :MULTIPLE-REP-PROPAGATES-CAUSES-TO-PARENTS))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Propagating time stamps
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; propagate the times from the annotation to the event
(rule ((:INTERN (describes ?annotation ?event) :VAR ?f1)
       (:INTERN (time ?annotation ?time) :VAR ?f2))
  (rassert! (:IMPLIES (:AND ?f1 ?f2)
		      (time ?event ?time))
	    :EVENT-GETS-ANNOTATIONS-TIME))

;;; times get asserted for root annotations but utterances are broken
;;; up.  If part of an utterance describes an event that part should
;;; get the same time stamp as the parent utterance.
(rule ((:INTERN (describes ?annotation ?event) :VAR ?f1)
       (:INTERN (sentence ?id ?tags)
		:TEST (member ?annotation ?tags)
		:VAR ?f2)
       (:INTERN (time ?id ?time) :VAR ?f3))
  (rassert! (:IMPLIES (:AND ?f1 ?f2 ?f3)
		      (time ?annotation ?time))
	    :TIME-TRANFERS-TO-ALL-PARTS-OF-A-SENTENCE))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Explanation order implies causal order
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;; This rule was nixed because it should really be a
;;; defualt/heuristic that is only applied if there are multiple
;;; exogenous events.

;;;consequtive annotations can indicate causality implicitly
; (rule ((:INTERN (event ?event1) :VAR ?e1)
;        (:INTERN (event ?event2)
; 		:TEST (not (eq ?event1 ?event2))
; 		:VAR ?e2)
;        (:INTERN (time ?event1 ?time1) :VAR ?t1)
;        (:INTERN (time ?event2 ?time2)
; 		:TEST (= (1+ ?time1) ?time2)
; 		:VAR ?t2))
;        (rassert! (:IMPLIES (:AND ?t1 ?t2 ?e1 ?e2)
; 		      (can-cause ?event1 ?event2))
; 	    :EXP-ORDER-SUGGESTS-CAUSALITY))


;;; different representations of the same event cannot cause one another
(rule ((:TRUE (causes ?evt1 ?evt2) :VAR ?f1)
       (:TRUE (same-event ?evt1 ?evt2) :VAR ?f2))
  (rassert! (:NOT (:AND ?f1 ?f2))
	    :CANNOT-CAUSE-SELF))
		      
; (rule ((:TRUE (time (event ?event1) ?time1) :VAR ?t1)
;        (:TRUE (time (event ?event2) ?time2)
; 	      :TEST (< ?time1 ?time2)
; 	      :VAR ?t2))
;   (rassert! (:IMPLIES (:AND ?t1 ?t2)
; 		      (before (event ?event1) (event ?event2)))
; 	    :CANT-VIOLATE-EXPLANATION-ORDER))

;; causal order must indicate temporal order
(rule ((:INTERN (causes (event ?cause) (event ?effect)) :VAR ?f1))
  (rassert! (:IMPLIES ?f1 (before (event ?cause) (event ?effect)))
	    :CAUSAL-ORDER-IMPLIES-TIME))

;; events cannot precede each other
(rule ((:INTERN (before ?evt1 ?evt2) :VAR ?f1)
       (:INTERN (before ?evt2 ?evt1) :VAR ?f2))
  (rassert! (:NOT (:AND ?f1 ?f2))
	    :EVENTS-CANNOT-PRECEDE-EACH-OTHER))

;;; to make the choice sets work out correctly make sure that if
;;; something definately causes something then it can-cause it
(rule ((:TRUE (causes ?evt1 ?evt2) :VAR ?f1))
  (rassert! (:IMPLIES ?f1 (can-cause ?evt1 ?evt2))
	    :IF-IT-CAUSES-IT-CERTAINLY-CAN-CAUSE))

;;; for now events can only have one cause
(rule ((:INTERN (causes ?evt1 (event ?effect)) :VAR ?f1)
       (:INTERN (causes ?evt2 (event ?effect))
	      :TEST (not (equal ?evt1 ?evt2))
	      :VAR ?f2))
  (rassert! (:NOT (:AND ?f1 ?f2)) :ONLY-ONE-EFFECT-PER-CAUSE))


;;; for now do the expensive transitivity thing for time...
(rule ((:TRUE (before ?evt1 ?evt2) :VAR ?f1)
       (:TRUE (before ?evt2 ?evt3) :VAR ?f2))
  (rassert! (:IMPLIES (:AND ?f1 ?f2) (before ?evt1 ?evt3))
	    :BEFORE-IS-TRANSITIVE))

(rule ((:TRUE (set (event ?id)) :VAR ?event))
  (rassert! (:IMPLIES ?event
		      (can-cause (exogenous-cause ?id) (event ?id)))
	    :EXTERNAL-FORCES-HAVE-EFFECTS-TOO))


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Composite events: some descriptions describe several events.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; (rule ((:TRUE (describes ?note ?event1) :VAR ?desc1)
;        (:TRUE (describes ?note ?event2)
; 	      :TEST (not (eq ?event1 ?event2))
; 	      :VAR ?desc2))
;   (rassert! (:IMPLIES (:AND ?desc1 ?desc2)
; 		      (:AND (set (describes ?note))
; 			    ((describes ?note) has-member ?event1)
; 			    ((describes ?note) has-member ?event2)))
; 	    :SAME-DESCRIPTION-SEVERAL-EVENTS))

;;; use the two describes version since we only need a set if there
;;; are two events described by the same annotation.  Otherwise we
;;; don't need them.
;;;
;;; This is not true we always want a set or else we have lots of
;;; special cases...  use this version.
(rule ((:INTERN (describes ?note ?event) :VAR ?desc)
       (:INTERN ((event ?id) has-member ?event) :VAR ?f))
  (rassert! (:IMPLIES
	     ?desc
	     (:AND (set (describes ?note))
		   ((describes ?note) has-member (event ?id))))
	    :DESCRIPTIONS-HAVE-SETS))
	       
;; if a conditional phrase has composite events then make sure that
;; one of them must cause one of the results.
(rule ((:INTERN (conditional ?clause1 ?clause2) :VAR ?cond)
       (:INTERN ((describes ?clause1) members ?causes) :VAR ?f1)
       (:INTERN ((describes ?clause2) members ?effects) :VAR ?f2))
  (assert-causal-taxonomy ?causes ?effects (list ?cond ?f1 ?f2)))


;; replace a "this" with the name of a body
;; for now you must point and then say "this"
;; only bodies can be referred to by "this"
;; only one body per utterance can be refered to by "this"
; (rule ((:TRUE (point ?point) :VAR ?f1)
;        (:TRUE (point-referent ?point ?body) :VAR ?f2)
;        (:TRUE (u-subject "this" ?subj-roots ?subj-id) :VAR ?f3)
;        (:TRUE (sentence ?sent-id ?tags)
; 	      :TEST (member ?sent-id ?subj-roots)
; 	      :VAR ?f4)
;        (:TRUE (u-simple_sentence ?simple ?roots ?simple-id)
; 	    :TEST (member ?simple-id ?subj-roots)
; 	    :VAR ?f5)
;        (:TRUE (time ?point ?tp) :VAR ?f6)
;        (:TRUE (time ?sent-id ?tu) :TEST (= (+ ?tp 1) ?tu) :VAR ?f7)
;        (:TRUE (name ?name ?body) :VAR ?f8))
;   (rassert! (:IMPLIES (:AND ?f1 ?f2 ?f3 ?f4 ?f5 ?f6 ?f7 ?f8)
; 		      (u-subject ?name ?subj-roots ?subj-id))
; 	    :NEARBY-ANNOTATIONS-DEREFERENCE-POINTS))

(rule ((:TRUE (point ?point) :VAR ?f1)
       (:TRUE (point-referent ?point ?body) :VAR ?f2)
       (:TRUE (u-subject ?subj-text ?subj-roots ?subj-id) :VAR ?f3)
       (:TRUE (u-reference ?subj-text ?subj-roots ?subj-id) :VAR ?ref)
       (:TRUE (sentence ?sent-id ?tags)
	      :TEST (member ?sent-id ?subj-roots)
	      :VAR ?f4)
       (:TRUE (u-simple_sentence ?simple ?roots ?simple-id)
	    :TEST (member ?simple-id ?subj-roots)
	    :VAR ?f5)
       (:TRUE (time ?point ?tp) :VAR ?f6)
       (:TRUE (time ?sent-id ?tu) :TEST (= (+ ?tp 1) ?tu) :VAR ?f7)
       (:TRUE (name ?name ?body) :VAR ?f8))
  (rassert! (:IMPLIES (:AND ?f1 ?f2 ?f3 ?f4 ?f5 ?f6 ?f7 ?f8)
		      (u-subject ?name ?subj-roots ?subj-id))
	    :NEARBY-ANNOTATIONS-DEREFERENCE-POINTS))


; ;; if an event causes another event then the same is true of the
; ;; equivalence classes that contain those events
; (rule ((:TRUE (causes ?id1 ?id2) :VAR ?cs)
;        (:TRUE ((event ?sid1) has-member ?id1) :VAR ?evt1)
;        (:TRUE ((event ?sid2) has-member ?id2) :VAR ?evt2))
;   (rassert! (:IMPLIES (:AND ?cs ?evt1 ?evt2)
; 		      (causes (event ?sid1) (event ?sid2)))
; 	    :MULTIPLE-REP-PROPAGATES-CAUSES-TO-PARENTS))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Parameter adjustment
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(rule ((:TRUE (attaches ?spring ?body) :VAR ?attach)
       (:TRUE (moves ?body ?id) :VAR ?move)       
       (:TRUE (spring ?spring) :VAR ?spr)
       (:TRUE (arrow ?arrow) :VAR ?arw)
       (:TRUE (arrow-referent ?arrow ?body) :VAR ?ref)
       (:TRUE ((event ?big-id) has-member ?id) :VAR ?event)
       (:TRUE ((describes ?arrow) has-member (event ?big-id)) :VAR ?desc))
  (rlet ((?constraint (:EVAL (get-spring-constraint ?spring ?body ?arrow))))
    (when ?constraint
      (rassert! (:IMPLIES (:AND ?attach ?move ?spr ?arw	?ref ?event ?desc)
			  ?constraint)
		:JAVA-FINDS-SPRING-STATE))))

;;; springs have three possible states
(rule ((:TRUE (spring ?spring) :VAR ?f1))
  (rassert! (:IMPLIES ?f1 (:TAXONOMY (spring-state ?spring in-compression)
				     (spring-state ?spring at-rest)
				     (spring-state ?spring in-tension)))
	    :SPRINGS-HAVE-THREE-STATES))
				     
       


