Unit 7: Production Rule Learning

 

In this unit we will discuss how new production rules are learned.  As we will see, new production rules can be acquired by collapsing two production rules that apply in succession into a single rule.  In the process one can move knowledge that is stored declaratively into a procedural form.   We call this process of forming new production rules production compilation.

 

7.1 The Basic Idea

 

A good pair of productions for illustrating production compilation is the two that fire in succession to retrieve a paired associate in the paired model from Unit 4:

 

(p read-probe

    =goal>

      isa      goal

      state    attending

      arg1     nil

    =visual>

      isa      text

      value    =val

    =visual-state>

      isa      module-state

      modality free

==>

    +retrieval>

      isa      goal

      state    associated

      arg1     =val

    =goal>

      arg1     =val

      state    testing

    -visual>

)

 

(p recall

    =goal>

      isa      goal

      arg1     =val

      state    testing

    =retrieval>

      isa      goal

      arg1     =val

      arg2     =ans

    =manual-state>

      ISA      module-state

      modality free

==>

    +manual>             

      isa      press-key    

      key      =ans

    =goal>

      state    read-study-item

)

 

 

If these two productions fired and retrieved the paired-associate zinc-9, production compilation would combine these two rules into the following single production:

 

(p recall-zinc

    =goal>

       isa GOAL

       state Attending

       arg1 nil

    =visual-state>

       isa MODULE-STATE

       modality Free

    =visual>

       isa TEXT

       value "zinc"

    =manual-state>

       isa MODULE-STATE

       modality Free

 ==>

    =goal>

       state Read-Study-Item

       arg1 "zinc"

    -visual>

    +manual>

       isa PRESS-KEY

       key "9"

 )

 

Essentially, this production combines the work of the two and has built into it the paired associate.  In the next two subsections we will describe generally the principles for combining two production rules together and the factors that control how these productions compete in the conflict resolution process.

 

7.2 Forming a New Production

 

The basic idea behind forming a new production is to combine the tests in the two conditions into a single set of tests that will recognize when the pair of productions will apply and combine the two actions into a single action that has the effect of both.  Since the conditions consist of a set of buffer tests and the actions consist of a set of buffer transformations (either direct changes or new requests) this can be done largely on a buffer-by-buffer basis.  The complications occur when there is a buffer transformation in the action of the first production and either a test of that buffer in the condition of the second production or another transformation of the same buffer in the action of the second productions.  The productions above illustrate both complications with respect to the goal buffer.  First, read-probe sets the state slot of the goal to testing.  Then recall tests for that value in the slot.  In this case, one can simply omit the setting of state to testing in the composed production. Also, the goal is changed in both productions but the resulting production can just produce the final changes.  The result of the overlap in the goal buffer is just a simplification of the production rule but in other cases other responses are necessary.

 

7.2.1 Perceptual-Motor Buffers

 

Let us first consider the compilation policy for the perceptual-motor buffers.  The buffers in question are visual-location, visual, manual, aural, and vocal.  There are two things that one can do with each of these buffers.  One is to test their contents on the left hand side and the other is to request an action on the right hand side. If the first production makes a request of one of these buffers then it is not possible to compose it with the second production if that production also mentions the same buffer. If both productions make a request, then there is a danger of jamming. If the first production makes a request and the second tests the value of the buffer after the request, then we cannot predict the outcome of the test in the future.  Thus, points where a request is made of a perceptual-motor buffer are points where there are natural breaks in the compilation and one cannot compose the production that makes the request with any later production that operates on the same buffer.

 

7.2.2 Retrieval Buffer

 

Next let us consider the compilation policy for the retrieval buffer.  Because it is an internal buffer (i.e., not subject to the whims of the outside world) it is more predictable and so offers an opportunity for economy. The interesting opportunity for economy occurs when the first production requests a retrieval and the second tests for the successful outcome of that retrieval.  In this case, one can delete the request and test and instead specialize the two productions -- by replacing throughout the production any variables in the retrieval request by the constants they are bound to. This was what happened in the example production above where the retrieved paired-associate zinc-9 was built into the recall-zinc production.  There is one case, however, where it is not possible to drop out the retrieval request and retrieval test.  This is when the first production requests a retrieval and the second test for a retrieval error.  This cannot be composed because declarative memory grows monotonically and it is not safe to predict that in the future there will be a retrieval error.  This suggests that it is preferable, if possible, to write production rules that do not depend on retrieval failures.

 

7.2.3 Goal Buffer

 

The goal buffer is also an internal buffer allowing economies to be achieved. I will treat separately the cases where the first production involves requesting a new goal (the action contains +goal>) and when it does not (the action contains =goal>). 

 

7.2.3.a First Production does not request a new goal.

 

Let C1 and C2 be the goal buffer conditions for the first and second production and A1 and A2 be the corresponding productions’ goal buffer modification actions.  Then, the goal buffer test for the combined production is essentially C1+(C2-A1) where C2-A1 specifies those things tested in C2 that were not created in A1.  The modification for the combined production is A2+(A1~A2) where (A1~A2) indicates those things that were in A1 that are not undone by A2. If the second production requests a new goal (+goal>) that can just be kept.

 

7.2.3.b First production requests a new goal. 

 

This case breaks down into two subcases depending on whether the second production also changes the goal:

 

The second production does not also request a new goal.  In this case the second goal test can be deleted since its satisfaction is guaranteed by the first production.  Let C1 be the goal buffer condition of the first production, A1 be the goal buffer modification action of the first production, N1 be the new goal request in the first production, C2 be the goal condition in the second production and A2 be the goal modification of the second production.  Then the goal test of the composed production is just C1, the goal modification is just A1, and the new goal request is A2+(N1~A2).

 

The second production also requests a new goal.  This is an ambiguous situation.  A conservative policy would be to just block the compilation.  A totally aggressive policy would just skip over the intermediate goal (i.e, the one created by the first and tested by the second production).  What we have implemented is a special case that occurs when the goal set in the second production is exactly the same as the goal tested in the first.  Then, the composed production would have test C1 and modification N2+(A1~N2) with no new goal request.  The consequence of this policy is that the chunk that represented the intermediate goal is not created.  This might be viewed as automating behavior and dropping out intermediate declarative representations.

 

While these are the basic principles of compilation it is the case that there are numerous technical details needed to assure that the proper references are made to variables and constants in the composed productions.  Some of these details will be illustrated in the example of Section 9.4.

 

7.3 Conflict Resolution

 

So far we have discussed how production rules are created but not how they are selected.  When a new production New is composed from old productions Old1 and Old2, it is the case that whenever New could apply Old1 could also apply (Note because New might be specialized it does not follow that whenever Old1 could apply New could also apply.)  The choice between New, Old1, and whatever other productions might apply will be determined by their utilities.  The utility of a production i is calculated as PiG-Ci where G is the value of the goal, Pi is the expected probability that i will achieve the goal and Ci is the expected cost to achieve that goal.  As we learned in Unit 8, the values Pi and Ci are learned from experience.  However, there is no experience associated with the new production New.  Therefore, how are these values to be assigned to that production?  The probability of a production is defined in terms of its successes and failures as

 

 

            P  =                     Probability Learning Equation

 

