

         Documentation for the PRODIGY Version 2.0 EBL Module

This document describes how to use PRODIGY's EBL module. The early
sections describe how to use the system with one of our predefined
domains. The later sections discuss the capabilities of the system in
more detail, and should be closely read by anyone who intends to use
the module with other domains.

Prodigy's EBL (Explanation-based learning) module is experimental code
for learning search control rules from experience. The system is not to
be used for commercial purposes. References include:

 Minton, S.  "Learning Search Control Knowledge: An Explanation-Based
    Approach", 1988, Kluwer Publishing Co.  (My Ph.D.  thesis, also available
    as a Tech Report from CMU.)

 Minton, S.  "Empirical Results Concerning the Utility of Explanation-Based
     Learning", AAAI Proceedings, 1988.

 Minton, S. and Carbonell, J.G.  "Strategies for Learning Search Control
     Rules: An Explanation-Based Approach", IJCAI Proceedings, 1987.

....as well as a number of earlier articles (see references section in
any of the above).

The EBL module must be used in conjunction with the PRODIGY planner,
described in the PRODIGY version2 manual, which is available from CMU
as technical report CMU-CS-89-146.

The code here is a bit different than the code described in my thesis,
but the differences are minor.  For one thing, the code was originally
written in franzlisp, and only later translated to commonlisp (which
explains several weird things, such as why we don't use packages).
Also, I have made an attempt to make things a bit more usable, but see
the DISCLAIMER at the end.

1. INSTALLING THE EBL MODULE.

All of the code for the EBL module is in the directory
prodigy/version2/system/ebl. (That's were this manual is also
located.)  When installing the code on your machine, all you need to
do is to check the file startup.lisp in this directory and make sure
that it sets the global *EBL-PATH* to the right directory (the correct
name is often system dependent).

You should compile all the files loaded by startup.lisp. Otherwise,
the system will be very (very) slow. Note that it helps to have the
planner already loaded into Lisp when you compile the files.
(You can load the file "compile-ebl-files.lisp" which will automatically
compile the files for you.  If you want to compile just one file and you
haven't loaded the system you must load setpath.lisp, then you can use
compile-file to compile the file.)

2.  USING THE EBL MODULE.

To run the system, first you must enter Lisp, and load the planner
(see the PRODIGY 2.0 manual for details).  The EBL module can then be
loaded simply by loading the file "startup" in the ebl directory.
Then you load the domain.  It is not strictly necessary to do things
in this order, but recommended.  It is also recommended that you do
not change domains without starting all over again (with a fresh Lisp,
etc).  The code is robust, but occasionally bugs pop up, and it's best
to be conservative.

The learning code can be invoked either from Lisp, or from the PRODIGY
interface.  In the latter case, you type the command "(prodigy)" to
Lisp to enter the interface (see the PRODIGY manual).  Set the path
and the domain and load a problem.  At this point you may use the
command "toggle-ebl" to toggle the EBL learning on or off.  Then
type "run" to run the problem.  The system will automatically run the
EBL module if the EBL flag is activated.

To use the learning code directly from Lisp, you must first load a
problem (i.e., a file containing a goal and start-state) as described
in the PRODIGY manual.  Then you can use the function "(toggle-ebl)"
to turn the EBL module on and off.  If you then type "(run)" the
system will run through the problem, invoking the EBL module if it is
active.

Here is a list of the top level functions, described using standard lisp
notation.  The same command can be given directly to the Prodigy interface,
as well as to the lisp top-level

Lisp			Description
----			-----------
(toggle-ebl)		Turns EBL learning On and Off.

(forget-rules &rest)	REST may be 'ALL, a number, or any number of rule
			names.  If all, forget all learned rules.  If a number,
			forgets last N learn rules.  If names, forgets 
                        each named learned rule.

(show-rules)		Will show active rules.

(write-rules "file")	Will write active rules out to a file.  Does not
			forget the rules upon completion.  Assigns new names
			to the rules as they are stored.

(read-rules "file")	Will read rules from the file given.  

(toggle-ebl-text)	Turns on and off output-printing by the EBL module.

To control the target concepts that are used by the system, the user can
change the file "tc-specs", which contain the various target concept
specifications. To turn a target concept off, simply change the active
slot in the target concept specification from "yes" to "no", and re-load
the file. (See the section of this document entitled "Global variables"
for other ways to control the EBL system.)


3. SYSTEM OUTPUT

When the EBL subsystem is invoked after problem-solving, it first
checks the tree for goal-interactions. As described in my thesis,
the EBL system may have to re-invoke the problem solver to check
whether the interaction necessarily followed from a particular decision.
You will see the msg "


After this phase is completed, the EBL system will examine the nodes
in the search tree in postorder. As it examines each node, you will
see the msg "EBS Processing Node: N". When the system decides that there
is something worth explaining, it will first generate an initial result,
then simplify it using a set of domain independent transformations, then
further simplify it using a simple theorem prover. At every node, for
each target concept/training example pair, the EBL module will print
these results as it generates them. (The further-simplified result will
only be printed if it is different from the simplified result).

If a result is estimated to be useful, a new learned rule will be created.
the system will tell you the name of the rule as it is created.
At the end the run, the new learned rules will be automatically
added to the system. During subsequent problem solving, the system will
evaluate each learned rule's utility, and deactivate (i.e. forget)
the rule if it does not appear useful (although see HINTS section 
for potential problems with timing mechanisms), as long as the EBL module 
is activated. If you want to turn off the learning process, but keep 
utility evaluation on, then simply turn off all the target concepts (see 
previous section).

4. GLOBAL VARIABLES

There are a number of global variables used within the EBL module.
These are initialized in all but one case in the EBL "startup" file.
You can change them if you like, in order to alter the system's behavior.

SYSTEM VARIABLES:

*EBL-PATH*
	This is used as a pointer to the location of the files in the
	EBL module.

*EBL-FLAG*
	This flag is very important.  It switches important code on and
	off within the Prodigy planner.  Certain code within the planner
	must run slightly differently so that the EBL module can operate 
        correctly.  (See the section on HINTS.) This flag 
        must always be true once the learning module has been loaded. 
	(cf. *ACTIVATE-EBL*, to turn off learning temporarily).

*ACTIVATE-EBL*
	This flag can be toggled from Lisp (using "(toggle-ebl)") or from
	Prodigy User Interface (using "toggle-ebl").  When a domain and
	problem are loaded and RUN, it will determine whether the EBL
	module will learn or not. Normally set to T during training phase.

*STOP-ON-WARNING*
	The EBL module will check to see if the rules that it has
	learned are obviously incorrect (i.e., they don't match
        the state from which they were learned). When this flag 
        is T it will stop and ask you whether you want to
	flush the offending result and continue, or break. When set to NIL,
        it will simply flush and continue. Normally set to nil.
       
*TP-FNS*
	This contains the names of Theorem Prover Functions used by users
	in simplification rules.  The functions are stored in the form of
	an ASSOC list, with the function names and the number of variables
	they take + 1.  See 'startup.lisp' for an example. Most users 
        shouldn't have to touch this.


*EXPAND-ALL*
	When set to T the planner will expand all of the nodes in the 
        search tree before learning. (Normally the planner stops after
        finding the first solution). This is initialized to NIL, but
        I recommend you set it to T for the first few training problems 
        in a domain. You'll get better learned rules this way, since
        the system will quickly learn by exploring "stupid mistakes".
        See my thesis for more on this.

*NUM-RUNS*
	This is used to give rules created within the EBL system unique
	names.  It is incremented every time the learning system is
	activated on a new RUN.

*LEARNED-RULES-IN-SYS*
	This is a list of the currently active rules that were learned
	by the system.  Rules that were discarded during utility evaluation
 	are removed from this list.

*LEARNED-RULES*
	This is a list of all of the rules learned by the system, since
	the learning was activated (or the last occurrance of (forget-rules).


VARIABLES FOR CONTROLLING LEARNING:

*EBL-PRINTING*
	The EBL module displays a lot of information while it is
	running.  When set to NIL, most of this information is inhibited
	from being displayed. Initialized to T. We recommend leaving
        it on, so you get an idea of what the learner is doing.

*MAX-NODES-TO-ADD*
	This limits the number of nodes that the system will expand to
	verify an interaction. Set it to a small number if you get
        tired of waiting, set it to a large number if want to maximize
        the system's chances of successfully learning from interactions.

*MAX-EXP-SIZE*
	This is the maximum number of atomic variables allowed within a
	learned expression.  If this number is exceeded, the expression is
	discarded and a warning is printed:
		"Eliminating horrible result from consideration!"

*MACRO-LEARNING*
	This flag is currently inactive.  It was used in the past when
	learning macro-operators. See the Franz Lisp version of PRODIGY
        if you want to play with this. (Or bug me to convert the code...)


SYSTEM DEPENDENT VARIABLES FOR CONTROLLING TIMING:

*TRIM-FACTOR*
	A rule must produce a savings of greater than the number of CPU
	seconds this is set to be considered useful enough to be learned.

*TP-TIME-BOUND*
	This determines the time bound for simplification by the
	Theorem Prover.

*MIN-MATCH-TIME*
        Some systems may not have accurate enough timing mechanisms for
        PRODIGY's utility evaluation. In particular, the system may simply
        report the match time for a learned search-control rule to be 0
        when the rule is matched during problem solving. If the user sets 
        *MIN-MATCH-TIME* to a value greater than zero, than the match time 
        of a rule will be at least *MIN-MATCH-TIME* every time PRODIGY
        attempts to match the rule. (If the system tries a rule 5 times
        during a problem-solving run, then its match cost will be 
        at least 5 times *MIN-MATCH-TIME*.) Note that the user should
        set *MIN-MATCH-TIME* in the same units as is returned by
        the commonlisp function (get-internal-run-time), not in CPU seconds.
        
PLANNER CONTROL: The following variables, which are set in the planner 
directory (in the file ini.lisp) are also useful when running with system 
with EBL turned on.

*PRODIGY-TIME-BOUND* 
        The maximum amount of time (in CPU seconds) the planner 
        will be allowed to run on a problem. 

*NODE-CUTOFF*
        When the planner reaches this node, search will be cut off. E.g.
        if *NODE-CUTOFF* is set to 'n25, the planner will halt upon reaching
        that node.

*SCR-TRACING*
        Used to control tracing of search control rules. See the PRODIGY 2.0
        manual.




5. CREATING AND RUNNING PROBLEM SETS

When running the Explanation Based Learning module (EBL) for PRODIGY
it is helpful to give a set of problems which it can solve and learn
rather than manually feeding it one problem at a time.  A system of
functions was written that has the facility to create, store and run
sets of test problems for three of the domains: Blocksworld,
Extended-Stripsworld, and Scheduling World (a machine-shop domain).
You can find descriptions of these domains in the README file
in each domain (or in my thesis).

To create a new problem set, call the Lisp function CREATE-PROBSET
with the appropriate world-type ('bw 'strips 'sched).  The function
will prompt the user for data that is needed to create a problem in
that particular world.  After the problem is created, it can be run.
Next, the problem may be rejected by the user or temporarily stored
with the other problems, after which new data for the next problem is
prompted.  This cycle continues, until stopped.  Finally, the set of
newly created problems may be stored in a file (filename is asked from
the user).

CREATE-PROBSET also takes a key, :SEED, which is normally set to T.
This variable, seed, determines whether the random function generator
is seeded or not (refer to Common Lisp Manual, Random Numbers,
RANDOM).  T will seed the generator, NIL will prevent it from being
seeded.  In this way, (assuming the global *RANDOM-STATE* is saved)
problem sets can be re-created, if SEED is NIL.

CREATE-PROBSET will not work correctly unless PRODIGY, the EBL module
and the appropriate domain have been loaded into Lisp.

Problems are stored in the list *TEST-PROBS*.  Each element of this
list contains a problem name, a goal expression and a start state.
For an example, check the problem sets included in each of the domains
mentioned previously).  The functions RUN-ALL, LOAD-NEXT, and GETPROB
(which are described below) destroy the global variable *TEST-PROBS*,
so it may be wise to save the problem set to a file when using it.

RUN-ALL will take a set of problems in *TEST-PROBS*, load each
problem, RUN the problem, and continue until the end of the set.  It
will destroy *TEST-PROBS*.  Note that it will LEARN new rules for the
problem sets only when the EBL module is active (toggle-ebl was used
to turn learning on).

LOAD-NEXT will pop the next problem in *TEST-PROBS* and load it into
the EBL system so that it is ready to be RUN.  It destroys
*TEST-PROBS*.

GETPROB takes the name of a problem, will search the list *TEST-PROBS*
for that problem and then use LOAD-NEXT to prepare it.  It destroys
*TEST-PROBS*.

The global variable *AUX-COMMANDS* can also be used with *TEST-PROBS*.
*AUX-COMMANDS* is a list of pairs, where each pair consists of a
problem name and a lisp statement. After solving a named problem,
PRODIGY will execute the associated lisp statement, and then invoke
learning.  This can be useful for turning flags on and off, etc.

Here is an example run:

 [At this point both PRODIGY 2.0 and the EBL module have been loaded]

 > (load "~prodigy/domains/ebl.domains/bw/startup") .  .  .
 #P"/home/copernicus/prodigy/domains/ebl.domains/bw/startup.lisp" >
 (create-probset 'bw)
 Enter the maximum number of blocks: 5
 Enter the maximum number of goals: 2

 Problem Name: BW-1 Goal State: (CLEAR A) Start State:

 ((OBJECT A)
  (HOLDING A)
  (OBJECT C)
  (ON-TABLE C)
  (CLEAR C)
  (OBJECT B)
  (ON-TABLE B)
  (CLEAR B)) 
 Do you wish to see a run of this problem? (Y or N): n 
 Do you wish to keep this problem? (Y or N): y
 1 problem accumulated 
 Do you wish to continue? (Y or N): n 
 Do you wish to save this set to a file?  (Yes or No) yes

 Please enter a filename in which to store the problem set: bw/probsets/ps0
 ...Data stored 
 T

 > (load "bw/probsets/ps0")
 ;;; Loading source file "bw/probsets/ps0.lisp" #P"bw/probsets/ps0.lisp"
 
 > (run-all)

 Goal State: (CLEAR A)
 OBSERVER reset

 Number of rules learned: 0 Number of learned rules still in: 0
 PROBLEM: BW-1

 * * * * * P R O D I G Y 2.0 * * * * *

  Goal State: (CLEAR A)
  Start State: (OBJECT A)
               (HOLDING A)
               (OBJECT C)
               (ON-TABLE C)
               (CLEAR C)
               (OBJECT B)
               (ON-TABLE B)
               (CLEAR B)

 N1 (DONE) Alts: *FINISH*

   N2 (CLEAR A)
   Alts: PUT-DOWN .  .  .




6.  RESTRICTIONS ON DOMAINS

   Unfortunately, the EBL module can't handle all legal PRODIGY
domains.  We list the restrictions required by the EBL module below.
Most of these restrictions are minor:

A) Negated existentials cannot be used (in the preconditions of operators
   or inference rules).  That is, a precondition like:
            (~ (EXISTS (<x>) (ON-TABLE <x>)))
   ...is forbidden.  Note that you can't get away from this restriction
   by simply changing the above condition to:
            (~ (ON-TABLE <x>))
   ...if this precondition is not preceded by another precondition that
   generates <x>, since this would not even be a legal prodigy expression.
   Of course, if a generator is included, then both the planner and the
   EBL module will be happy.  Thus, the following is fine:
            (AND (OBJECT <x>)
                 ...
                 (~ (ON-TABLE <x>))) 

B) Generators cannot be used in the middle of disjunctions.  Thus, the
   following precondition is illegal, assuming that SQUARE and CIRCLE are
   the generators for <x>.
            (AND (OR (SQUARE <x>)
                     (CIRCLE <x>))
                 (ON-TABLE <x>)) 

C) Conditional effects (i.e.  using IF in an add or delete) is disallowed.
   Wildcard variables, however, are fine. Thus, you can have a MOVE operator
   in the stripsworld that deletes all the formulas that match
   (NEXT ROBOT <x>), since <x> is a wildcard variable; however,
   you can't have MOVE delete only those next-to relations where <x> is
   not being carried by the robot, since this would require a conditional.
   (See the PRODIGY manual if you are not clear on conditionals and wildcards).

