EPAM VI

programmed by Howard B. Richman

February 23, 2002 version

Copyright 2002

 

Click here to download EPAM VI as a zip file which will unpack into Windows files  .

Click here to download EPAM VI as a zip file which will unpack into UNIX files.

Click here to read Simulations of Classification Learning Using EPAM VI – CIP Working Paper 552

Click here to read Simulations of Paired Associate Learning Using EPAM VI – CIP Working Paper 553

 

For best results unpack EPAM into a directory or folder just off your root directory and entitled “epam”.  The Windows and Unix versions only differ in that each line in the Windows files ends with a return and line feed while each line in the Unix versions ends with just a line feed.  

 

If you are using Allegro Common Lisp 5.0 Release from Franz, Inc., you should be able to run EPAM VI without change.  Simply open Allegro Common Lisp and then click on “File” and then “Open Project” and then select “epam6.lpr” from the \epam directory.

 

If you are running a different version of common lisp, you will need to take out one of the commands from each of the files: (in-package :common-graphics-user)

 

If you are using Allegro Common Lisp, then EPAM will automatically be loaded in the following order:

 

1.     The first file to load will be epam6.lsp. This program includes all of the main EPAM 6 routines.  If you are developing an application using EPAM VI, you may not have to load any additional files.

2.     The second file to load is epamdata.lsp  This file includes data sets that are used in various EPAM simulations.

3.     The third file to load is master.lsp. This file includes EPAM’s simulation of short term memory as well as the experiments that are used to simulate short term memory and paired-associate learning.   At the bottom of the file you will find routines entitled run-all-paired-associate-simulations and run-all-stm-simulations. You can use these routines to generate all the data in our paired-associate and short-term-memory simulations.

4.     The fourth file to load is exptsim.lsp.  This file includes EPAM’s simulation of expert mnemonist DD who could repeat up to 100 digits presented one per second. 

5.     The fifth file to load is serant.lsp.  This file includes EPAM’s simulations of the paired-associate paradigm.  The routine at the bottom run-all-serial-anticipation-simulations runs the simulations here.

6.     The sixth file to load is conteff.lsp.  This file runs all of the context-effects-in-letter-perception simulations.

7.     The last file to load is concform.lsp.  This file runs all of the classification learning  experiments.  The routine just before the bottom run-all-concept-formation-simulations runs the simulations here.

 

To run all of the paired-associate simulations, just type:

 

(run-all-paired-associate-simulations)

 

in the debug window and then press “Enter”.  You can also run individual simulations in the debug window.

 

If you are running a simulation and you want to follow what is happening more closely, you can stop the simulation by clicking “Run” then “Interrupt” and then click the “Debug” button.  Then you can change several parameters that control the display.  If you type

 

(turn-printing-on)

 

in the Debug Window and then press return you will turn on all of these variables at once.  If you type

 

(turn-printing-off)

 

you will turn them off.  Or you can simply turn some on or some off.  The variables that control display are:

 

·        *print-time-updates*  -- this variable shows whenever something advances the clock.

·        *print-imagery-stores*  -- this variable prints contents of imagery stores

·        *print-experimenter-updates* -- this variable prints results while they are collected

·        *print-epam-updates*  -- this variables gives you a window into epam learning

·        *print-forgetting-updates* -- this variable prints forgetting caused by decay

·        *print-net-updates* - this variable frequently prints the discrimination net contents.

·        *print-strategy-updates*  - this variable lets you know why epam does what it does

·        *print-major-updates*  - this variable gives you more results for the experiment

 

You can turn any of these on individually by typing the equivalent of:

 

(setf *print-time-updates* t)

 

in the debug window and turn any of them off individually by typing the equivalent of:

 

(setf *print-time-updates* nil)

 

in the debug window.

 

Also you can print the contents of the discrimination net by printing:

 

(print-net)

 

in the debug window.  If you want to see everything that is in the discrimination net you can type:

 