where Successes and Failures are the number of experienced successes and failures.  Therefore, the question of assigning an initial value of P comes down to the question of how to assign initial values to Successes and Failures.  Similarly, the cost associated with a production is defined as

 

 

            C  =                     Cost Learning Equation

 

where Efforts is the accumulated time over all the successful and failed applications of this production rule.  Therefore, the question of assigning an initial value to C requires that we also assign an initial value to Efforts.

 

Roughly speaking the value of P and C for a new production New should be set based on the values of P and C for the production Old1 that it competes with.  The simple idea would be that the same estimates for P and C should apply.  This is roughly the principle that applies but there are a couple of complications.

 

What we will do is to have a component in the equation that represents the experience of Old1, and a component that reflects the rule’s own experience. For P this amounts to:

 

            P  =   

When the rule is first created, we set priorP to 0. Each time the rule is recreated, however, the value of priorP is increased so that it approaches the P value of Old1, on the basis of the formula:

 

 

This learning system has to parameters, n, which determines how many experiences the priorP value is worth (default 10, can be set by the :ie keyword in the sgp command), and a (default .05, which can be set by a (setf *pc-speed* value) command), which determines the speed of learning.

 

Similar equations determine the behavior of C:

 

            C  =    

 

Here priorC is initially set to G (default 20), and is update each time the rule is recreated by:

 

 

This leaves us with a system that is biased against new productions. However, each time a rule is recreated, its utility will get closer to the utility of the parent rule it competes with, until it is selected due to noise in the utility evaluation. Should the new rule prove to be better than the old, which is often the case, its conflict resolution parameters will come to dominate the old rule and so it will eventually become favored in the conflict resolution.

 

 

7.4 Learning from Instruction

 

Generally production compilation allows a problem to be solved with fewer productions over time and therefore performed faster.  In addition to this speed-up, production compilation results in the drop-out of declarative retrieval as part of the task performance.  As we saw in the example of the previous section, production rules are produced that just "do it" and do not bother retrieving the intervening information.  The classic case of where this applies in experimental psychology is in the learning of experimental instructions.  These instructions are told to the participant and initially the participant needs to interpret these declarative productions.  However, with practice the participant will come to embed these instructions into productions that directly perform the task.  These productions will be like the productions we normally write to model participant performance in the task.    Essentially these are productions that participants learn in the warm-up phase of the experiment.  The paired model for this assignment contains an example of a system that interprets instructions about how to perform a paired associate task and learns productions that do the task directly.

 

In the model are a set of chunks that encode declaratively the following knowledge about the structure of a paired associate task:

 

1. To do the experiment you are to read the stimulus, associate the stimulus with the response, act on the response, and repeat.

2. To associate a response with a stimulus, wait and read the response.

3. To act on an item, if you are still in the stimulus stage, type the item, and read the response.

4. Otherwise to act on an item just pass.

 

Below are a set of "rules" that encode this information.  It would be too much of a digression from the main point of this lesson (production compilation) to give a total exposition of the system.  This is done in the Appendix at the end of this unit.  Nonetheless, the following are the most significant points:

 

A. Each point in the instructions above is represented as a rule for achieving a goal by trying to satisfy a sequence of clauses.  Thus, RULE102 below states that to achieve the experiment goal one satisfies the clauses of reading the stimulus (P102), associating the stimulus with the response (P103), acting on the response (P104), and then repeating (P105).

 

B. Some clauses can be directly achieved and others require that one apply other rules.  Thus, RULE105 specifies how to associate the stimulus and response should it not be possible to retrieve the response.  Rules RULE106 and RULE109 specify two ways to act on the response depending on whether one is in the stimulus or the response phase of the experiment.

 

(RULE102 ISA HEAD RELATION DO-EXPERIMENT PRIOR START)

(P102 ISA CLAUSE RELATION READ PRIOR RULE102 ARG1 VAR1)

(P103 ISA CLAUSE RELATION ASSOCIATE PRIOR P102 ARG1 VAR1 ARG2 VAR2)

(P104 ISA CLAUSE RELATION ACT PRIOR P103 ARG1 VAR2)

(P105 ISA CLAUSE RELATION REPEAT PRIOR P104)

(RULE105 ISA HEAD RELATION ASSOCIATE PRIOR START ARG1 VAR1 ARG2 VAR2)

(P106 ISA CLAUSE RELATION READ PRIOR RULE105 ARG1 VAR2)

(P107 ISA CLAUSE RELATION done PRIOR P106)

(RULE106 ISA HEAD RELATION ACT PRIOR START ARG1 VAR1)

(P108 ISA CLAUSE RELATION STILL-STIMULUS? PRIOR RULE106)

(P109 ISA CLAUSE RELATION TYPE PRIOR P107 ARG1 VAR1)

(P110 ISA CLAUSE RELATION READ PRIOR P108 ARG1 VAR2)

(P111 ISA CLAUSE RELATION done PRIOR P110)

(RULE109 ISA HEAD RELATION ACT PRIOR RULE102 ARG1 VAR1)

(P111 ISA CLAUSE RELATION done PRIOR RULE109)

 

 

The paired model contains a set of productions for interpreting instructions like this rather than productions for actually doing the paired-associate task.  Otherwise, it is nearly identical to the paired model you had for Unit 4.  It can be run either with production compilation on or off.  This is controlled by an additional parameter to the functions collect-data and do-experiment.  Below is a contrast of the behavior with compilation off (second argument to collect-data nil) and compilation on (second argument to collect-data t):

 

? (collect-data 10 nil)

 

 

Latency:

CORRELATION:  0.958

MEAN DEVIATION:  0.360

Trial    1       2       3       4       5       6       7       8

         0.000   2.176   2.177   2.063   2.010   2.077   1.920   1.962

 

 

Accuracy:

CORRELATION:  0.990

MEAN DEVIATION:  0.082

Trial    1       2       3       4       5       6       7       8

         0.000   0.555   0.655   0.730   0.825   0.785   0.860   0.830

NIL

? (collect-data 10 t)

 

 

Latency:

CORRELATION:  0.975

MEAN DEVIATION:  0.146

Trial    1       2       3       4       5       6       7       8

         0.000   2.015   1.983   1.962   1.829   1.764   1.535   1.205

 

 

Accuracy:

CORRELATION:  0.986

MEAN DEVIATION:  0.086

Trial    1       2       3       4       5       6       7       8

         0.000   0.575   0.580   0.725   0.740   0.805   0.880   0.905

 