D) You cannot use any user-defined NODE-SELECT, NODE-PREFERENCE,
   or BINDINGS-SELECT control rules. You should only use operator
   selection rules if you are sure that only one operator will be selected
   at a time. Also, you MUST use the same default
   control rule for selecting goals that is defined in the blocksworld,
   stripsworld, and scheduling domains. (It is also in the file
   default-control-rule.lisp for your convenience.) This rule causes
   PRODIGY to try different orderings of top-level goals,
   but not lower-level goals (for these it will rely on the precondition
   orderings of the operators). This is normally the way we run prodigy;
   the system is relatively efficient this way, and it can still explore
   some interesting goal ordering problems. You cannot add your own goal 
   selection rules, since the learner expects to see only the
   expected goal-selection rule.
   (Note: the meta-functionn "primary-candidate-goal" works slightly 
   differently when the EBL module is loaded.  Specifically, there is
   no primary-candidate-goal at top-level nodes. Thus, at top-level
   nodes, you must use the meta-function "candidate-goal" instead.)

E) Negated and subgoals goals are not allowed. Therefore, once the 
   EBL module is loaded, backchaining on negated goals is
   disabled. I.e., if PRODIGY is given the goal (~ (INROOM ROBOT RM1))
   in the STRIPS world, the planner will not be able to solve
   the problem, even though normally (without the EBL module loaded)
   this problem could be solved. The system will attempt to warn
   the user if it believes such problems could arise.


