;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; ACT-R model of the Differential Fan Effects
;;; from the Radvansky, Spieler, and Zacks experiments
;;; 
;;; Radvansky, G. A., Spieler, D. H., & Zacks, R. T. (1993).  Mental model
;;; organization. Journal of Experimental Psychology: Learning, Memory, 
;;; and Cognition, 19, 95-114.
;;;
;;; Works with ACT-R  4.0 (2/6/97 or newer)
;;;
;;; interface coded by: Dan Bothell
;;;
;;; This file contains an ACT-R model that
;;; models the fan effect present in the recognition 
;;; during experiments 5 and 6 of Radvansky et al.
;;; In the task the subject first learns several 
;;; person-small location pairs.  The fan of 
;;; either the person or location is held at 1, and
;;; the fan of the other is varied, such that
;;; there are 1, 2, or 3 pairs containing a
;;; given item.  Then, there is a recognition task.
;;; The subject is presented with a 
;;; person-small location pair, and must respond yes
;;; or no as to whether or not it was one of the
;;; pairs learned.  The foils are constructed from
;;; the same people and locations as the targets.
;;;
;;; The memory of a set of pairs is encoded into
;;; the model.  The model simulates one recognition step, and
;;; there is a fuction which will present the model
;;; with 12 pairs to be judged.  Half of the pairs are
;;; targets, and half foils, with all possible 
;;; fan combinations represented.
;;; 
;;; A simple function call, and a WWW interface
;;; are included.
;;;
;;; To run the model through the recognition, call
;;; (do-radvansky-5-6 n).  That will print
;;; out a chart of the average time to classify
;;; the pairs over n runs of the model.
;;;
;;; To use the WWW interface, you need to run
;;; the ACT-R on the Web application (follow the
;;; instructions provided with it), or use a
;;; web browser to connect to a site that has
;;; the model installed.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; This section contains the code to simulate 
;;; the experiment, present the interface,
;;; and display the results.  The ACT-R
;;; model is located farther down.


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; Global Variables

;; these are set by the interface to control the model

(defvar *lf* 1.143)
(defvar *v* nil)
(defvar *s* 1.28)
(defvar *i* .918)
(defvar *runs* 1)
(defvar *wp* .12)
(defvar *wl* .55)

(setf *lf* 1.143)
(setf *v* nil)
(setf *s* 1.28)
(setf *i* .918)
(setf *runs* 1)
(setf *wp* .12)
(setf *wl* .55)

;;; description of the model

(defparameter *about-radvansky-5-6*
"
   This ACT-R model simulation models the fan 
effect present in recognition during experiments 5
and 6 of Radvansky et al.  In the task the 
subject first learns several person-
small location pairs.  The fan of either the 
person or location is held at 1, and the fan 
of the other is varied, such that there are 
1, 2, or 3 pairs containing a given item.  
Then, there is a recognition task.  The subject is
presented with a person-location pair, and 
must respond yes or no as to whether or not
it was one of the pairs learned.  The foils 
are constructed from the same people and 
locations as the targets.

   The memory of a set of pairs is encoded 
into the model.  The model simulates one 
recognition step, and running the simulation will 
present the model with 12 pairs to be judged.
Half of the pairs are targets, and half 
foils, with all possible fan combinations 
represented.
")

(defparameter *radvansky-5-6-data* '(1.488 1.500 1.447
                                    1.537 1.638 1.619
                                    1.449 1.526 1.662
                                    1.548 1.814 2.014))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; This section contains the interface for the WWW using the
;;; ACT-R on the Web application by Elmar Schwarz

(defvar *WWW-interface*)

