about summary refs log tree commit diff stats
path: root/js/games/nluqo.github.io/~bh/logic.html
diff options
context:
space:
mode:
authorelioat <elioat@tilde.institute>2023-08-23 07:52:19 -0400
committerelioat <elioat@tilde.institute>2023-08-23 07:52:19 -0400
commit562a9a52d599d9a05f871404050968a5fd282640 (patch)
tree7d3305c1252c043bfe246ccc7deff0056aa6b5ab /js/games/nluqo.github.io/~bh/logic.html
parent5d012c6c011a9dedf7d0a098e456206244eb5a0f (diff)
downloadtour-562a9a52d599d9a05f871404050968a5fd282640.tar.gz
*
Diffstat (limited to 'js/games/nluqo.github.io/~bh/logic.html')
-rw-r--r--js/games/nluqo.github.io/~bh/logic.html703
1 files changed, 703 insertions, 0 deletions
diff --git a/js/games/nluqo.github.io/~bh/logic.html b/js/games/nluqo.github.io/~bh/logic.html
new file mode 100644
index 0000000..2f762c4
--- /dev/null
+++ b/js/games/nluqo.github.io/~bh/logic.html
@@ -0,0 +1,703 @@
+<HTML>
+<HEAD>
+<TITLE>Reasoning with Computers</TITLE>
+</HEAD>
+<BODY>
+<H1>Reasoning with Computers</H1>
+
+<CITE>Brian Harvey<BR>University of California, Berkeley</CITE>
+
+<P>``Intelligent agents'' are said to be right around the corner; some products
+are already available.  These programs are supposed to watch you work, make
+inferences about your preferred style, and automate repetitive tasks.  They
+will sift through all the nonsense on the World Wide Web and find only those
+items you'll really want to read.  They'll be teammates or opponents in
+computer games.
+
+<P>How can computer programs make inferences?  I chose logic puzzles as a
+testbed for experimentation.  Logic puzzles are a relatively easy test case
+because each puzzle forms a ``closed world''; we know in advance all the
+possible names, ages, house colors, or whatever characteristics the puzzle
+asks us to match up.  There is no new computer science here.  I am more or
+less recapitulating the early history of computer inference systems.  But
+educationally that may be more helpful than the complexities of the most
+modern attempts.
+
+<H2>An Inference System for One Logic Puzzle</H2>
+
+<P>I first worked on this project when I wrote the third volume of <I>Computer
+Science Logo Style</I> (MIT Press, 1987).  In that volume the task I set for
+myself was to introduce some of the topics in the undergraduate computer
+science curriculum to a younger audience, and to illustrate the ideas with
+Logo programs rather than with formal proofs.  I wanted to discuss logic as
+part of discrete mathematics, and thought of logic puzzles as the task for
+an illustrative Logo program.
+
+<P>The program I wrote solved only one logic puzzle, taken from <I>Mind
+Benders</I> Book B-2, by Anita Harnadek (Critical Thinking Press, 1978):
+
+<BLOCKQUOTE>
+<P>A cub reporter interviewed four people.  He was very careless, however.
+Each statement he wrote was half right and half wrong.  He went back and
+interviewed the people again.  And again, each statement he wrote was
+half right and half wrong.  From the information below, can you
+straighten out the mess?
+
+<P>The first names were Jane, Larry, Opal, and Perry.  The last names were
+Irving, King, Mendle, and Nathan.  The ages were 32, 38, 45, and 55.  The
+occupations were drafter, pilot, police sergeant, and test car driver.
+
+<P>On the first interview, he wrote these statements, one from each person:
+
+<UL>
+<LI>1. Jane: ``My name is Irving, and I'm 45.''
+<LI>2. King: ``I'm Perry and I drive test cars.''
+<LI>3. Larry: ``I'm a police sergeant and I'm 45.''
+<LI>4. Nathan: ``I'm a drafter, and I'm 38.''
+</UL>
+
+<P>On the second interview, he wrote these statements, one from each person:
+
+<UL>
+<LI>5. Mendle: ``I'm a pilot, and my name is Larry.''
+<LI>6. Jane: ``I'm a pilot, and I'm 45.''
+<LI>7. Opal: ``I'm 55 and I drive test cars.''
+<LI>8. Nathan: ``I'm 38 and I drive test cars.''
+</UL>
+</BLOCKQUOTE>
+
+<P>This puzzle includes four <I>categories</I>: first name, last name, job,
+and age.  In each category there are four <I>individuals</I>; for example, the
+first name individuals are Jane, Larry, Opal, and Perry.
+
+<P>For every possible pairing of individuals in different categories (for
+example, Jane and pilot), the program keeps track of what it knows about
+whether or not they go together.  Initially it knows nothing, but, for
+example, after the first interview the program knows that Jane is not King,
+since the four statements are from different people.
+
+<P>For any given pairing, the program can know nothing, can know that the two
+individuals <I>are</I> the same, or can know that the two individuals <I>are
+not</I> the same.  But there is also a fourth, perhaps more interesting,
+situation.  After the first interview, the program does not know whether or
+not Jane and Irving are the same person, nor whether Jane and age 45 are the
+same person.  But it does know that if one of these is true, the other must be
+false, and vice versa.  This fact is represented as a <I>link</I> between the
+Jane-Irving pair and the Jane-45 pair.
+
+<P>The program works by making <I>assertions</I> based on the puzzle statement.
+From the first interview we get the following assertions:
+
+
+<UL>
+<LI>Jane-King is false.
+<LI>Jane-Nathan is false.
+<LI>Larry-King is false.
+<LI>Larry-Nathan is false.
+<LI>Jane-Irving is linked to Jane-45.
+<LI>King-Perry is linked to King-driver.
+<LI>Larry-sergeant is linked to Larry-45.
+<LI>Nathan-drafter is linked to Nathan-38.
+</UL>
+
+<P>As each assertion is recorded in the database, the program tries to use
+<I>rules of inference</I> to draw conclusions from the new assertion and the
+assertions already recorded.  Here are the rules:
+
+<UL>
+<LI>Elimination rule:  If the X-Y pairs are false for all but one
+individual Y in a given category, then the remaining possibility
+must be true.
+
+<LI>Uniqueness rule:  If some X-Y pair is true, then every other X-Z pair
+must be false if Z is in the same category as Y.
+
+<LI>Transitive rules:  If X-Y is true, and Y-Z is true, then X-Z must
+also be true.  If X-Y is true, and Y-Z is false, then X-Z must be
+false.
+
+<LI>Link falsification:  If X-Y is linked to Z-W, and we learn that X-Y
+is true, then Z-W must be false.
+
+<LI>Link verification:  If X-Y is linked to Z-W, and we learn that X-Y
+is false, then Z-W must be true.
+</UL>
+
+<P>For each new assertion, there are only a finite number of possible
+inferences using these rules.  If we assert that X-Y is true, then the
+program must check the uniqueness rule for each other individual in the same
+category as X, and for each other individual in the same category as Y.  It
+must check the transitive rules for the other known pairs involving X or Y.
+And if there was already a link involving X-Y, then it must apply the link
+falsification rule.
+
+<P>Similarly, if we assert that X-Y is false, then the program must check the
+elimination rule, the second transitive rule, and the link verification rule.
+
+<H2>An Inference System for Many Logic Puzzles</H2>
+
+<P>This first program worked fine for this particular puzzle, but couldn't
+handle other puzzles.  The most obvious problem was that the link
+verification and link falsification rules apply only to this puzzle.  (The
+other three rules apply to any logic puzzle.)
+
+<P>In preparing the second edition of <I>Computer Science Logo Style</I> (MIT
+Press, 1997), I decided to generalize these link rules.  In Anita Harnadek's
+puzzle, two pairs are linked only through mutual exclusion; exactly one of the
+pairs must be true.  More generally, two pairs might be linked by an
+<I>implication</I>:
+
+<BLOCKQUOTE>
+If X-Y is true/false, then Z-W must be true/false.
+</BLOCKQUOTE>
+
+<P>So each link in the first program became two implications in the second
+version.  For example:
+
+<BLOCKQUOTE>
+If Jane-Irving is true, then Jane-45 must be false.<BR>
+If Jane-Irving is false, then Jane-45 must be true.
+</BLOCKQUOTE>
+
+<P>These two implications are logically independent; one cannot be derived from
+the other.
+
+<P>Once the program (reproduced in appendix A) (or
+<A HREF="https://people.eecs.berkeley.edu/~bh/logic-code/infer.lg">download it</A>) can record implications, we
+replace the link falsification and link verification rules with three new
+rules about implications:
+
+<UL>
+<LI>Contrapositive rule:  If P implies Q, then not-Q implies not-P.
+
+<LI>Implication rule (modus ponens):  If P implies Q, and P is true,
+then Q must be true.
+
+<LI>Contradiction rule:  If P implies Q, and P also implies not-Q, then
+P must be false.
+</UL>
+
+<P>In these rules, P and Q represent statements about the truth or falsehood of
+a pair, e.g., ``Jane-Irving is false.''
+
+<P>The modified program can solve not only Anita Harnadek's puzzle but also
+several others that I tried, taken from a Dell puzzle book.
+
+<H2>Backtracking</H2>
+
+<P>By coincidence, my work on the second edition of <I>Computer Science Logo
+Style</I> happened at about the same time that Harold Abelson, Gerald Jay
+Sussman, and Julie Sussman were working on the second edition of their
+brilliant text, <I>Structure and Interpretation of Computer Programs</I> (MIT
+Press, 1996).  Their second edition introduced several new topics, one of
+which was -- here's the coincidence -- logic puzzles.  I tried out my
+program on their example puzzles, such as this one:
+
+<BLOCKQUOTE>
+<P>Five schoolgirls sat for an examination.  Their parents -- so they
+thought -- showed an undue degree of interest in the result.  They
+therefore agreed that, in writing home about the examination, each girl
+should make one true statement and one untrue one.  The following are
+the relevant passages from their letters:
+
+<UL>
+<LI>Betty: ``Kitty was second in the examination.  I was only third.''
+<LI>Ethel: ``You'll be glad to hear that I was on top.  Joan was second.''
+<LI>Joan: ``I was third, and poor old Ethel was bottom.''
+<LI>Kitty: ``I came out second.  Mary was only fourth.''
+<LI>Mary: ``I was fourth.  Top place was taken by Betty.''
+</UL>
+
+<P>What in fact was the order in which the five girls were placed?
+</BLOCKQUOTE>
+
+<P>Since this puzzle is very similar in form to the other one, with paired true
+and false statements, I thought my program would solve it easily.  Here is
+how I represented the puzzle in Logo:
+
+<PRE>
+to exam
+cleanup
+category "person [Betty Ethel Joan Kitty Mary]
+category "place [1 2 3 4 5]
+xor "Kitty 2 "Betty 3
+xor "Ethel 1 "Joan 2
+xor "Joan 3 "Ethel 5
+xor "Kitty 2 "Mary 4
+xor "Mary 4 "Betty 1
+print []
+solution
+end
+</PRE>
+
+To my dismay, my program was unable to discover any facts at all from this
+puzzle!
+
+<P>The program used by Abelson and Sussman does not work by making inferences
+from known facts.  Instead, it works by <I>backtracking</I>: trying every
+possible combination of names with places, and rejecting the ones that lead
+to a contradiction.  This is more of a ``brute force'' approach; many possible
+combinations must be tried.  (In this example, there are 120 possibilities,
+five factorial.)
+
+<P>A Logo version of the backtracking program is in appendix B (or
+<A HREF="logic-code/backtrack.lg">download it</A>).  Here is how
+the program can be used to solve the examination puzzle:
+
+<PRE>
+to exam
+track [[Betty Ethel Joan Kitty Mary] [1 2 3 4 5]] ~
+      [[not equalp (is "Kitty 2) (is "Betty 3)]
+       [not equalp (is "Ethel 1) (is "Joan 2)]
+       [not equalp (is "Joan 3) (is "Ethel 5)]
+       [not equalp (is "Kitty 2) (is "Mary 4)]
+       [not equalp (is "Mary 4) (is "Betty 1)]]
+end
+</PRE>
+
+<P>The general backtracking procedure TRACK takes two inputs.  The first is a
+list of lists, one for each category, naming the individuals in that
+category.  (The categories themselves don't have names in this program.)
+The second input is also a list of lists, each of which is a Logo expression
+whose value must be TRUE for a correct solution.  The tests use a predicate
+procedure IS that takes two inputs and outputs true if they correspond to
+the same person in the particular proposed combination that the program is
+trying.
+
+<P>The backtracking procedure can also be used to solve the earlier puzzle
+about the cub reporter:
+
+<PRE>
+to cub.reporter
+track [[Jane Larry Opal Perry]
+       [Irving King Mendle Nathan]
+       [32 38 45 55]
+       [drafter pilot sergeant driver]] ~
+      [[differ [Jane King Larry Nathan]]
+       [says "Jane "Irving 45]
+       [says "King "Perry "driver]
+       [says "Larry "sergeant 45]
+       [says "Nathan "drafter 38]
+       [differ [Mendle Jane Opal Nathan]]
+       [says "Mendle "pilot "Larry]
+       [says "Jane "pilot 45]
+       [says "Opal 55 "driver]
+       [says "Nathan 38 "driver]]
+end
+
+to differ :things
+if emptyp bf :things [op "true]
+op and (differ1 first :things bf :things) (differ bf :things)
+end
+
+to differ1 :this :those
+foreach :those [if is :this ? [output "false]]
+output "true
+end
+
+to says :who :one :two
+output not equalp (is :who :one) (is :who :two)
+end
+</PRE>
+
+<P>I wrote the backtracking solution to this puzzle using the same names DIFFER
+and SAYS for the procedures that embody the facts of the puzzle, but they
+are not the same DIFFER and SAYS that are used in the original version.  The
+originals add assertions to a database; these are predicates that output
+TRUE if the current combination satisfies the condition.
+
+<P>The trouble with the backtracking solution to the cub reporter puzzle is
+that it's quite slow.  There are 13,824 possible arrangements of first
+names, last names, jobs, and ages.  (There are 24 possible combinations of
+first and last names, times 24 combinations of name and job, times 24
+combinations of name and age.)  The program might get lucky and find a
+solution on its first try, but on average it will have to examine half of
+the possible combinations before finding a solution.
+
+<H2>Repairing the Inference System</H2>
+
+<P>Why couldn't my inference program solve the examination puzzle?  One crucial
+difference between the two puzzles discussed here is that the first includes
+some direct assertions, such as the fact that Jane-King is false.  The
+second puzzle tells us no actual facts; it's entirely implications.  As a
+result, the implication rule (modus ponens) can't infer any facts.
+
+<P>If we don't have enough facts, we have to get more mileage out of the
+implications.  Each of the inference rules for assertions gives rise to a
+corresponding rule for implications:
+
+<UL>
+<LI>Meta-elimination rules:  If P implies that the X-Y pair is false for
+all but one individual Y in a given category, then P implies that
+the remaining possibility must be true.  If P implies that the X-Y
+pair is false for <I>every</I> Y in a given category, then P is false.
+
+<LI>Meta-uniqueness rule:  If P implies that some X-Y pair is true, then
+P implies that every other X-Z pair must be false if Z is in the
+same category as Y.
+
+<LI>Meta-transitive rules:  If P implies that X-Y is true, and if Y-Z is
+true, then P also implies that X-Z is true.  If P implies that X-Y
+is true, and if Y-Z is false, then P implies that X-Z is false.
+</UL>
+
+<P>When the inference program is modified to include these new rules (appendix
+C) (or <A HREF="logic-code/meta.lg">download it</A>), it can solve the
+examination puzzle as well as the cub reporter puzzle.  The cost is that the
+solution is <I>very</I> slow, even for the original puzzle, because the new
+rules allow the program to infer many new implications, each of which must be
+tested in later steps to see if it, combined with new information, allows yet
+another implication to be inferred.
+
+<P>I discovered this example as I was working on the final draft of my books.
+Should I include the modified program?  In the end, I decided not to change
+the printed version, because the modified version is so slow even for easy
+puzzles.  The original version does work for most of the puzzles I found
+in puzzle books; the difficulty of published puzzles is limited by the fact
+that mere human beings must be able to solve them!
+
+<H2>Implications Unleashed</H2>
+
+<P>Even the modified version of the program does not make every possible
+inference from implications.  For example, I included these rules:
+
+<UL>
+<LI>Meta-transitive rules:  If P implies that X-Y is true, and if Y-Z is
+true, then P also implies that X-Z is true.  If P implies that X-Y
+is true, and if Y-Z is false, then P implies that X-Z is false.
+</UL>
+
+but I didn't include these:
+
+<UL>
+<LI>Meta-meta-transitive rules:  If P implies that X-Y is true, and if P
+implies that Y-Z is true, then P also implies that X-Z is true.  If
+P implies that X-Y is true, and if P implies that Y-Z is false, then
+P implies that X-Z is false.
+
+<LI>All bases covered rule:  If P implies Q, and not-P implies Q, then
+Q must be true.
+
+<LI>Meta-meta-meta-transitive rules:  If P implies that X-Y is true, and
+if Q implies that Y-Z is true, then P and Q together imply that X-Z
+is true.  If P implies that X-Y is true, and if Q implies that Y-Z
+is false, then P and Q together imply that X-Z is false.
+</UL>
+
+<P>Also, my program can only accept implications about basic assertions.  That
+is, if P and Q are statements such as ``X-Y is true'' or ``Z-W is false'' then
+I can represent the implication ``P implies Q,'' but my program has no way to
+represent an implication such as ``(P implies Q) implies R.''
+
+<P>In fact, it's because of the limitation on the assertions that can be
+represented in this program that I need so many rules.  A general inference
+system won't have transitive rules at all, meta- or not.  Instead it will
+represent assertions in a more general way so that
+
+<BLOCKQUOTE>
+for any x, y, and z, is(x,y) and is(y,z) implies is(x,z)
+</BLOCKQUOTE>
+
+can be represented as an assertion, not as a rule.  In such a system, the
+number of rules needed is much smaller.  In effect, I've again fallen into the
+same trap that led me to have the link falsification and link verification
+rules in the first version of the program.  I eliminated the need for those
+rules by allowing my program to represent implications as well as basic facts.
+But I'm still limited to implications tied to a particular X-Y pair.  What I
+can't represent in an assertion is the ``for any x, y, and z'' part of this
+transitive property.  A system like mine, in which assertions are about
+specific individuals, is a <I>propositional</I> logic.  One in which I can say
+``for any x'' is a <I>predicate</I> logic.
+
+<P>My original program, which could only record basic assertions except for one
+ad hoc kludge for links, could truly discover every possible inference from
+the facts it was given.  But once we introduce the idea of implications,
+there is no bound on the number of possible inferences.  To write a
+practical program, we must draw a line somewhere, and decline to make
+inferences that are too complicated.
+
+<H2>Forward and Backward Chaining</H2>
+
+<P>My program works by starting with the known facts and inferring as many new
+facts as it can.  This approach is called ``forward chaining.''  Most
+practical inference systems today use ``backward chaining'':  The program
+starts with a question, such as ``What is Jane's last name,'' and looks for
+known facts that might help answer that question.  In practice this can
+effectively limit the number of dead-end chains of inference that the
+program follows.
+
+<H2>Inference Versus Backtracking</H2>
+
+<P>Backtracking works best for puzzles with few categories, because increasing
+the number of categories dramatically increases the number of possible
+combinations that must be tested.  But a backtracking program is not much
+affected by the nature of the information given by the puzzle.  By contrast,
+inference works best for puzzles that include plenty of basic facts in the
+information given, but an inference program is not much affected by the
+number of categories.  Each approach has strengths and weaknesses.
+
+<P>How do <I>people</I> solve logic puzzles?  We often use a combination of
+the two methods.  We generally start by making inferences, but if we get
+stuck, we switch to a backtracking approach.  Backtracking works well if
+inferences have already ruled out most of the possible solutions, so that
+there aren't as many left to test.  Computer inference systems have also been
+written using this hybrid technique.  Such a program is harder to write,
+because it's not easy to specify precise rules to decide when to switch from
+inference to backtracking, and because the program's data structures must
+accommodate both techniques.  The advantage is that solutions can be found
+quickly for a wide range of problems.
+
+<P>[Addendum:  Since publishing this, I've written a hybrid program, which
+you can <A HREF="logic-code/hybrid.lg">download</A>.]
+
+<H2>Appendix A:  The Inference Program</H2>
+
+<PRE>
+;; Establish categories
+
+to category :category.name :members
+print (list "category :category.name :members)
+if not namep "categories [make "categories []]
+make "categories lput :category.name :categories
+make :category.name :members
+foreach :members [pprop ? "category :category.name]
+end
+
+;; Verify and falsify matches
+
+to verify :a :b
+settruth :a :b "true
+end
+
+to falsify :a :b
+settruth :a :b "false
+end
+
+to settruth :a :b :truth.value
+if equalp (gprop :a "category) (gprop :b "category) [stop]
+localmake "oldvalue get :a :b
+if equalp :oldvalue :truth.value [stop]
+if equalp :oldvalue (not :truth.value) ~
+   [(throw "error (sentence [inconsistency in settruth]
+                            :a :b :truth.value))]
+print (list :a :b "-> :truth.value)
+store :a :b :truth.value
+settruth1 :a :b :truth.value
+settruth1 :b :a :truth.value
+if not emptyp :oldvalue ~
+   [foreach (filter [equalp first ? :truth.value] :oldvalue)
+            [apply "settruth butfirst ?]]
+end
+
+to settruth1 :a :b :truth.value
+apply (word "find not :truth.value) (list :a :b)
+foreach (gprop :a "true) [settruth ? :b :truth.value]
+if :truth.value [foreach (gprop :a "false) [falsify ? :b]
+                 pprop :a (gprop :b "category) :b]
+pprop :a :truth.value (fput :b gprop :a :truth.value)
+end
+
+to findfalse :a :b
+foreach (filter [not equalp get ? :b "true] peers :a) ~
+        [falsify ? :b]
+end
+
+to findtrue :a :b
+if equalp (count peers :a) (1+falses :a :b) ~
+   [verify (find [not equalp get ? :b "false] peers :a)
+           :b]
+end
+
+to falses :a :b
+output count filter [equalp "false get ? :b] peers :a
+end
+
+to peers :a
+output thing gprop :a "category
+end
+
+;; Common types of clues
+
+to differ :list
+print (list "differ :list)
+foreach :list [differ1 ? ?rest]
+end
+
+to differ1 :a :them
+foreach :them [falsify :a ?]
+end
+
+to justbefore :this :that :lineup
+falsify :this :that
+falsify :this last :lineup
+falsify :that first :lineup
+justbefore1 :this :that :lineup
+end
+
+to justbefore1 :this :that :slotlist
+if emptyp butfirst :slotlist [stop]
+equiv :this (first :slotlist) :that (first butfirst :slotlist)
+justbefore1 :this :that (butfirst :slotlist)
+end
+
+;; Remember conditional linkages
+
+to implies :who1 :what1 :truth1 :who2 :what2 :truth2
+implies1 :who1 :what1 :truth1 :who2 :what2 :truth2
+implies1 :who2 :what2 (not :truth2) :who1 :what1 (not :truth1)
+end
+
+to implies1 :who1 :what1 :truth1 :who2 :what2 :truth2
+localmake "old1 get :who1 :what1
+if equalp :old1 :truth1 [settruth :who2 :what2 :truth2  stop]
+if equalp :old1 (not :truth1) [stop]
+if memberp (list :truth1 :who2 :what2 (not :truth2)) :old1 ~
+   [settruth :who1 :what1 (not :truth1)  stop]
+if memberp (list :truth1 :what2 :who2 (not :truth2)) :old1 ~
+   [settruth :who1 :what1 (not :truth1)  stop]
+store :who1 :what1 ~
+      fput (list :truth1 :who2 :what2 :truth2) :old1
+end
+
+to equiv :who1 :what1 :who2 :what2
+implies :who1 :what1 "true :who2 :what2 "true
+implies :who2 :what2 "true :who1 :what1 "true
+end
+
+to xor :who1 :what1 :who2 :what2
+implies :who1 :what1 "true :who2 :what2 "false
+implies :who1 :what1 "false :who2 :what2 "true
+end
+
+;; Interface to property list mechanism
+
+to get :a :b
+output gprop :a :b
+end
+
+to store :a :b :val
+pprop :a :b :val
+pprop :b :a :val
+end
+
+;; Print the solution
+
+to solution
+foreach thing first :categories [solve1 ? butfirst :categories]
+end
+
+to solve1 :who :order
+type :who
+foreach :order [type "| |   type gprop :who ?]
+print []
+end
+
+;; Get rid of old problem data
+
+to cleanup
+if not namep "categories [stop]
+ern :categories
+ern "categories
+erpls
+end
+</PRE>
+
+<H2>Appendix B: The Backtracking Program</H2>
+
+<PRE>
+to track :lists :tests
+foreach first :lists [make ? array count bf :lists]
+catch "tracked [track1 first :lists bf :lists 1]
+end
+
+to track1 :master :others :index
+if emptyp :others [tracktest stop]
+track2 :master first :others bf :others
+end
+
+to track2 :names :these :those
+if emptyp :these [track1 :master :those :index+1 stop]
+foreach :these [setitem :index thing first :names ?
+                track2 bf :names remove ? :these :those]
+end
+
+to tracktest
+foreach :tests [if not run ? [stop]]
+foreach :master [pr se ? arraytolist thing ?]
+throw "tracked
+end
+
+to is :this :that
+if memberp :this :master [output memberp :that thing :this]
+if memberp :that :master [output memberp :this thing :that]
+localmake "who find [memberp :this thing ?] :master
+output memberp :that thing :who
+end
+</PRE>
+
+<H2>Appendix C: The Enhanced Inference System</H2>
+
+<P>Only the procedures changed from the version in appendix A are given here:
+
+<PRE>
+to implies :who1 :what1 :truth1 :who2 :what2 :truth2
+if equalp (gprop :who1 "category) (gprop :what1 "category) [stop]
+if equalp (gprop :who2 "category) (gprop :what2 "category) [stop]
+implies1 :who1 :what1 :truth1 :who2 :what2 :truth2
+implies1 :who2 :what2 (not :truth2) :who1 :what1 (not :truth1)
+end
+
+to implies1 :who1 :what1 :truth1 :who2 :what2 :truth2
+localmake "old1 get :who1 :what1
+if equalp :old1 :truth1 [settruth :who2 :what2 :truth2  stop]
+if equalp :old1 (not :truth1) [stop]
+if memberp (list :truth1 :who2 :what2 :truth2) :old1 [stop]
+if memberp (list :truth1 :what2 :who2 :truth2) :old1 [stop]
+if memberp (list :truth1 :who2 :what2 (not :truth2)) :old1 ~
+   [settruth :who1 :what1 (not :truth1)  stop]
+if memberp (list :truth1 :what2 :who2 (not :truth2)) :old1 ~
+   [settruth :who1 :what1 (not :truth1)  stop]
+store :who1 :what1 ~
+      fput (list :truth1 :who2 :what2 :truth2) :old1
+if :truth2 [foreach (remove :who2 peers :who2)
+                    [implies :who1 :what1 :truth1 ? :what2 "false]
+            foreach (remove :what2 peers :what2)
+                    [implies :who1 :what1 :truth1 :who2 ? "false]]
+if not :truth2 [implies2 :what2 (remove :who2 peers :who2)
+                implies2 :who2 (remove :what2 peers :what2)]
+foreach (gprop :who2 "true) ~
+        [implies :who1 :what1 :truth1 ? :what2 :truth2]
+foreach (gprop :what2 "true) ~
+        [implies :who1 :what1 :truth1 :who2 ? :truth2]
+if :truth2 ~
+   [foreach (gprop :who2 "false)
+            [implies :who1 :what1 :truth1 ? :what2 "false]
+    foreach (gprop :what2 "false)
+            [implies :who1 :what1 :truth1 :who2 ? "false]]
+end
+
+to implies2 :one :others
+localmake "left filter [not (or memberp (list :truth1 :one ? "false) :old1
+                                memberp (list :truth1 ? :one "false) :old1
+                                (and :truth1
+                                     (or (and equalp ? :who1
+                                              equalp gprop :what1 "category
+                                                     gprop :one "category)
+                                         (and equalp ? :what1
+                                              equalp gprop :who1 "category
+                                                     gprop :one "category))
+                                     (not or equalp :one :who1 
+                                             equalp :one :what1))
+                                equalp get :one ? "false)] ~
+                       :others
+if emptyp :left [settruth :who1 :what1 (not :truth1) stop]
+if emptyp butfirst :left ~
+   [implies :who1 :what1 :truth1 :one first :left "true]
+end
+</PRE>
+
+<P><ADDRESS>
+<A HREF="index.html"><CODE>www.cs.berkeley.edu/~bh</CODE></A>
+</ADDRESS>
+</BODY>
+</HTML>