Basically, these restrictions are necessary because I was too lazy to
put in the code so that version2 deals correctly with these cases.
There is no deep technical reason.  (Note, however, that the EBL code
is quite complex, so extending the code to handle these cases would be
non-trivial).

The EBL system will warn you if you violate any of these restrictions.
For its own purposes, the system will also rename variables in your 
operators, inference rules, or simplification rules if you use the same 
variable name in two or more places.  This shouldn't matter to you, 
but in any event, it will tell you when it does this.


7.  OTHER HINTS.

   In addition to the restrictions described previously, there are
several other points worth noting.  First, you should definitely try
to use static generators.  It's even more important for the EBL module
than it is with the planning module (see the manual), since it makes
it easier for the EBL module to reason about the planner's behavior.
You will encounter fewer bugs, as well.  

   Secondly, try to move static conditions close to the front 
of precondition expressions (in operators and inference rules).  
For technical reasons, the EBL module disables the "static 
predicate check" that the planner does before it subgoals.  
Thus, if you don't move static predicates to the front, the
planner could behave fairly inefficiently, subgoaling the first
precondition of an operator even though the second precondition cannot
be achieved.
  
  In general, try not to use generators that may be false (i.e., they
may not generate any values at all). This sometimes cannot be avoided.
For example, if the condition (is-object <obj>) is used to generate objects
and there are problems where there are no objects in the world, the EBL
module may have difficulties. Hopefully not.

  As mentioned previously, try not to change domains in the middle of