As can be seen, whether learning is off or on has relatively little impact on the accuracy of recall but turning it on greatly increases the speed of recall.  This is because we are cutting out productions and retrievals. 

 

If you set the :v trace to t you will see the system print out its production compilations.  For instance, the following is a fragment of the trace when we executed the command (do-experiment 1 8 t) -- to study one paired-associate for 8 trials with production compilation turned on.

 

 Time  0.285: Read-Bind-Var1 Selected

 Time  0.335: Read-Bind-Var1 Fired

 Time  0.335: P6419 Retrieved

 Time  0.335: Retrieve-*Var1-Var2 Selected

 Compiling Production Production6439.

 (p Production6439

    =goal>

       isa TASK

       arg1 Var1

       relation Read

       step Reading

       clause P6418

       var2 nil

    =visual>

       isa TEXT

       value =val

 ==>

    =goal>

       relation Associate

       arg1 =val

       arg2 Var2

       clause P6419

       step Retrieval-Harvest

       var1 =val

    +retrieval>

       isa TASK

       relation Associate

       arg1 =val

     - arg2 Var2

     - step Retrieval-Harvest

    -visual-location>

 )

 Parameters for production Production6439:

 :Chance  1.000

 :Effort  0.050

 :P  1.000

 :C  5.000

 :PG-C 15.000

 :Successes (10.0)

 :Failures  (0.0)

 :Efforts (50.0)

 :Success    nil

 :Failure    nil

 

 

 

The production that was learned, Production6439, is a compilation of two of the original productions:

 

(P read-bind-var1

   "read-bind-var1"

   =goal>

      ISA         task

      arg1        var1

      relation    read

      step        reading

      clause      =clause

   =visual>

      ISA         text

      value       =val

==>

   -visual-location>

   =goal>

      step        done

      relation    nil

      arg1        nil

      var1        =val

   +retrieval>

      ISA         clause

      prior       =clause

)

 

 (P retrieve-*var1-var2

   "retrieve-*var1-var2"

   =goal>

      ISA         task

      step        done

      var1        =val1

      var2        nil

   =retrieval>

      ISA         clause

      relation    =relation

      arg1        var1

      arg2        var2

==>

   =goal>

      relation    =relation

      arg1        =val1

      arg2        var2

      clause      =retrieval

      step        retrieval-harvest

   +retrieval>

      ISA         task

      relation    =relation

      arg1        =val1

   -  arg2        var2

   -  step        retrieval-harvest

)

 

 

The first production, Read-Bind-Var1, encodes the stimulus, puts that stimulus in its var1 slot, and retrieves the chunk that gives the next subgoal.  This is the chunk P6419, which asserts that we need to find what var1 is associated with.  Production, Retrieve-*Var1-Var2, attempts to retrieve that element.

 

 

 P6419    7.921

    isa CLAUSE

    relation Associate

    arg1 Var1

    arg2 Var2

    prior P6418

 

Declarative retrieval of the instruction chunk P6419 is compiled out and the resulting production just goes from the stimulus to a goal to test memory with that stimulus. 

 