(print-net *net* ‘everything)

 

Then to restart the program, click on the circular arrow icon, “return from break” will be highlighted.  Then click on the “Invoke Selected Restart” button.

 

EPAM Object

 

You could also run EPAM in interactive mode.  In order to understand how to do so, you need to understand EPAM objects.  

 

EPAM uses a homogenous representation for the knowledge that it learns and accesses: the object.  The same representation is used for external objects (“stimuli”) and internal objects (“images”).  An object is a list of parts (called “subobjects”) and/or a set of features and properties.  The object itself can have properties of its own that are different from the properties of its subobjects. The list of subobjects is an ordered list.  This representation is recursively defined, i.e., a subobject or a property is itself an object.  The simplest of all objects is represented by a LISP atom, usually a character representing an individual letter.

 

 This representation of objects was borrowed from the IPL-V programming language, the precursor of LISP in which EPAM was first modeled.  In that language the first cell of a list was usually reserved for a description list.  When we translated EPAM from IPL-5 to LISP we kept the same representation using a LISP construct known as an association list in the first cell to hold the information of the description list.

 

For example, a Stimulus-Response episode could be an object consisting of two subobjects, the Stimulus syllable (such as “BAJ”) followed by a Response syllable (such as “JID”); and it might have a property (e.g., its color is red).  The Stimulus (such as BAJ) might be a syllable of three letters, hence three subobjects:

 

((is-a syllable)) B A J)

 

The description list of this syllable simply tells us that it is a syllable.  (Just as in the ACT system, every object in EPAM has a value for the attribute “is-a”.)  The ordered list consisting of three subobjects follows the head cell.  These three subobjects are the letters B, A, and J.  The stimulus-response object described above would appear as the following list:

 

(((is-a episode) (color red)) (((is-a syllable)) B A J) (((is-a syllable)) J I D))

 

The description list of the stimulus-response object above consists of two associations: (1) is-a à episode, and (2) color à red.  The first of those associations tells us that the object in question is an episode.  The second of those associations tells us that its color is red.  The two subobjects are themselves objects, the first of them is the syllable “BAJ” and the second is the syllable “JID”.

 

Once this episode has been fully learned, there will probably be three new nodes in EPAM’s declarative memory, one for the episode uniting “BAJ” and “JID”, one for the syllable “BAJ” and one for the syllable “JID”.  Each of those nodes will have an image associated with it.  That image is used by the system when it wants to output (i.e. speak, write, or imagine) a copy of the object.  The image associated with the syllable JID is likely to have the following structure:

 

(((is-a syllable)) J I D)

 

This image is so complete that the subject could respond with the entire response “JID” if asked to articulate the contents of the JID node.  The image associated with the syllable BAJ is likely to have an abbreviated structure:

 

(((is-a syllable)) B ~)

 

The tilde is used in an EPAM list to indicate that there are an unknown number of additional subobjects following the initial B.  (In most stimulus-response experiments, the subject does not have to respond with the stimulus, just with the response, and as a result subjects often do not bother to learn more about the stimulus than is necessary in order to discriminate it from other stimuli.).  The image of the episode uniting the stimulus and the response is likely to have the following structure:

 

(((is-a episode)) (((is-a syllable)) B ~) (((is-a syllable)) J I D))

 

Here neither the color nor the second or third letters of BAJ have been memorized.  The image is a copy of the object and has the same structure as the object, but only includes those features of the object that have been memorized.

 

Running EPAM Interactively

 

The first step in order to run EPAM interactively is to initialize the discrimination net. 

 

First turn all printing on by typing the following into the Debug window and then pressing “Enter”:

 

(turn-printing-on)

 

Then initialize an EPAM net by typing the following and then pressing “Enter”:

 

(initialize-variables)

 

Then to see what the discrimination net looks like, type the following and then press “Enter”.

 

(print-net)

 

The discrimination net should look something like this:

 

EPAM NET:

node5049: tests=(is-a) image=(nil)

  Test=is-a:

EPISODES:

 

It consists of just one node which has a test for “is-a”.  Now let’s study  the nonsense syllable “baj” in the discrimination net.  Type the following and then press “Enter”

 

(study ‘(((is-a syllable)) b a j))

 

Then type:

 

(print-net)

 

To see what the discrimination net looks like.  You have just created a subnet for items whose type is "syllable”.

 

Let’s study it again:

 

(study ‘(((is-a syllable)) b a j))

 

(print-net)

 

Now the new subnet has a test for “1” (first position) at the top and a branch for the letter b.

 

Let’s study another syllable, this time jid.

 

(study ‘(((is-a syllable)) j i d))

 

(print-net)

 

You might wonder how much learning time has passed type:

 

*epam-clock*

 

You will see that 16000 ms has passed so far on EPAM’s learning clock

 

Now let’s associate “baj” with “jid”

 

(associate 'episode '(((is-a syllable)) b a j) '(((is-a syllable)) j i d))

 

(print-net)

 

*epam-clock*

 

The resulting net will look something like this:

 

EPAM NET:

node5064: tests=(is-a) image=(nil)

  Test=is-a:syllable-->node5068

     node5068: tests=(1) image=(((is-a syllable)))

       Test=1:j-->node5071 b-->node5070

          node5071: tests=(2) image=(((is-a syllable)) j ~)

            Test=2:i-->node5074

               node5074: ENTRIES: episode5072 image=(((is-a syllable)) j i ~)

          node5070: ENTRIES: episode5072 image=(((is-a syllable)) b ~)

EPISODES:

episode5072 = (((is-a episode)) (((is-a syllable)) b ~) (((is-a syllable)) j i ~) ~)

 

First “jid” was studied again.  Then a new episode, in this case episode5072 was formed in declarative memory and the images of the chunks baj and jid were added to that episode.  There are also pointers from both the junk for baj and the chunk for jid to episode5072.

 

Running Paired-Associate Simulations Interactively

 

The two key routines for running a paired-associate simulation are the study-paired-associate routine and find-associate routine.

 

Let’s start by initializing a new net:

 

(initialize-variables)

 

And start by creating the variables baj, jid, cez, and mun, which will make the objects that they hold more easy to work with.  Type each of the following in the debug window and then press “Enter”:

 

(setf baj (((is-a syllable)) b a j)

 

(setf jid '(((is-a syllable)) j i d))

 

(setf cez '(((is-a syllable)) c e z))

 

(setf mun '(((is-a syllable)) m u n))

 

(turn-printing-on)

 

(print-net)

 

At this point the discrimination net is completely empty:

 

EPAM NET:

node1830: tests=(is-a) image=(nil)

  Test=is-a:

EPISODES:

 

There is just a node1830 at the top which has a test for “is-a”.  If you type:

 

(find-associate ‘episode baj)

 

The response from the system is nil, because there is no response currently associated with baj.

 

The system *clock* is currently = 0 and the *epam-clock* is currently equal to 0, as you can ascertain by typing:

 

*clock*

 

*epam-clock*

 

To initiate the first learning type:

 

(study-paired-association 'episode baj jid)

 

(print-net)

 

The discrimination net is now:

 

EPAM NET:

node1830: tests=(is-a) image=(nil)

  Test=is-a:syllable-->node1855

     node1855: ENTRIES: episode1856 tests=(1) image=(((is-a syllable)))

       Test=1:j-->node1858

          node1858: ENTRIES: episode1856 image=(((is-a syllable)) j ~)

EPISODES:

episode1856 = (((is-a episode)) (((is-a syllable))) (((is-a syllable)) j ~) ~)

 

To find out what the associate to baj is now, type:

 

(find-associate 'episode baj)

 

The result is the syllable j~.  To study that association again, type:

 

(study-paired-association 'episode baj jid)

 

EPAM will respond:

 

Not studying because EPAM is occupied!

EPAM will be occupied until 26000, current time is 0

 

Typing *clock* and *epam-clock* will substantiate what EPAM just reported.  *clock* is now 0 and *epam-clock* is now 26000, which means that EPAM will not be able to learn anything else until 26 seconds have elapsed. So that more learning can take place type:

 

(wait-until-learning-available)

 

(study-paired-association 'episode baj jid)

 

(find-associate ‘episode baj)

 

(print-net)

 

Now the response to the stimulus is the syllable ji~.  By the way, you might wonder what all of the “pseudochunk” messages from the computer are about. EPAM has created “pseudochunks” in its discrimination net for the letters j and i and the word “syllable” so that it could associate entries with those items. You can see those pseudochunks if you type:

 

(print-net *net* t t)

 

Next let’s study the association between cez and mon.

 

(wait-until-learning-available)

 

(study-paired-association 'episode cez mon)

 

(find-associate ‘episode baj)

 

(print-net)

 

At this point the discrimination net points to two episodes.  One with the response m~ and the other with the response ji~

 

EPAM NET:

node1830: tests=(is-a) image=(nil)

  Test=is-a:syllable-->node1855

     node1855: ENTRIES: episode1856 episode1870 tests=(1) image=(((is-a syllable)))

       Test=1:m-->node1871 j-->node1858

          node1871: ENTRIES: episode1870 image=(((is-a syllable)) m ~)

          node1858: ENTRIES: episode1856 image=(((is-a syllable)) j ~)

EPISODES:

episode1870 = (((is-a episode)) (((is-a syllable))) (((is-a syllable)) m ~) ~)

episode1856 = (((is-a episode)) (((is-a syllable))) (((is-a syllable)) j i ~) ~)

 

If you now type:

 

(find-associate 'episode baj)

 

you will find that the current response to baj is “m~” because it is currently the most active of the two entries at the top node of the “syllable” subnet.

 

You can continue studying the associations to baj and cez until both elicit their complete and correct responses.

 

Classification-Learning Simulations

 

Let’s start by creating a discrimination net and by zeroing out the various memory stores:

 

(turn-printing-on)

 

(initialize-variables)

 

(zero-out-variables)

 

Now let’s create some cases to study and define the possible categories, the possible tests, the weights of each of the three possible tests, and the routines that will be used for finding the category.

 

(setf case1 '(((is-a shj) (color black) (shape triangle) (size large))))

 

(setf case2 '(((is-a shj) (color black) (shape square) (size small))))

 

(setf *categories* ‘(#\A #\B))

 

(setf *list-of-possible-tests* ‘(color shape size))

 

(setf *w1* 1.0)

 

(setf *w2* 1.0)

 

(setf *w3* 1.0)

 

(setf *find-category-routine* ‘find-category-in-standard-condition)

 

In this particular simulation the category to be learned is that the color black predicts category A.  First we will find what category the system will guess will be associated with case1.

 

(find-subject-response case1)

 

EPAM guesses category A or Category B

 

(wait-until-learning-available)

 

(study-in-standard-condition case1 #\A nil)

 

(put-copy-of-object-and-category-in-vis case1 #\A)

 

(print-store ‘visual ‘imagery)

 

Now the visual imagery store has the following contents:

 

PAD: response->(((is-a visual)) A ~) stimulus->(((is-a shj) (color black) (shape triangle) (size large)))

 

Now if we study case2 with the same category, EPAM will create an hypothesis.

 

(wait-until-learning-available)

 

(study-in-standard-condition case2 #\A t)

 

By the way, the “t” or “nil” at the end of the study-in-standard-condition command indicates whether the system made an error when it classified this stimulus. The hypothesis now appears in the visual imagery-store with the confidence “possible”:

 

PAD: stimulus->(((is-a shj) (color black) (confidence possible))) response->(((is-a visual)) A ~)

 

Now repetitions of

 

(wait-until-learning-available)

 

(study-in-standard-condition case2 #\A nil)

 

(print-pad)

 

will cause the confidence in the hypothesis to rise from “possible” to “likely” to “very-likely” and then the hypothesis will be studied.

 

Adding a Simple Test to the Discrimination Net

 

In the classification learning simulations, a strategy determines which nets are added to the discrimination net.  Here are the commands actually used to create a simple test and branch.  First, create an object to be studied:

 

(turn-printing-on)

 

(initialize-variables)

 

 (setf object '(((is-a shj) (eh 1) (mh 1))))

 

In order to create a subnet for objects with is-a = shj, study the object:

 

(study object)

 

In order to add the test mh and branch using that test:

 

(study object ‘mh)

 

In order to associate the object created with Category B:

 

(associate ‘category object #\B)

 

(print-net)

 

Creating Discrimination Nets where you Control Tests that are Added

 

In the classification learning simulations, sometimes EPAM adds a compound test and value to the discrimination net.  It needs to chunk the compound value before it can do so.  Here is a sequence of commands for adding a compound test (eh mh) and the values of that test: (1 1) to the discrimination net. First, create an object to be studied:

 

(turn-printing-on)

 

(initialize-variables)

 

 (setf object '(((is-a shj) (eh 1) (mh 1))))

 

In order to create a subnet for objects with is-a = shj, study the object:

 

(study object)

 

The first test that we will add in the discrimination net will be a test for eye-height (eh) and mouth-height (mh).  We’ll hold this test in the variable test with the following command:

 

(setf test ‘(eh mh))

 

To find out what the value of the test would be on the object, type:

 

(test-value-finder object test)

 

The response from the computer is: (((is-a compound-value)) 1 1)

 

In order to add this value to the discrimination net, we first of all have to study it fully by typing in (study value) several times:

 

(study value)

 

(study value)

 

(study value)

 

(study value)

 

(print-net)

 

EPAM NET:

node1851: tests=(is-a) image=(nil)

  Test=is-a:compound-value-->node1861 shj-->node1856

     node1861: tests=(1) image=(((is-a compound-value)))

       Test=1:1-->node1863

          node1863: tests=(2) image=(((is-a compound-value)) 1 ~)

            Test=2:1-->node1865

               node1865: tests=(length) image=(((is-a compound-value)) 1 1 ~)

                 Test=length:2-->node1867

                    node1867:image=(((is-a compound-value)) 1 1)

     node1856:image=(((is-a shj)))

EPISODES:

 

(study object test)

 

(associate 'category object #\A)

 

(print-net)

 

The result is the following discrimination net which sorts the object to node1869 using a recursive sorting process:

 

EPAM NET:

node1851: tests=(is-a) image=(nil)

  Test=is-a:compound-value-->node1861 shj-->node1856

     node1861: tests=(1) image=(((is-a compound-value)))

       Test=1:1-->node1863

          node1863: tests=(2) image=(((is-a compound-value)) 1 ~)

            Test=2:1-->node1865

               node1865: tests=(length) image=(((is-a compound-value)) 1 1 ~)

                 Test=length:2-->node1867

                    node1867:image=(((is-a compound-value)) 1 1)

     node1856: tests=((eh mh)) image=(((is-a shj)))

       Test=(eh mh):node1867[(((is-a compound-value)) 1 1)]-->node1869

          node1869: ENTRIES: episode1873 image=(((is-a shj) (eh 1) (mh 1)))

EPISODES:

 

 

Report bugs or problems

 

If you have encounter any bugs or problems, or just have some questions with running EPAM, please do not hesitate to e-mail me (howard@pahomeschoolers.com).  I will do my best to answer your questions.

 

Also, do keep track of whether this file has changed.  If a new date appears at the top, there may be a later version available which fixes the problems that you have encountered.

 

Howard Richman

howard@pahomeschoolers.com