a session.  Doing so will increase the likelihood that the system will
become confused.

  In this version of the code, incremental learning (i.e. interleaving
learning and problem-solving) and macro-operator learning are
disabled.  If I have a chance (and people bug me enough) I'll put them
back in.

Unfortunately, Commonlisp does not provide much in the way of 
machine-independent timing functions, so things like
garbage-collect time are more-or-less ignored and will occasionally 
screw things up on some machines. Furthermore, some machines will not 
report very accurate match-times. (But see *MIN-MATCH-TIME* global 
variable described below for one way around this.) For these reasons, 
utility evaluation in this version of the system does not seem to work 
as accurately as in the old CMUlisp (franzlisp) version.  This 
exacerbates the problems with the utility evaluation mentioned in 
my thesis, however, it still seems to produce fairly reasonable 
behavior in many cases. Often, gross estimates of utility are sufficient.


8.  SIMPLIFICATION RULES
 
  In addition to the usual list of operators and inference rule
necessary for the planner to run, the EBL subsystem requires
additional domain-specific information necessary for simplifying
learned rules.  For the most part, this information is required
because the operators and inference rules do not completely specify
the domain; what is missing is a characterization of the legal initial
states.  For example, it is not possible to determine from the
blocksworld operators that a block cannot have two blocks on top of
it.  In fact, if such an initial state were presented to PRODIGY, the
planner would quite happy to solve the problem, even though it
violates our normal conception of the blocks world.  The
simplification knowledge that I used in my experiments with PRODIGY
was quite simple (and quite useful) -- most of it could probably be
learned very quickly using inductive learning, eliminating the need
for the user to add this information himself.  (Any volunteers to
implement this?)

      To make it easy to enter the requisite knowledge, I have set