After 7 trials on this single-paired associate, the following represents the trace of the model on the eighth trial:

 

 Time 70.000: Read-Attend Selected

 Time 70.050: Read-Attend Fired

 Time 70.050: Module :VISION running command MOVE-ATTENTION

 Time 70.135: Module :VISION running command FOCUS-ON

 Time 70.135: Read-Bind-Var1 Selected

 Time 70.185: Read-Bind-Var1 Fired

 Time 70.185: P6419 Retrieved

 Time 70.185: Retrieve-*Var1-Var2 Selected

 Recreating Production Production6439.

 Time 70.235: Retrieve-*Var1-Var2 Fired

 Time 71.025: Goal6442 Retrieved

 Time 71.025: Production6523 Selected

 Recreating Production Production6577.

 Parameters for production Production6577:

 :Chance  1.000

 :Effort  0.050

 :P  1.000

 :C 17.000

 :PG-C  3.000

 :Successes (10.0)

 :Failures  (0.0)

 :Efforts (169.9997973604053)

 :Success    nil

 :Failure    nil

 

 Time 71.075: Production6523 Fired

 Time 71.075: P6427 Retrieved

 Time 71.075: Type-Var1 Selected

 Compiling Production Production6598.

 (p Production6598

    =goal>

       isa TASK

       arg2 Var2

       step Retrieval-Harvest

       clause P6419

    =retrieval>

       isa TASK

       arg2 =val

    !eval! (and (stimulus =goal) (equal (length =val) '1))

 ==>

    =goal>

       relation Act

       arg1 =val

       arg2 nil

       step Subgoaled

       clause P6420

       var2 =val

    +goal>

       isa TASK

       relation nil

       arg1 nil

       clause P6427

       step Done

       rule Rule6425

       var1 =val

       parent =goal

    +retrieval>

       isa CLAUSE

       prior P6427

    +manual>

       isa PRESS-KEY

       key =val

 )

 Parameters for production Production6598:

 :Chance  1.000

 :Effort  0.050

 :P  1.000

 :C  6.000

 :PG-C 14.000

 :Successes (10.0)

 :Failures  (0.0)

 :Efforts (60.00003213993572)

 :Success    nil

 :Failure    nil

 

 Time 71.125: Type-Var1 Fired

 Time 71.125: P6428 Retrieved

 Time 71.125: Module :MOTOR running command PRESS-KEY

 Time 71.125: Ready-To-Read Selected

 Recreating Production Production6482.

 Time 71.175: Ready-To-Read Fired

 Time 71.175: Module :VISION running command CLEAR

 Time 71.225: Module :MOTOR running command PREPARATION-COMPLETE

 Time 71.225: Module :VISION running command CHANGE-STATE

 Time 71.275: Module :MOTOR running command INITIATION-COMPLETE

 Time 71.375: Device running command OUTPUT-KEY

 

<< Window "Paired-Associate Experiment" got key #\9 at time 71375 >>

 

 Time 71.525: Module :MOTOR running command FINISH-MOVEMENT

 Time 75.000: * Running stopped because time limit reached.

 Time 75.000: Read-Attend Selected

 Time 75.050: Read-Attend Fired

 Time 75.050: Module :VISION running command MOVE-ATTENTION

 Time 75.135: Module :VISION running command FOCUS-ON

 Time 75.135: Read-Bind-Var2 Selected

 Time 75.185: Read-Bind-Var2 Fired

 Time 75.185: P6429 Retrieved

 Time 75.185: Go-Back-1 Selected

 Recreating Production Production6486.

 Time 75.235: Go-Back-1 Fired

 Time 75.622: Goal6590 Retrieved

 Time 75.622: Go-Back-Side-Effect Selected

 Merging chunk Goal6596 into chunk Goal6475

 Time 75.672: Go-Back-Side-Effect Fired

 Time 75.672: Production6462 Selected

 Time 75.722: Production6462 Fired

 Time 75.722: Experiment Retrieved

 Time 75.722: Repeat-0-Arg Selected

 Recreating Production Production6532.

 Parameters for production Production6532:

 :Chance  1.000

 :Effort  0.050

 :P  1.000

 :C  5.550

 :PG-C 14.450

 :Successes (10.0)

 :Failures  (0.0)

 :Efforts (55.49974863812315)

 :Success      t

 :Failure    nil

 

 Merging chunk Goal6590 into chunk Start

 Time 75.772: Repeat-0-Arg Fired

 Time 75.772: Rule6417 Retrieved

 Time 75.772: Production6437 Selected

 Recreating Production Production6516.

 Time 75.822: Production6437 Fired

 Time 75.822: Module :VISION running command CLEAR

 Time 75.872: Module :VISION running command CHANGE-STATE

 Time 80.000: * Running stopped because time limit reached.

 

 

Notice that it involves a mixture of productions from the original production set plus new learned ones.  Also we see that sometimes it is choosing old productions and forming the same new one.  This occurs whenever there is a recreate message presented.  The system avoids duplicating productions just as it avoids duplicating chunks. 

 

Where the system to get to the point of maximal learning it would produce a trace like:

 

 Time 70.000: Read-Attend Selected

 Time 70.050: Read-Attend Fired

 Time 70.050: Module :VISION running command MOVE-ATTENTION

 Time 70.135: Module :VISION running command FOCUS-ON

 Time 70.135: Production6657 Selected

 Time 70.185: Production6657 Fired

 Time 70.185: P6428 Retrieved

 Time 70.185: Module :MOTOR running command PRESS-KEY

 Time 70.185: Ready-To-Read Selected

 Time 70.235: Ready-To-Read Fired

 Time 70.235: Module :VISION running command CLEAR

 Time 70.285: Module :MOTOR running command PREPARATION-COMPLETE

 Time 70.285: Module :VISION running command CHANGE-STATE

 Time 70.335: Module :MOTOR running command INITIATION-COMPLETE

 Time 70.435: Device running command OUTPUT-KEY

 

<< Window "Paired-Associate Experiment" got key #\9 at time 70435 >>

 

 Time 70.585: Module :MOTOR running command FINISH-MOVEMENT

 Time 75.000: * Running stopped because time limit reached.

 Time 75.000: Read-Attend Selected

 Time 75.050: Read-Attend Fired

 Time 75.050: Module :VISION running command MOVE-ATTENTION

 Time 75.135: Module :VISION running command FOCUS-ON

 Time 75.135: Production6486 Selected

 Time 75.185: Production6486 Fired

 Time 75.916: Goal6787 Retrieved

 Time 75.916: Go-Back-Side-Effect Selected

 Merging chunk Goal6792 into chunk Goal6475

 Time 75.966: Go-Back-Side-Effect Fired

 Time 75.966: Production6623 Selected

 Merging chunk Goal6787 into chunk Start

 Time 76.016: Production6623 Fired

 Time 76.016: Module :VISION running command CLEAR

 Time 76.066: Module :VISION running command CHANGE-STATE

 Time 76.752: Goal6475 Retrieved

 Time 80.000: * Running stopped because time limit reached.

 

The newly learned productions are:

 

(p Production6657

    =goal>

       isa TASK

       arg1 Var1

       relation Read

       step Reading

       clause P6418

       var2 nil

    =visual>

       isa TEXT

       value "zinc"

    !eval! (stimulus =goal)

 ==>

    =goal>

       relation Act

       arg1 "9"

       arg2 nil

       step Subgoaled

       clause P6420

       var2 "9"

       var1 "zinc"

    +goal>

       isa TASK

       relation nil

       arg1 nil

       clause P6427

       step Done

       rule Rule6425

       var1 "9"

       parent =goal

    +retrieval>

       isa CLAUSE

       prior P6427

    -visual-location>

    +manual>

       isa PRESS-KEY

       key "9"

 )

 (p Production6486

    =goal>

       isa TASK

       arg1 Var2

       relation Read

       step Reading

       clause P6428

       parent =oldgoal

     - parent Experiment

    =visual>

       isa TEXT

       value =val

 ==>

    =goal>

       step Go-Back

       parent nil

       relation nil

       arg1 nil

       var2 =val

    +retrieval>

       =oldgoal

    -visual-location>

 )

 (p Production6623

    =goal>

       isa TASK

       step Subgoaled

       clause P6420

     - arg1 Var1

     - arg1 Var2

     - arg2 Var1

     - arg2 Var2

       parent Experiment

       rule =rule

 ==>

    =goal>

       step Repeat

       relation nil

       arg1 nil

       arg2 nil

    +goal>

       isa TASK

       relation Read

       arg1 Var1

       arg2 nil

       clause P6418

       step Ready-To-Read

       rule Rule6417

       parent Experiment

    -visual>

 )

 

The first production, Production6657, goes directly from the word "zinc" on the screen to the typing of the response.  It is no longer necessary to retrieve the declarative chunk.  If productions like these were always operative it would only take .435 seconds to respond.  The other two productions are responsible for resetting the system after it has read the response to be ready for the stimulus on the next trial.

 

7.5 Assignment

 

Your assignment is to make a model that learns the past tense of verbs in English. The learning process of the English past tense is characterized by the so-called U-shaped learning in the learning of irregular verbs. That is, at a certain age children inflect irregular verbs like “to break” correctly, so they say “broke” if they want to use the past tense. But at a later age, they overgeneralize, and start saying “breaked”. At an even later stage they again inflect irregular verbs correctly. Some people, such as Pinker and Marcus, interpret this as evidence that a rule is learned to create regular past tense (add –ed to the stem). According to Pinker and Marcus, after this rule has been learned, it is overgeneralized so that it will also produce regularized versions of irregular verbs.

 

Part of the model is already given in the file past-tense. The assignment is to make a model that learns both the regular rule for the past tense, and particular rules for particular irregular verbs. So eventually it should learn rules like:

 

IF the goal is to make the past tense of a verb

THEN copy that verb and add –ed

 

IF the goal is to make the past tense of the verb have

THEN the past tense is had

 

The code that is provided does two things. It adds correct past tenses to declarative memory, reflecting the fact that a child hears and then encodes correct past tenses in the environment.  It also creates goals to generate the past tense of a verb and then runs the model to generate one.

 

Here are examples of correctly formed past tenses:

 

WORD2323

            isa past-tense

            verb have

            stem had

            suffix blank

            status nil

 

is a correct encoding of the irregular verb have and:

 

WORD4323

            isa past-tense

            verb use

            stem use

            suffix ed

            status nil

 

is a correct encoding of the regular verb use.

 

A goal to generate a new past tense will look like this:

 

GOAL332

            isa past-tense

            verb get

            stem nil

            suffix nil

            status start

 

 

 

Your model has to fill in the stem and suffix slots of the goal to indicate the past tense form of the verb and set the status slot to done. Then, one of the three production rules given will fire to simulate the final encoding and “use” of the word. There are three possible cases. The first is an irregular inflection, in which the suffix is blank.  There is a regular inflection, in which the stem is the same as the verb and the suffix is ed, and finally, there is a non-inflection case, in which both the stem and suffix are nil. The non-inflection case applies when the model cannot come up with a past tense at all, either because it has no example to retrieve or no rule or strategy to come up with anything else. The regular case and the non-inflection case each receive a cost penalty in the form of an additional effort added to the rule. The extra effort added to the regular rule reflects the fact that regular forms would take longer on average to say, and the penalty on the non-inflection rule reflects the fact that the past tense has to be indicated by some other method, for example by adding “yesterday” or some other explicit reference to time when it is actually used. 

 

One important thing to notice is that all three of the provided productions are marked as a success.  The model receives no feedback as to whether the past tenses it produces are correct – any past tense is considered a success.  The only feedback is has are the correctly constructed verbs that it hears from the environment. 

 

 

You can run the model with the do-it command. It takes as an argument the number of words you want the model to generate:

 

(do-it 5000)

 

As optional parameters you can specify whether or not you want ACT-R to be verbose (:v t), or whether ACT-R should continue with the run you started in an earlier do-it (:cont t).

 

During the run the simulation will display four numbers on each row, reflecting the results of the last 100 words. The first number is the proportion correct of irregular verbs. The second number is the proportion of irregular verbs that are inflected regularly. An increase in this number indicates a regular rule is active i.e. irregular verbs are having ed added to them. The third number is the proportion of irregular verbs that are not inflected at all.  The fourth number is the proportion of inflected irregular verbs that are inflected correctly (the non-inflected verbs are not counted for this measure). It is in this last column that you should see a U-shape.

 

It often requires much more than 5000 trials to see the effect, and taking 30000 to 50000 trials is not uncommon.  The :cont (continue) option in the do-it function allows you to run more trials without resetting the model. After the model is done, the report-irreg function gives a report where results are summarized for 1000 trials at a time. The 100 trial summaries displayed during the do-it function run are more to see the model is still doing things, and in what direction the results are going.   If you have loaded the ACT-R environment then you can pass t as a parameter to the report-irreg function to have it generate a graph of the data.  What you are looking for from the model is a graph that looks something like this:

 

 

It starts out with a high percentage correct, dips down, and then goes back up.  That is the U-shaped learning result.

 

This model differs from other models in the tutorial in that it does not model a particular experiment, but rather some long term development. This has a couple of consequences for the model.  One of those is that using perceptual/motor modules does not contribute much to the objective of the model. Thus things like the "hearing" of past tenses and the eventual generation of the verb in speech are not modeled for the purpose of this exercise. It could be modeled, but it is not what the model and exercise are about. Therefore explicitly adding already processed perceived past tenses to declarative memory and just adding extra time for generation of certain classes of verb tenses serves as a reasonable compromise.

 

The other big consequence is that runs of the model may differ considerably. On the one hand this is not so bad, as children also differ with respect to U-shaped learning. One reason for the relative unpredictability is the fact that this simulation runs with a very limited vocabulary (extending the vocabulary results in a model that runs extremely slowly which is not beneficial as an exercise), but the effect of the noise in the model also has an impact that can create noticeable effects over the long term running of the model. This also makes comparing this model to data difficult, and hard data on the phenomenon are scarce, although the phenomenon of the U-shape is reported often. A few children have been followed in a longitudinal study, and there is a spreadsheet included with the unit materials (data.xls) that shows those results for comparison.

 

So, in terms of the assignment the objective is to write a model that learns the appropriate productions for producing past tenses.  There is no parameter adjustment or data fitting required.  The key to a successful model is to implement both a retrieval strategy and a simple analogy strategy.  The model can either remember a correct past tense or the model attempts to generate a past tense based on another retrieved verb.  The productions you write should make no explicit reference to either ed or blank because that is what the model is to eventually learn i.e. you do not write a production that says add ed, but though the compilation mechanism such a production is created.  Although the experiment code is only outfitted with a limited set of words, the frequency that the words are presented to the model is in accordance with the frequency they appear in real life.  So, if your model learns the proper productions it should generate the U-shaped learning automatically, but not necessarily on every run.

 

7.6 Appendix on Learning from Instruction

 

The basic idea behind the representation of instructions is that they should be represented as sequences of instructions about how to achieve goals.  The instruction about how to achieve a goal is represented as a sequence of clauses that need to be achieved.  Below in Prolog format is a set of instructions about how to perform a simple paired associate task.  They encode essentially the following knowledge:

 

1. To do the experiment you are to read the stimulus, associate the stimulus with the response, act on the response, and repeat.

2. To associate a response with a stimulus, wait and read the response.

3. To act on an item, if you are still the stimulus stage, type the item, and read the response.

4. Otherwise to act on an item just pass.

 

The Prolog clauses are:

 

do-experiment :- read(Stimulus),associate(Stimulus,Response),

                            act(Response), repeat.

associate(Probe,Answer):- read(Answer).

act(Item):- still-stimulus?, type (Item), read (Answer).

act(Item).

 

The main goal of do-experiment breaks down into a sequence of 4 clauses of reading the stimulus, finding the association between the stimulus and response, acting on the response, and a special goal of repeating.  If it is not possible to retrieve the response to the stimulus, there is a special rule that says to simply read the answer. There is an ordered set of rules for acting on the response.  The first rule tests that one is still in the stimulus stage, and if so types the item and read the answer.  Otherwise if it is too late one just passes on any action.

 

This small example reflects most of the significant structure of the representation of instruction.

 

1. A rule for a goal is represented as an ordered sequence of clauses.  Should it be not possible to satisfy one clause, the rule immediately fails.  There is no backup (unlike Prolog).

 

2. The rules for a goal are tried in strict sequence and in this way one can arrange to have default rules tried only after special case rules.

 

3. Iteration is achieved with a special case repeat goal.

 

4. The terms capitalized above are variables.  Rules have at most two variables.

 

5. Relations have at most two arguments.

 

The first three constraints enable a relatively simple control structure for instruction interpretation.  The last two constraints minimize the number of cases we have to deal with.  It does appear that this is adequate for full expressive power.

 

Obviously, we do not encounter instruction as prolog clauses.  The above representation is just for my (and perhaps your) own conceptual clarity.  I have developed a means of representing these prolog clauses as LISP structure and parsing them into internal ACT-R structures.  The following is the LISP encoding of the above clauses:

 

(setf instructions '(

     (do-experiment read (stimulus) associate (stimulus response)

                    act (response) repeat)

     (associate (probe answer) read (answer) done)

     (act (item) still-stimulus? type (item) read (answer) done)

     (act (item) done)))

 

Note that each clause requires a specification of whether it should be repeated (repeat) or whether it terminates (done).  There is a LISP function parse that will convert these into ACT-R structure:

 

? (parse instructions)

 

 

 

The heads of these rules are represented as structures of type head and the clauses as structures of type clause.  The following are the type definitions used in the instruction follower:

 

(chunk-type clause relation arg1 arg2 prior)

(chunk-type head relation arg1 arg2 prior)

(chunk-type task parent relation arg1 arg2 step rule clause var1 var2)

 

Heads and clauses have slots for their relation and (possibly as many as) 2 arguments plus a prior slot.  The prior slot keeps track of the order of rules in the case of heads and the order of clauses in the case of clauses.  The last chunk type is the task type that keeps track of the interpretation of a rule.  It has a parent slot to keep track of what goal called it.  It has slots to represent the relation and arguments it is currently interpreting and a step slot to represent where it is in the interpretation of the clause.  It has a rule slot to represent which rule it is working on and a clause slot to represent which clause it is working on within the rule.  Finally it has two slots to keep track of the binding of the variables.

 

Interpretation of Instructions

 

Initiation of a Rule

A goal starts out as task with its relations and arguments filled in and the step set to achieve.  The following production is responsible for selecting the first rule to apply to achieve that relation:

 

(P retrieve-rule

   "retrieve-rule"

   =goal>

      ISA         task

      relation    =relation

      step        achieve

==>

   +retrieval>

      ISA         head

      relation    =relation

      prior       start

   =goal>

      step        rule

)

 

Then, depending on the number of arguments that the relation takes, one of the following three rules applies:

 

(P instantiate-rule-0-args

   "instantiate-rule-0-args"

   =goal>

      ISA         task

      relation    =relation

      step        rule

   =retrieval>

      ISA         head

      arg1        nil

==>

   =goal>

      step        done

      relation    nil

      rule        =retrieval

   +retrieval>

      ISA         clause

      prior       =retrieval

)

 

(P instantiate-rule-var1

   "instantiate-rule-var1"

   =goal>

      ISA         task

      relation    =relation

      arg1        =val

      arg2        nil

      step        rule

   =retrieval>

      ISA         head

      arg1        var1

      arg2        nil

==>

   +retrieval>

      ISA         clause

      prior       =retrieval

   =goal>

      step        done

      relation    nil

      arg1        nil

      rule        =retrieval

      var1        =val

)

 

(P instantiate-rule-var1-var2

   "instantiate-rule-var1-var2"

   =goal>

      ISA         task

      relation    =relation

      arg1        =val1

      arg2        =val2

      step        rule

   =retrieval>

      ISA         head

      arg1        var1

      arg2        var2

==>

   +retrieval>

      ISA         clause

      prior       =retrieval

   =goal>

      step        done

      relation    nil

      arg1        nil

      arg2        nil

      var1        =val1

      var2        =val2

      rule        =retrieval

)

 

Note that these productions bind the arguments to variable slots in the goal so that they can be remembered while instantiating the clauses of that rule.  The first argument in the head will always be bound to the var1 slot and the second argument to the var2 slot.  The relation and argument slots will change as the focused clause changes and so they are set to nil.   The var1 and var2 slots will remember the variable bindings.  As we will see at the end of achieving a goal, the relation and argument slots will be set back to values for the head. A retrieval request is made for the first clause and the step slot is set to done as a signal that it is time to go onto the next clause.

 

There are three basic ways a clause can be satisfied.  First, there might be some special productions for achieving that clause like how to read a word or move a mouse.  Second, it is possible that the clause can be satisfied by retrieving some fact in the data base.  Third, it may be necessary to try to apply some other declarative rule for achieving the clause.  These three options are ordered. 

 

Failure to Find a Rule

It may be the case that there are no rules for achieving that goal or that all the rules have been exhausted.  In that case one needs to return failure the higher goal that called the current goal.  This higher goal is contained in the parent slot of the current goal.  The following production retrieves that goal noting that there has been a failure to achieve it:

 

(P retry-higher

   "retry-higher"

   =goal>

      ISA         task

      parent      =parent

   -  parent      experiment

      step        rule

   =retrieval>

      ISA         error

==>

   +retrieval>    =parent

   =goal>

      step        pop-failure

)

 

The term "experiment" in this situation refers to the top goal and the negative test in the above rule is a test to prevent popping out of the task. 

 

To deal with the failure the parent goal has to be re-established and the system checks whether there are any other rules that might achieve the clause it was at.  This process takes place in two steps.  First a copy of the parent goal is created from which to try again:

 

(P pop-failure

   "pop-failure"

   =goal>

      ISA         task

      step        pop-failure

   =retrieval>

      ISA         task

      parent      =grandparent

      rule        =rule

==>

   +retrieval>    =grandparent

   +goal>

      ISA         task

      step        try-again

      rule        =rule

      parent      =grandparent

)

 

The parent (grand parent goal if you like) of this parent goal is retrieved from which one can recreate the initial state of the goal being retried.  There are three productions to deal with this depending on whether the parent goal has zero, one, or two arguments:

 

(P retry-0-arg

   "retry-0-arg"

   =goal>

      ISA         task

      step        try-again

      rule        =rule

   =retrieval>

      ISA         task

      relation    =rel

      arg1        nil

==>

   +retrieval>

      ISA         head

      prior       =rule

   =goal>

      relation    =rel

      arg1        nil

      step        rule

)

 

(P retry-1-arg

   "retry-1-arg"

   =goal>

      ISA         task

      step        try-again

      rule        =rule

   =retrieval>

      ISA         task

      relation    =rel

      arg1        =arg1

      arg2        nil

==>

   +retrieval>

      ISA         head

      prior       =rule

   =goal>

      relation    =rel

      arg1        =arg1

      arg2        nil

      step        rule

)

 

(P retry-2-args

   "retry-2-args"

   =goal>

      ISA         task

      step        try-again

      rule        =rule

   =retrieval>

      ISA         task

      relation    =rel

      arg1        =arg1

      arg2        =arg2

==>

   +retrieval>

      ISA         head

      prior       =rule

   =goal>

      relation    =rel

      arg1        =arg1

      arg2        =arg2

      step        rule

)

 

In all cases a request is made to retrieve the rule that follows the rule last tried.

 

Special Instructions for Achieving a Clause

One can provide special productions for achieving any clause.  The following is an example of the productions we use in the paired-associate model for typing

 

(P type-var1

   "type-var1"

   =goal>

      ISA         task

      step        done

      var1        =val

   =retrieval>

      ISA         clause

      relation    type

      arg1        var1

      arg2        nil

   !eval!         (equal (length =val) 1)

==>

   +manual>

      ISA         press-key

      key         =val

   =goal>

      relation    nil

      arg1        nil

      clause      =retrieval

      step        done

   +retrieval>

      ISA         clause

      prior       =retrieval

)

 

In this case there is a single production but sometimes it takes multiple productions to achieve a clause.  All cases have to begin with a rule like this inspecting the retrieved clause and taking appropriate action.  All have to end with a rule like this, setting the step slot to done and retrieving the next clause.

 

 

Retrieval to Instantiate a Clause

Sometimes the clause will have one argument bound and the other not.  This is the situation in which we first try to retrieve another clause in memory that will fill in the missing value. There are eight possibilities created by whether it is the first or second variable we are trying to bind, by whether it is first or second argument, and by whether the other value is just given or bound to a variable:

 

(P retrieve-var1-val

   "retrieve-var1-val"

   =goal>

      ISA         task

      step        done

      var1        nil

   =retrieval>

      ISA         clause

      relation    =relation

      arg1        var1

      arg2        =val2

   -  arg2        var2

==>

   =goal>

      relation    =relation

      arg1        var1

      arg2        =val2

      clause      =retrieval

      step        retrieval-harvest

   +retrieval>

      ISA         task

      relation    =relation

   -  arg1        var1

      arg2        =val2

   -  step        retrieval-harvest

)

 

(P retrieve-var1-*var2

   "retrieve-var1-*var2"

   =goal>

      ISA         task

      step        done

      var1        nil

      var2        =val2

   =retrieval>

      ISA         clause

      relation    =relation

      arg1        var1

      arg2        var2

==>

   =goal>

      relation    =relation

      arg1        var1

      arg2        =val2

      clause      =retrieval

      step        retrieval-harvest

   +retrieval>

      ISA         task

      relation    =relation

   -  arg1        var1

      arg2        =val2

   -  step        retrieval-harvest

)

 

(P retrieve-var2-val

   "retrieve-var2-val"

   =goal>

      ISA         task

      step        done

      var2        nil

   =retrieval>

      ISA         clause

      relation    =relation

      arg1        var2

      arg2        =val2

   -  arg2        var1

==>

   =goal>

      relation    =relation

      arg1        var2

      arg2        =val2

      clause      =retrieval

      step        retrieval-harvest

   +retrieval>

      ISA         task

      relation    =relation

   -  arg1        var2

      arg2        =val2

   -  step        retrieval-harvest

)

 

(P retrieve-var2-*var1

   "retrieve-var2-*var1"

   =goal>

      ISA         task

      step        done

      var1        =val2

      var2        nil

   =retrieval>

      ISA         clause

      relation    =relation

      arg1        var2

      arg2        var1

==>

   =goal>

      relation    =relation

      arg1        var2

      arg2        =val2

      clause      =retrieval

      step        retrieval-harvest

   +retrieval>

      ISA         task

      relation    =relation

   -  arg1        var2

      arg2        =val2

   -  step        retrieval-harvest

)

 

(P retrieve-val-var1

   "retrieve-val-var1"

   =goal>

      ISA         task

      step        done

      var1        nil

   =retrieval>

      ISA         clause

      relation    =relation

      arg2        var1

      arg1        =val1

   -  arg1        var2

==>

   =goal>

      relation    =relation

      arg2        var1

      arg1        =val1

      clause      =retrieval

      step        retrieval-harvest

   +retrieval>

      ISA         task

      relation    =relation

      arg1        =val1

   -  arg2        var1

   -  step        retrieval-harvest

)

 

(P retrieve-*var2-var1

   "retrieve-*var2-var1"

   =goal>

      ISA         task

      step        done

      var1        nil

      var2        =val2

   =retrieval>

      ISA         clause

      relation    =relation

      arg1        var2

      arg2        var1

==>

   =goal>

      relation    =relation

      arg1        =val2

      arg2        var1

      clause      =retrieval

      step        retrieval-harvest

   +retrieval>

      ISA         task

      relation    =relation

      arg1        =val2

   -  arg2        var1

   -  step        retrieval-harvest

)

 

(P retrieve-val-var2

   "retrieve-val-var2"

   =goal>

      ISA         task

      step        done

      var2        nil

   =retrieval>

      ISA         clause

      relation    =relation

      arg2        var2

      arg1        =val1

   -  arg1        var1

==>

   =goal>

      relation    =relation

      arg2        var2

      arg1        =val1

      clause      =retrieval

      step        retrieval-harvest

   +retrieval>

      ISA         task

      relation    =relation

      arg1        =val1

 

   -  arg2        var2

   -  step        retrieval-harvest

)

 

(P retrieve-*var1-var2

   "retrieve-*var1-var2"

   =goal>

      ISA         task

      step        done

      var1        =val1

      var2        nil

   =retrieval>

      ISA         clause

      relation    =relation

      arg1        var1

      arg2        var2

==>

   =goal>

      relation    =relation

      arg1        =val1

      arg2        var2

      clause      =retrieval

      step        retrieval-harvest

   +retrieval>

      ISA         task

      relation    =relation

      arg1        =val1

   -  arg2        var2

   -  step        retrieval-harvest

)

 

All of these productions are given lower utilities to make sure they are only tried when there are no special case rules for that relation.

 

The following productions are responsible for harvesting successful retrievals.  They deal with the four possibilities created by whether var1 or var2 is to be bound and whether it is arg1 or arg2:

 

(P harvest-var1a

   "harvest-var1a"

   =goal>

      ISA         task

      arg1        var1

      step        retrieval-harvest

      clause      =clause

   =retrieval>

      ISA         task

      arg1        =val

==>

   =goal>

      step        done

      relation    nil

      arg1        nil

      arg2        nil

      var1        =val

   +retrieval>

      ISA         clause

      prior       =clause

)

 

(P harvest-var2a

   "harvest-var2a"

   =goal>

      ISA         task

      arg1        var2

      step        retrieval-harvest

      clause      =clause

   =retrieval>

      ISA         task

      arg2        =val

==>

   =goal>

      step        done

      relation    nil

      arg1        nil

      arg2        nil

      var2        =val

   +retrieval>

      ISA         clause

      prior       =clause

)

 

(P harvest-var1b

   "harvest-var1b"

   =goal>

      ISA         task

      arg2        var1

      step        retrieval-harvest

      clause      =clause

   =retrieval>

      ISA         task

      arg2        =val

==>

   =goal>

      step        done

      relation    nil

      arg1        nil

      arg2        nil

      var1        =val

   +retrieval>

      ISA         clause

      prior       =clause

)

 

(P harvest-var2b

   "harvest-var2b"

   =goal>

      ISA         task

      arg2        var2

      step        retrieval-harvest

      clause      =clause

   =retrieval>

      ISA         task

      arg2        =val

==>

   =goal>

      step        done

      relation    nil

      arg1        nil

      arg2        nil

      var2        =val

   +retrieval>

      ISA         clause

      prior       =clause

)

 

The following rule transitions to setting a subgoal to find the variable should the retrieval fail:

 

 

(P fail-harvest-var

   "fail-harvest-var"

   =goal>

      ISA         task

      relation    =relation

      step        retrieval-harvest

   =retrieval>

      ISA         error

==>

   +retrieval>

      ISA         head

      relation    =relation

      prior       start

   =goal>

      step        subgoal-var

)

 

Subgoaling Variables

In addition to the case of failure of retrieval, we will set a subgoal to find a value of a variable immediately when there is only a single unbound variable argument.  There are two production rules corresponding to whether it is the first or second variable.  As in the case of the productions that request retrieval these are given lower utility so that special case rules for the relation will be tried first.

 

(P subgoal-rule-var1

   "subgoal-rule-var1"

   =goal>

      ISA         task

      step        done

      var1        nil

   =retrieval>

      ISA         clause

      relation    =relation

   -  relation    read

      arg1        var1

      arg2        nil

==>

   +retrieval>

      ISA         head

      relation    =relation

      prior       start

   =goal>

      relation    =relation

      arg1        var1

      step        subgoal-var

      clause      =retrieval

)

 

(P subgoal-rule-var2

   "subgoal-rule-var2"

   =goal>

      ISA         task

      step        done

      var2        nil

   =retrieval>

      ISA         clause

      relation    =relation

   -  relation    read

      arg1        var2

      arg2        nil

==>

   +retrieval>

      ISA         head

      relation    =relation

      prior       start

   =goal>

      relation    =relation

      arg1        var2

      step        subgoal-var

      clause      =retrieval

)

 

Both of these productions request retrieval of a rule associated with that relation.  The next productions deal with the processing of the retrieved rule.  If there are two arguments for this retrieved rule, one will be bound upon the calling of the rule.  In the productions below we create a new goal (+goal) and use the parent slot of the new goal to point to the original goal.

 

(P subgoal-find-first-arga

   "subgoal-find-first-arga"

   =goal>

      ISA         task

      relation    =relation

      step        subgoal-var

   =retrieval>

      ISA         head

      arg1        var1

      arg2        nil

==>

   +retrieval>

      ISA         clause

      prior       =retrieval

   =goal>

      step        subgoaled

   +goal>

      ISA         task

      parent      =goal

      step        done

      rule        =retrieval

)

 

(P subgoal-find-first-argb

   "subgoal-find-first-argb"

   =goal>

      ISA         task

      relation    =relation

      arg2        =val

   -  arg2        var1

   -  arg2        var2

      step        subgoal-var

      parent      =parent

   =retrieval>

      ISA         head

      arg1        var1

      arg2        var2

==>

   +retrieval>

      ISA         clause

      prior       =retrieval

   +goal>

      ISA         task

      var2        =val

      parent      =goal

      step        done

      rule        =retrieval

   =goal>

      step        subgoaled

)

 

(P subgoal-find-second-arg

   "subgoal-find-second-arg"

   =goal>

      ISA         task

      relation    =relation

      arg1        =val

   -  arg1        var1

   -  arg1        var2

      step        subgoal-var

      parent      =parent

   =retrieval>

      ISA         head

      arg1        var1

      arg2        var2

==>

   +retrieval>

      ISA         clause

      prior       =retrieval

   +goal>

      ISA         task

      var1        =val

      parent      =goal

      step        done

      rule        =retrieval

   =goal>

      step        subgoaled

)

 

Finally, we have to deal with the case when there is no rule that applies:

 

(P fail-subgoal-var

   "fail-subgoal-var"

   =goal>

      ISA         task

      step        subgoal-var

      parent      =parent

   =retrieval>

      ISA         error

==>

   =goal>

      step        try-again

      relation    nil

      arg1        nil

      arg2        nil

   +retrieval>    =parent

)

 

Returning from Subgoals

The following is the production that recognizes generally when a goal has been achieved.  This occurs when one reaches the ending done clause:

 

(P go-back-1

   "go-back-1"

   =goal>

      ISA         task

      step        done

      parent      =oldgoal

   -  parent      experiment

   =retrieval>

      ISA         clause

      relation    done

==>

   +retrieval>    =oldgoal

   =goal>

      step        go-back

      parent      nil

)

 

 

For our purposes "experiment" is considered to be the top goal and the test is just to prevent us from jumping out of the experiment.  This production requests retrieval of the parent goal.

 

Before returning to the parent goal an attempt is made to set the subgoal to a state that contains the answer (so it can be retrieved next time and so avoid the need for a subgoal).  This is determined by inspecting the parent goal and filling in the variable.  There are 4 cases if the variable is in the first slot depending on whether it is var1 or var2 and whether the second argument is filled or not.  If the variable is in the second slot there are two cases depending on whether it is var1 or var2

 

(P go-back-arg1a

   "go-back-arg1a"

   =goal>

      ISA         task

      step        go-back

      var1        =arg1

   =retrieval>

      ISA         task

      relation    =rel

      arg1        var1

      arg2        =arg2

      step        subgoaled

==>

   =goal>

      relation    =rel

      arg1        =arg1

      arg2        =arg2

   +retrieval>    =goal

   +goal>         =retrieval

)

 

(P go-back-arg1b

   "go-back-arg1b"

   =goal>

      ISA         task

      step        go-back

      var1        =arg1

   =retrieval>

      ISA         task

      relation    =rel

      arg1        var2

      arg2        =arg2

      step        subgoaled

==>

   =goal>

      relation    =rel

      arg1        =arg1

      arg2        =arg2

   +retrieval>    =goal

   +goal>         =retrieval

)

 

(P go-back-arg1c

   "go-back-arg1c"

   =goal>

      ISA         task

      step        go-back

      var1        =arg1

   =retrieval>

      ISA         task

      relation    =rel

      arg1        var1

      arg2        nil

      step        subgoaled

==>

   =goal>

      relation    =rel

      arg1        =arg1

      arg2        nil

   +retrieval>    =goal

   +goal>         =retrieval

)

 

(P go-back-arg1d

   "go-back-arg1d"

   =goal>

      ISA         task

      step        go-back

      var1        =arg1

   =retrieval>

      ISA         task

      relation    =rel

      arg1        var2

      arg2        nil

      step        subgoaled

==>

   =goal>

      relation    =rel

      arg1        =arg1

      arg2        nil

   +retrieval>    =goal

   +goal>         =retrieval

)

 

(P go-back-arg2a

   "go-back-arg2a"

   =goal>

      ISA         task

      step        go-back

      var2        =arg2

   =retrieval>

      ISA         task

      relation    =rel

      arg1        =arg1

      arg2        var2

      step        subgoaled

==>

   =goal>

      relation    =rel

      arg1        =arg1