(setf  *WWW-interface* 
      '((:heading "Simulation of Radvansky, Spieler, & Zacks (1993) Experiments 5 & 6" 2)
        (:table)
        
        (:table)
        "F (latency scale) (s): "       (:string :sy *lf*  1.143)  (:new-row)
        "I (intercept, min .6) (s): "   (:string :sy *i*   0.918)  (:new-row)
        "S (base log probability): "    (:string :sy *s*   1.28) (:new-row) 
        "W of object:"                  (:string :sy *wp*   .12) (:new-row)
        "W of location:"                (:string :sy *wl*   .55) (:new-row)
        "number of runs (1 - 20): "     (:string :sy *runs* 1) 
        (:table-end)
        
        (:table)
        (:checkbox "Trace" :sy *v*  nil)
        (:table-end)
        (:table-end)
        
        (:new-para)
        (:button "Show Experiment Results" "(progn
                                            (format *standard-output* \"~%~%Experimental Data:~%~%\")
                                            (output-radvansky-5-6 *radvansky-5-6-data* 1))")
        (:new-para)
        (:button "Run model" "(if (and (numberp *i*) (numberp *s*) (numberp *lf*) (numberp *runs*)
                                       (numberp *wp*) (numberp *wl*))
                                  (do-radvansky-5-6 (min 20 (max 1 *runs*)))
                                  (format *standard-output* \"~%All parameters must be numbers.~%\"))")
        (:reset "Default values")
        (:button "Production Rules" "(let ((prods (no-output (pp))))
                                       (dolist (x prods)
                                         (pp-fct (list x))
                                         (spp-fct (list x))
                                         (format *standard-output* \"~%\")))")
        (:button "Chunk types" "(chunk-type)")
        (:button "Chunks" "(dm)")
        (:button "About Model" "(format *standard-output* \"~%~A~%\" *about-radvansky-5-6*)")
        (:new-para)
        "NOTE:"
        (:new-para)
        "- the choice between retrieving by person and retrieving by location is 
         random, so the system matches the foil times only on average over multiple
         runs."
        (:new-para)
         "TIME and SIZE:"
        (:new-para)
        "- It usually takes less than 1 minute for 1 run of the model"
        (:new-line)
        "- The trace of 1 run is approximatly 60k (40 pages) in size"
        (:new-para)))




;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; do-radvansky-5-6 takes one parameter, times, and prints out the average of 
;;; times runs over the 12 probe types.  
;;; Note: the choice between retrieving by person and retrieving
;;; by location is random and so the system matches the foil times 
;;; only on average over many runs

(defun do-radvansky-5-6 (times) 
  
  (let ((rts '(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)))
    (do ((result (list (test-radvansky-5-6 'captain   'house) 
                       (test-radvansky-5-6 'lawyer    'store)
                       (test-radvansky-5-6 'hippie    'park)
                       (test-radvansky-5-6 'captain   'bank)
                       (test-radvansky-5-6 'lawyer    'park)
                       (test-radvansky-5-6 'hippie    'cave)
                       (test-radvansky-5-6 'fireman   'theatre)
                       (test-radvansky-5-6 'teacher   'jail)
                       (test-radvansky-5-6 'artist    'office)
                       (test-radvansky-5-6 'debutante 'theatre)
                       (test-radvansky-5-6 'farmer    'jail)
                       (test-radvansky-5-6 'fireman   'office)) 
                 (list (test-radvansky-5-6 'captain   'house) 
                       (test-radvansky-5-6 'lawyer    'store)
                       (test-radvansky-5-6 'hippie    'park)
                       (test-radvansky-5-6 'captain   'bank)
                       (test-radvansky-5-6 'lawyer    'park)
                       (test-radvansky-5-6 'hippie    'cave)
                       (test-radvansky-5-6 'fireman   'theatre)
                       (test-radvansky-5-6 'teacher   'jail)
                       (test-radvansky-5-6 'artist    'office)
                       (test-radvansky-5-6 'debutante 'theatre)
                       (test-radvansky-5-6 'farmer    'jail)
                       (test-radvansky-5-6 'fireman   'office)))
         (count 0 (1+ count)))
      ((= count times) nil)
      (setf rts (mapcar '+ rts result)))
    (format *standard-output* "~%~%Simulation parameters: (~S ~S ~S ~S ~S ~S)~%" *lf* *i* *s* *wp* *wl* times)
    (format *standard-output* "~%Simulation Data:~%~%")
    (output-radvansky-5-6 rts times)))


;;;;;;;;;;;;;;;;;;;
;;;
;;; output-radvansky-5-6 takes two parameters,
;;; a list of response times, and the number of runs
;;; that generated those times, and prints out the tables
;;; of the results

(defun output-radvansky-5-6 (rts times)

    (format *standard-output* "~%Location fan 1:~%")
    (format *standard-output* "                    Person fan~%")
    (format *standard-output* "                1       2       3~%")
    (format *standard-output* "Targets    ~8,3F~8,3F~8,3F~%" (/ (nth 0 rts) times) (/ (nth 1 rts) times) (/ (nth 2 rts) times))
    (format *standard-output* "Foils      ~8,3F~8,3F~8,3F~%" (/ (nth 3 rts) times) (/ (nth 4 rts) times) (/ (nth 5 rts) times))
    (format *standard-output* "Aggregated ~8,3F~8,3F~8,3F~%" (/ (+ (nth 0 rts) (nth 3 rts)) (* 2 times)) 
            (/ (+ (nth 1 rts) (nth 4 rts)) (* 2 times)) (/ (+ (nth 2 rts) (nth 5 rts)) (* 2 times)))
    (format *standard-output* "~%Person fan 1:~%")
    (format *standard-output* "                  Location fan~%")
    (format *standard-output* "                1       2       3~%")
    (format *standard-output* "Targets    ~8,3F~8,3F~8,3F~%" (/ (nth 6 rts) times) (/ (nth 7 rts) times) (/ (nth 8 rts) times))
    (format *standard-output* "Foils      ~8,3F~8,3F~8,3F~%" (/ (nth 9 rts) times) (/ (nth 10 rts) times) (/ (nth 11 rts) times))
    (format *standard-output* "Aggregated ~8,3F~8,3F~8,3F~%" (/ (+ (nth 9 rts) (nth 6 rts)) (* 2 times)) 
            (/ (+ (nth 7 rts) (nth 10 rts)) (* 2 times)) (/ (+ (nth 8 rts) (nth 11 rts)) (* 2 times))))

    

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;       
;;; test-radvansky-5-6 runs 1 trial, with the stimuli given in p and l
;;; and the time of the run is returned

(defun test-radvansky-5-6 (p l)
  (reset)
  (set-radvansky-5-6-params)
  (mod-chunk-fct 's1 (list 'second p 'sixth l))
  (mod-chunk goal person nil location nil)
  (goal-focus goal) 
  (run 5)
  
  ;; set the strengths

  (sdp-fct (list (list (car (no-output (swm-fct (list 'word p)))) :source *wp*) 
                 (list (car (no-output (swm-fct (list 'word l)))) :source *wl*) 
                 (list 'in* :source .33)))

  (run)
  (actr-time))

;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; set-radvansky-5-6-params sets the parameters for a run based
;;; on the global variables set by one of the interfaces

(defun set-radvansky-5-6-params ()
  (sgp-fct (list 
            :era t
            :er t
            :LF *lf* 
            :act t
            :le 1 
            :v *v*))
   
  (parameters-fct 'match (list :effort (- (max .6 *i*) .6)))
  (parameters-fct 'not-location (list :effort (- (max .6 *i*) .6)))
  (parameters-fct 'not-person (list :effort (- (max .6 *i*) .6))))



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; The ACT-R model of the recognition phase of 
;;; Radvansky et al. differential fan experiments 1 & 2.


(clearall)


(sgp-fct (list  :era t :LF *lf* :act t :v nil :er t :le 1))

;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; CHUNK TYPES
;;;

(chunk-type proposition 
"
 a chunk type to represent the statement:
   arg1 relation arg2 (example captain in park)
"
 relation arg1 arg2)

(chunk-type sentence 
"
 a chunk type to hold a 6 word sentence
 of the form:
     A subject IS preposition THE place
"
 first second third fourth fifth sixth)

(chunk-type process-sentence 
"
 a chunk type to hold a goal to 
 process a sentence
  slots:
     person - holds the word for the person
              from the sentence (or nil if not yet read)
     location - holds the word for the location
              from the sentence (or nil if not yet read)
     sentence - the sentence to process
     pm - the meaning of the word in the person slot
     lm - the meaning of the word in the location slot
"
person location sentence pm lm)

(chunk-type recognize-goal
"
 a chunk type for a goal to try to recognize
 the association person relation location
  slots:
     person - holds the meaning chunk of a person
     location - holds the meaning chunk of a location
     relation - holds the meaning chunk of a relation
                between person and location
     pp - holds the meaning chunk of a person for
          a retrieved assiciation pp relation pl
     pl - holds the meaning chunk of a location 
          for a retrieved association pp relation pl
"
 person location relation pl pp)

(chunk-type word 
"
 a chunk type to hold words (used for display)
 with a slot containing the meaning chunk
"
 meaning)

(chunk-type meaning 
"
 a chunk type used to represent the meaning
 for a word, the word is in the word slot
"
 word)

;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; CHUNKS
;;;

(set-dm (p1 isa proposition relation in* arg1 hippie* arg2 park*)
        (p2 isa proposition relation in* arg1 hippie* arg2 church*)
        (p3 isa proposition relation in* arg1 hippie* arg2 bank*)
        (p4 isa proposition relation in* arg1 lawyer* arg2 store*)
        (p5 isa proposition relation in* arg1 lawyer* arg2 cave*)
        (p6 isa proposition relation in* arg1 captain* arg2 house*)
        (p7 isa proposition relation in* arg1 fireman* arg2 theatre*)
        (p8 isa proposition relation in* arg1 debutante* arg2 jail*)
        (p9 isa proposition relation in* arg1 teacher* arg2 jail*)
        (p10 isa proposition relation in* arg1 cowboy* arg2 office*)
        (p11 isa proposition relation in* arg1 artist* arg2 office*)
        (p12 isa proposition relation in* arg1 farmer* arg2 office*)
        (hippie isa word meaning hippie*)       (hippie* isa meaning word hippie)
        (park isa word meaning park*)           (park* isa meaning word park)
        (church isa word meaning church*)       (church* isa meaning word church)
        (bank isa word meaning bank*)           (bank* isa meaning word bank)
        (lawyer isa word meaning lawyer*)       (lawyer* isa meaning word lawyer)
        (store isa word meaning store*)         (store* isa meaning word store)
        (cave isa word meaning cave*)           (cave* isa meaning word cave)
        (captain isa word meaning captain*)     (captain* isa meaning word captain)
        (house isa word meaning house*)         (house* isa meaning word house)
        (fireman isa word meaning fireman*)     (fireman* isa meaning word fireman)
        (theatre isa word meaning theatre*)     (theatre* isa meaning word theatre)
        (debutante isa word meaning debutante*) (debutante* isa meaning word debutante)
        (teacher isa word meaning teacher*)     (teacher* isa meaning word teacher)
        (jail isa word meaning jail*)           (jail* isa meaning word jail)
        (cowboy isa word meaning cowboy*)       (cowboy* isa meaning word cowboy)
        (artist isa word meaning artist*)       (artist* isa meaning word artist)
        (farmer isa word meaning farmer*)       (farmer* isa meaning word farmer)
        (office isa word meaning office*)       (office* isa meaning word office)
        (in isa word meaning in*)               (in* isa meaning word in)
        (is isa word meaning is*)               (is* isa meaning word is)
        (the isa word)
        (a isa word)
        (goal isa process-sentence sentence s1)
        (s1 isa sentence first a second hippie third is fourth in fifth the 
            sixth bank))

;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;
;;;
;;; Set the association strengths directly to S - ln(fan)
;;;

(let ((meanings (no-output (swm isa meaning))))
  (dolist (x meanings)
    (let* ((props (append (no-output (sdm-fct (list 'isa 'proposition 'arg1 x)))
                          (no-output (sdm-fct (list 'isa 'proposition 'arg2 x)))))
           (count (length props)))
      (dolist (y props)
        (set-ia-fct (list (list x y (- *s* (log  count)))))))))

;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; eliminate any associative activation
;;; resulting from in* since it will be constant
;;; across all propositions, it is eliminated for 
;;; simplicity in fitting the other parameters

(let ((statements (no-output (swm isa proposition))))
  (dolist (x statements)
    (set-ia-fct (list (list 'in* x 0)))))

;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; set the base level activations to 0 (B = 0)
;;; for the words - people, places, and prepositions
 
(setgeneralbaselevels 
 (hippie 0)(hippie* 0)
 (park 0)(park* 0)
 (church 0)(church* 0)
 (bank 0)(bank* 0)
 (lawyer 0)(lawyer* 0)
 (store 0)(store* 0)
 (cave 0)(cave* 0)
 (captain 0)(captain* 0)
 (house 0)(house* 0)
 (fireman 0)(fireman* 0)
 (theatre 0)(theatre* 0)
 (debutante 0)(debutante* 0)
 (teacher 0)(teacher* 0)
 (jail 0)(jail* 0)
 (cowboy 0)(cowboy* 0)
 (artist 0)(artist* 0)
 (farmer 0)(farmer* 0)
 (office 0)(office* 0)
 (in 0)(in* 0)
 (the 0)
 (a 0)
 (s1 10)
 (goal 2))


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; PRODUCTIONS
;;;

(p read-person
"
   IF the goal is to process a sentence and the person has 
      not been read yet
   THEN note the second word of the sentence in the goal as the person
"
   =goal>
      isa process-sentence
      person nil
      sentence =sentence

   =sentence>
      isa sentence
      second =word
==>
  =goal>
     person =word
)

(parameters read-person :effort .15)


(p read-location
"
   IF the goal is to process a sentence and the location has 
      not been read yet
   THEN note the sixth word of the sentence in the goal as the location
"
   =goal>
      isa process-sentence
      location nil
      sentence =sentence

   =sentence>
      isa sentence
      sixth =word
==>
   =goal>
      location =word
)

(parameters read-location :effort .15)


(p understand-person
"
   IF the goal is to process a sentence, and the person has been
       read, but its meaning not found
   THEN store the meaning of the word in the goal
"
   =goal>
      isa process-sentence
      person =word
      pm nil

   =word>
      isa word
      meaning =m
==>
   =goal>
      pm =m
)

(parameters understand-person :effort .1 :strength 10)


(p understand-location
"
   IF the goal is to process a sentence, and the location has been
       read, but its meaning not found
   THEN store the meaning of the word in the goal
"
   =goal>
      isa process-sentence
      location =word
      lm nil

   =word>
      isa word
      meaning =m
==>
  =goal>
     lm =m
)

(parameters understand-location :effort .1 :strength 10)


(p recognize
"
   IF the goal is to process a sentence, and both the person and
      location meanings have been determined
   THEN set a new goal to attempt to remember the association
       the 'person' in the 'location'
"
   =goal>
      isa process-sentence
      pm =p
      lm =l
==>
   =newgoal>
      isa recognize-goal
      person =p
      relation in*
      location =l
    
    !focus-on! =newgoal
)


(p retrieve-sentence-p
"
   IF the goal is to recognize the association 'person' in 'location'
      and no location memory has yet been found
      and there is a memory with 'person' in somewhere
   THEN set the retrieved person and location in the goal to
      'person' and somewhere
"
   =goal>
      isa recognize-goal
      person =p
      location =l
      pl nil

   =prop>
      isa proposition
      relation in*
      arg1 =p
      arg2 =newl
==>
   =goal>
      pp =p
      pl =newl
)


(p retrieve-sentence-l
"
   IF the goal is to recognize the association 'person' in 'location'
      and no person memory has yet been found
      and there is a memory with someone in 'location'
   THEN set the retrieved person and location in the goal to
      someone and 'location'
"
   =goal>
      isa recognize-goal
      person =p
      location =l
      pp nil

   =prop>
      isa proposition
      relation in*
      arg1 =newp
      arg2 =l
==>
   =goal>
      pp =newp
      pl =l
)


(p not-person
"
   IF the goal is to recognize the association 'person' in 'location'
      and a memory has been recalled
      and the person is not correct
   THEN respond no
      and pop the goal, finishing the trial
"
   =goal>
      isa recognize-goal
      person =p
      location =l
    - pp =p
      pl =l
==>
   !output! ("no")

   !pop!
)

(parameters-fct 'not-person (list :effort (- (max .6 *i*) .6)))


(p not-location
"
   IF the goal is to recognize the association 'person' in 'location'
      and a memory has been recalled
      and the location is not correct
   THEN respond no
      and pop the goal, finishing the trial
"
   =goal>
      isa recognize-goal
      person =p
      location =l
      pp =p
    - pl =l
==>
   !output! ("no")

   !pop!
)

(parameters-fct 'not-location (list :effort (- (max .6 *i*) .6)))


(p match
"
   IF the goal is to recognize the association 'person' in 'location'
      and a memory has been recalled
      and the memory has both 'person' and 'location'
   THEN respond yes
      and pop the goal, finishing the trial
"
   =goal>
      isa recognize-goal
      location =l
      pl =l
      person =p
      pp =p
==>
   !output! ("yes")

   !pop!
)

(parameters-fct 'match (list :effort (- (max .6 *i*) .6)))