things up as follows.  Each domain that will be used for
EBL should have in its directory a file called ebl-axioms.lisp,
in addition to the usual STARTUP file, DOMAIN file
(containing the operators and inference rules) and the FUNCTIONS file.
This file should set the following four global variables, 
as described below.  (For the most part, you can understand what
to do if you read this section, and take a look at the
ebl-axioms files for the sample domains that come with PRODIGY.)
It is OK to set all four of these globals to NIL, in which case PRODIGY's
learning will probably not do as well as it might. *SINGLE-GENERATORS*
is particularly important, so you should at least try to use that one.


A) *SINGLE-GENERATORS* provides a way of specifying which arguments to
  a predicate that can only take on a single value at any time
  (once all other arguments are bound).  For example
  in the blocksworld, only one block can be held at any time.
  To show the format of this information, the following line
  is taken from the ebl-axioms file in the blocksworld:

   (setq *SINGLE-GENERATORS* '((holding nil)(on nil t)(on t nil)))

  The first entry, (holding nil), means that only one block can be held
  at a time.  That is, if first argument to HELD is unbound, then it will
  generate at most one value. The second entry, (on nil t), means that
  there can be only one block on another block.  For example, the variable
  <x> in (on <x> BLOCKA) will match at most one other block. Similarly,
  the third entry, (on t nil), means that there can be at most
  one block that a block can be on.  E.g., <x> in (on BLOCKA <x>) can
  match at most one block.  The order of the entries is immaterial (I.e.,
  it doesn't matter than HOLDING listed before ON, etc.).

    The STRIPS robot world also provides some good examples of single
  generators.  The following is taken from the ebl-axioms file in the 
Extended-Strips domain:

  (setq *SINGLE-GENERATORS*
    '((holding nil) ; The robot can be holding at most one object.
      (is-key t nil) ; A key opens a single door, e.g.  (is-key key1 door1)
      (inroom t nil) ; An object is an a single room at any time
                       ; e.g.  (inroom robot rm1)
      (connects t nil t) ; A dr connects to a single other room.
      (connects t t nil))) ; A dr connects from a single other room.
                           ; Eg. (connects door1 room1 room2)


  *SINGLE-GENERATORS* provides a simple, built-in way of specifying 
  information   that the simplifier can take great advantage of.  If we were 
  to specify the same thing in logic, we would use statements of the form:

  Forall <x>,<y>,<z> ((ON <x> <y>) and (ON <x> <z>))
                      implies (IS-EQUAL <z> <y>)


B) *AT-LEAST-ONE-GENERATOR* is very similar to the above, but instead
   of specifying that an argument can only take on a single value, it
   specifies that an argument must take on at least one value (if
   all other arguments have been bound).  In the blockworlds,
   there is only one relevant statement, that is, that there
   is always at least one object (i.e.  block) in the world, which is
   specified as below:

   (setq *AT-LEAST-ONE-GENERATORS* '((object nil)))

  To illustrate the format of this information, a better example is
  the STRIPS robot world.  The following line is taken from the
  ebl-axioms file in the STRIPS domain directory:

  (setq *AT-LEAST-ONE-GENERATORS*
      '((is-object nil)
        (dr-to-rm t nil)
	(dr-to-rm nil t)
	(connects t t nil)
	(connects t nil t)
	(inroom t nil)))

  This first entry states that there is at least one object in the world.
  The second entry, (dr-to-rm t nil), indicates that every door is the
  door to a room, i.e.  (dr-to-room Door1 <x>) will match at least one
  room.  (We assume Door1 is a door -- see next paragraph).
  Similarly, (dr-to-rm nil t) indicates that every room
  has AT LEAST ONE door.  The next two entries indicate
  that if there is a door from a room, then there is a room
  it connects to, and if there is a door to a room, there is a door it
  connects from.  Finally, every object is in at least one room.
  
  In general, unless you are trying to maximize the performance of the
  learning system, it is a good idea to restrict your entries to
  predicates with one variable (such as OBJECT). I've found that
  people are often careless and put in entries that aren't always
  guaranteed to be true...

C) *EVALUABLE-DOMAN-FNS* is only used for domains that have functions
  (used to implement static predicates), such as in the machine-shop
  scheduling world. These functions, such as LESS-THAN, are defined in the
  functions.lisp file.  (See the PRODIGY manual for details on how to
  define and use such functions).  Typically, functions are designed to be
  generators, so that if you evaluate, for example, (LESS-THAN <x> 7), the
  function LESS-THAN will generate the values 1 to 6, which will then
  be candidate bindings for <x>.  Since functions can be embedded in learned
  search control rules, the EBL system needs to know the circumstances under
  which these functions can be evaluated, so that it can order the
  preconditions of the learned search control rules.  So, for example,
  it may be possible to evaluate LESS-THAN if its first argument is
  unbound, but not if its second argument is unbound.  Here is how you would
  say that:

  (setq *EVALUABLE-DOMAIN-FNS* '((less-than nil t)))
  
  The following line illustrates some further examples:
    
  (setq *EVALUABLE-DOMAIN-FNS*
     '((is-time-period nil)
       (between nil t t)
       (adjacent nil nil)))

  The first entry says that IS-TIME-PERIOD is a function with one argument
  which can generate values for the argument.  The second entry
  says that the function BETWEEN, of three arguments, can only generate
  values for the first argument.  (I.e., it can only be called
  with all arguments bound, or the last two arguments bound). Finally,
  the function adjacent can be called with both arguments unbound.
  It will generate all possible pairs of values.

D) *SIMPLIFICATION-RULES* lists a set of arbitrary proof rules that
   are used by a theorem prover in the last phase of the
   simplification process. The rules take the form:

(rule-name
  (p-exp <pdl-expression>)
  (q-exp <pdl-expression>)
  (prove-cond <pdl-expression>)
  (known-cond <pdl-expression>))
  
The purpose of this format is discussed in my thesis.  Basically the
idea is that the theorem prover will replace the P-EXP by the Q-EXP
if it can show that KNOWN-COND and PROVE-COND both hold.  The prover
is restricted, however, in that KNOWN-COND must be shown to be true
without using any additional proof rules.  The theorem prover can
use additional simplification rules to show that PROVE-COND holds.
In general, it is a good idea to use these rules sparingly, since the
learning system can usually do a good job without them.

As an example, here is a rule from the blocksworld which states
that if the prover can show that (holding <r4>) is true,
then it can replace (~ (clear <r4>)) with true:

 (rule4 
  (p-exp (~ (clear <r4>)))
  (q-exp t)
  (prove-cond t)
  (known-cond (holding <r4>)))

  In standard logic, such rules would be written as:
     forall <x> <y>....(and Known-cond Prove-cond)
                       implies (p-exp iff q-exp)

  This facility is a very powerful one, but must be used with care.
To ensure that the simplification process runs in a reasonable time, 
the user can set various flags (such as a time-limit), as described
in the interface section below.

  The blocksworld ebl-axioms file contains a short, but useful set of
examples.  Note that quantified variables (other than the obvious universals)
must be handled explicitly.  Some useful meta-level functions 
that can be used within the KNOWN-COND are described below for adventurous
users:
  (f-outside-scope <var1> <var2>) 
       is true if <var1> is universally quantified over some type, and
       <var2> is defined outside the scope of var1.
  (complete-univ-quantified-var <var> <type>) 
       is true if <var> is a universally quantified variable which
       MUST range over all values of type <type>, I.e. there is no
       disjunction between the quantifier and the condition.
  (only-single-mention <var>)
       is true if variable <var> is not mentioned elsewhere in the 
       expression being simplified.


 
9.  DISCLAIMER

Please keep in mind that EBL subsystem is EXPERIMENTAL code, produced
in the course of a research project. It was never intended 
to be widely used or particularly robust.  It was written to help
explore and test the ideas that underlie explanation-based
learning (and in fact, the original work on this code in 1985 actually 
predates this term).  Parts of the system have been rewritten on 
several occasions, and it was translated to COMMONLISP only after it was 
completed in 1987. (It predates commonlisp too.) If you want to look at 
the code itself, be my guest, but don't say I didn't warn you...some of
it is pretty horrible.

Amazingly, at this point the system is reasonably robust, and using it 
WILL give you you a feel for how well the learning works, and what the
tradeoffs are.  That's why you should be reading this.  I would encourage 
you to give it a try!



10) ACKNOWLEDGEMENTS

Thanks to Jaime Carbonell, Craig Knoblock and Dan Kuokka with their advice
on designing and implementing the EBL module. Thanks to Andy Philips for
helping maintain and rewrite parts of the EBL module. Thanks to the 
PRODIGY group at CMU for their help in designing, implementing, 
maintaining and documenting the PRODIGY system (Jaime, Craig, Dan, Yolanda 
Gil, Manuela Veloso, Robert Joseph, Alicia Perez, Oren Etzioni, Henrik 
Nordin, Ellen Riloff, Mike Miller, Dan Kahn, Santiago Rementaria, 
Hiroshi Tsuji).

                                        -- Steve Minton
                                           NASA Ames Research Center
                                           Moffett Field, CA, 94035
                                           (Minton@pluto.arc.nasa.gov
                                            or Minton@cs.cmu.edu)





