about summary refs log tree commit diff stats
path: root/js/games/nluqo.github.io/~bh/v3ch6/ai.html
diff options
context:
space:
mode:
Diffstat (limited to 'js/games/nluqo.github.io/~bh/v3ch6/ai.html')
-rw-r--r--js/games/nluqo.github.io/~bh/v3ch6/ai.html3070
1 files changed, 3070 insertions, 0 deletions
diff --git a/js/games/nluqo.github.io/~bh/v3ch6/ai.html b/js/games/nluqo.github.io/~bh/v3ch6/ai.html
new file mode 100644
index 0000000..631abbf
--- /dev/null
+++ b/js/games/nluqo.github.io/~bh/v3ch6/ai.html
@@ -0,0 +1,3070 @@
+<HTML>
+<HEAD>
+<TITLE>Computer Science Logo Style vol 3 ch 6: Artificial Intelligence</TITLE>
+</HEAD>
+<BODY>
+<CITE>Computer Science Logo Style</CITE> volume 3:
+<CITE>Beyond Programming</CITE> 2/e Copyright (C) 1997 MIT
+<H1>Artificial Intelligence</H1>
+
+<TABLE width="100%"><TR><TD>
+<IMG SRC="../csls3.jpg" ALT="cover photo">
+<TD><TABLE>
+<TR><TD align="right"><CITE><A HREF="http://www.cs.berkeley.edu/~bh/">Brian
+Harvey</A><BR>University of California, Berkeley</CITE>
+<TR><TD align="right"><BR>
+<TR><TD align="right"><A HREF="../pdf/v3ch06.pdf">Download PDF version</A>
+<TR><TD align="right"><A HREF="../v3-toc2.html">Back to Table of Contents</A>
+<TR><TD align="right"><A HREF="../v3ch5/v3ch5.html"><STRONG>BACK</STRONG></A>
+chapter thread <A HREF="https://people.eecs.berkeley.edu/~bh/v3ch7/v3ch7.html"><STRONG>NEXT</STRONG></A>
+<TR><TD align="right"><A HREF="https://mitpress.mit.edu/books/computer-science-logo-style-second-edition-volume-3">MIT
+Press web page for <CITE>Computer Science Logo Style</CITE></A>
+</TABLE></TABLE>
+
+<HR><P>Program file for this chapter: <A HREF="student.lg"><CODE>student</CODE></A>
+
+
+<P>
+
+<P>Can a computer be intelligent?  What would it mean for a computer to be
+intelligent?  John McCarthy, one of the founders of
+artificial intelligence
+research, once defined the field as &quot;getting a computer to do things which,
+when done by people, are said to involve intelligence.&quot; The point of the
+definition was that he felt perfectly comfortable about carrying on his
+research without first having to defend any particular philosophical view of
+what the word &quot;intelligence&quot; means.
+
+<P>There have always been two points of view among AI researchers about what
+their purpose is.  One point of view is that AI programs contribute to our
+understanding of <EM>human</EM> psychology; when researchers take this view
+they try to make their programs reflect the actual mechanisms of intelligent
+human behavior.  For example, Allen Newell and
+Herbert A. Simon begin their
+classic AI book <EM>Human Problem Solving</EM> with the sentence, &quot;The aim
+of this book is to advance our understanding of how humans think.&quot; In one
+of their research projects they studied cryptarithmetic problems, in which
+digits are replaced with letters in a multi-digit addition or multiplication.
+First they did a careful observation and analysis of how a human subject
+attacked such a problem, then they pointed out specific problem-solving
+techniques that the person used, and used those techniques as the basis for
+designing a computer simulation.  The other point of view
+is that AI programs provide a more abstract model for intelligence in
+general; just as one can learn about the properties of computers by studying
+finite-state machines, even though no real computer operates precisely as a
+formal finite-state machine does, we can learn about the properties of any
+possible intelligent being by simulating intelligence in a computer program,
+whether or not the mechanisms of that program are similar to those used by
+people.
+
+<P>In the early days of AI research these two points of view were not sharply
+divided.  Sometimes the same person would switch from one to the other,
+sometimes trying to model human thought processes and sometimes trying to
+solve a given problem by whatever methods could be made to work.  More
+recently, researchers who hold one or the other point of view consistently
+have begun to define two separate fields.  One is <EM>
+cognitive science,</EM> in which computer scientists join with
+psychologists, linguists, biologists, and others to study human cognitive
+psychology, using computer programs as a concrete embodiment of theories
+about the human mind.  The other is called <EM>expert systems</EM>
+or <EM>knowledge engineering,</EM> in which programming techniques
+developed by AI researchers are put to practical use in programs that solve
+real-world business problems such as the diagnosis and repair of
+malfunctioning equipment.
+
+<P><H2>Microworlds: Student</H2>
+
+<P>In this chapter I'm going to concentrate on one particular area of AI
+research: teaching a computer to understand English.  Besides its inherent
+interest, this area has the advantage that it doesn't require special
+equipment, as do some other parts of AI such as machine vision and the
+control of robot manipulators.
+
+<P>In the 1950s many people were very optimistic about the use of computers to
+translate from one language to another.  IBM undertook a government-sponsored
+project to translate scientific journals from Russian to English.  At first
+they thought that this translation could be done very straightforwardly,
+with a Russian-English dictionary and a few little kludges to rearrange the
+order of words in a sentence to account for differences in the grammatical
+structure of the two languages.  This simple approach was not successful.
+One problem is that the same word can have different meanings, and even
+different parts of speech, in different contexts.  (According to one famous
+anecdote, the program translated the Russian equivalent of &quot;The spirit is
+willing but the flesh is weak&quot; into &quot;The vodka is strong but the meat is
+rotten.&quot;)
+
+<P>A decade later, several AI researchers had the idea that ambiguities in the
+meanings of words could be resolved by trying to understand English only in
+some limited context.  If you know in advance that the sentence you're
+trying to understand is about baseball statistics, or about relationships in
+a family tree, or about telling a robot arm to move blocks on a table (these
+are actual examples of work done in that period) then only certain narrowly
+defined types of sentences are meaningful at all.  You needn't think about
+metaphors or about the many assumptions about commonsense knowledge that
+people make in talking with one another.  Such a limited context for a
+language understanding program is called a <EM>microworld.</EM>
+
+<P>This chapter includes a Logo version of Student, a program written by
+Daniel G. Bobrow for his 1964 Ph.D. thesis, <EM>Natural
+Language Input for a Computer Problem Solving System,</EM> at MIT.  Student
+is a program that solves algebra word problems:
+
+<P><PRE>? <U>student [The price of a radio is 69.70. If this price is 15 percent</U>
+           <U>less than the marked price, find the marked price.]</U>
+
+The marked price is 82 dollars
+</PRE>
+
+<P>(In this illustration I've left out some of Student's display of
+intermediate results.)  The program has two parts: one that translates the
+word problem into the form of equations and another that solves the
+equations.  The latter part is complex (about 40 Logo procedures) but
+straightforward; it doesn't seem surprising to most people that a computer
+can manipulate mathematical equations.  It is Student's understanding of
+English sentences that furthered the cause of artificial intelligence.
+
+<BLOCKQUOTE>
+<P><A NAME="bobrow1">The aim</A> of the
+research reported here was to discover how one could build a
+computer program which could communicate with people in a natural language
+within some restricted problem domain.  In the course of this investigation,
+I wrote a set of computer programs, the Student system, which accepts as
+input a comfortable but restricted subset of English which can be used to
+express a wide variety of algebra story problems...
+
+<P>In the following discussion, I shall use phrases such as &quot;the computer
+understands English.&quot;  In all such cases, the &quot;English&quot; is just the
+restricted subset of English which is allowable as input for the computer
+program under discussion.  In addition, for purposes of this report I have
+adopted the following operational definition of understanding.  A computer
+<EM>understands</EM> a subset of English if it accepts input sentences which
+are members of this subset, and answers questions based on information
+contained in the input.  The Student system understands English in this
+sense.  [Bobrow, 1964.]
+</BLOCKQUOTE>
+
+<P>How does the algebra microworld simplify the understanding problem?  For one
+thing, Student need not know anything about the meanings of noun phrases.
+In the sample problem above, the phrase <CODE>The price of a radio</CODE> is used
+as a variable name.  The problem could just as well have been
+
+<P><PRE>The weight of a giant size detergent box is 69.70 ounces.  If this weight
+is 15 percent less than the weight of an enormous size box, find the
+weight of an enormous size box.
+</PRE>
+
+<P>For Student, either problem boils down to
+
+<P><PRE><EM>variable1</EM> = 69.70 <EM>units</EM>
+
+<EM>variable1</EM> = 0.85 * <EM>variable2</EM>
+
+Find <EM>variable2</EM>.
+</PRE>
+
+<P>Student understands particular words only to the extent that they
+have a <EM>mathematical</EM> meaning.  For example, the program knows that
+<CODE>15 percent less than</CODE> means the same as <CODE>0.85 times</CODE>.
+
+<P><H2>How Student Translates English to Algebra</H2>
+
+<P>Student translates a word problem into equations in several steps.  In the
+following paragraphs, I'll mention in parentheses the names of the Logo
+procedures that carry out each step I describe, but don't read the
+procedures yet.  First read through the description of the process without
+worrying about the programming details of each step.  Later you can reread
+this section while examining the complete listing at the end of the chapter.
+
+<P>In translating Student to Logo, I've tried not to change the capabilities of
+the program in any way.  The overall structure of my version is similar to
+that of Bobrow's original implementation, but I've changed some details.
+I've used iteration and mapping tools to make the program easier to read;
+I've changed some aspects of the fine structure of the program to fit more
+closely with the usual Logo programming style; in a few cases I've tried to
+make exceptionally slow parts of the program run faster by finding a more
+efficient algorithm to achieve the same goal.
+
+<P>The top-level procedure <CODE>student</CODE> takes one input, a list containing the
+word problem.  (The disk file that accompanies this project includes several
+variables containing sample problems.  For example,
+
+<P><PRE>? <U>student :radio</U>
+</PRE>
+
+<P>will carry out the steps I'm about to describe.)  Student begins
+by printing the original problem:
+
+<P><PRE>? <U>student :radio</U>
+
+The problem to be solved is
+
+The price of a radio is 69.70. If this price is 15 percent less than the
+marked price, find the marked price.
+</PRE>
+
+<P>The first step is to separate punctuation characters from the
+attached words.  For example, the word &quot;<CODE>price,</CODE>&quot; in the original problem
+becomes the two words &quot;<CODE>price ,</CODE>&quot; with the comma on its own.  Then
+(<CODE>student1</CODE>) certain <EM>mandatory substitutions</EM> are applied
+(<CODE>idioms</CODE>).  For example, the phrase <CODE>percent less than</CODE> is translated
+into the single word <CODE>perless</CODE>.  The result is printed:
+
+<P><PRE>With mandatory substitutions the problem is
+
+The price numof a radio is 69.70 dollars . If this price is 15 perless
+the marked price , find the marked price .
+</PRE>
+
+<P>(The word <CODE>of</CODE> in an algebra word problem can have two
+different meanings.  Sometimes it means &quot;times,&quot; as in the phrase
+&quot;one half of the population.&quot; Other times, as in this problem, &quot;of&quot; is
+just part of a noun phrase like &quot;the price of a radio.&quot; The special word
+<CODE>numof</CODE> is a flag to a later part of the program and will then be
+further translated either into <CODE>times</CODE> or back into <CODE>of</CODE>.  The
+original implementation of Student used, instead of a special word like <CODE>
+numof</CODE>, a &quot;tagged&quot; word represented as a list like <CODE>[of / op]</CODE>.  Other
+examples of tagging are <CODE>[Bill / person]</CODE> and <CODE>[has / verb]</CODE>.)
+
+<P>
+
+<P>The next step is to separate the problem into simple sentences (<CODE>bracket</CODE>):
+
+<P><PRE>The simple sentences are
+
+The price numof a radio is 69.70 dollars .
+
+This price is 15 perless the marked price .
+
+Find the marked price .
+</PRE>
+
+<P>Usually this transformation of the problem is straightforward, but
+the special case of &quot;age problems&quot; is recognized at this time, and special
+transformations are applied so that a sentence like
+
+<P><PRE>Mary is 24 years old.
+</PRE>
+
+<P>is translated into
+
+<P><PRE>Mary s age is 24 .
+</PRE>
+
+<P>An age problem is one that contains any of the phrases <CODE>as old
+as</CODE>, <CODE>age</CODE>, or <CODE>years old</CODE>.
+
+<P>The next step is to translate each simple sentence into an equation or a
+variable whose value is desired as part of the solution (<CODE>senform</CODE>).
+
+<P><PRE>The equations to be solved are
+
+Equal [price of radio] [product 69.7 [dollars]]
+
+Equal [price of radio] [product 0.85 [marked price]]
+</PRE>
+
+<P>The third simple sentence is translated, not into an equation, but
+into a request to solve these equations for the variable <CODE>marked price</CODE>.
+
+<P>The translation of simple sentences into equations is the most
+&quot;intelligent&quot; part of the program; that is, it's where the program's
+knowledge of English grammar and vocabulary come into play and many special
+cases must be considered.  In this example, the second simple sentence
+starts with the phrase <CODE>this price</CODE>.  The program recognizes the word
+<CODE>this</CODE> (procedure <CODE>nmtest</CODE>) and replaces the entire phrase with the
+left hand side of the previous equation (procedure <CODE>this</CODE>).
+
+<P>
+
+
+<P><H2>Pattern Matching</H2>
+
+
+<P>Student analyzes a sentence by comparing it to several <EM>patterns</EM>
+(<CODE>senform1</CODE>).  For example, one sentence form that Student understands
+is exemplified by these sentences:
+
+<P><PRE>Joe weighs 163 pounds .
+The United States Army has 8742 officers .
+</PRE>
+
+<P>The general pattern is
+
+<P><PRE><EM>something</EM> <EM>verb</EM> <EM>number</EM> <EM>unit</EM> .
+</PRE>
+
+<P>Student treats such sentences as if they were rearranged to match
+
+<P><PRE>The number of <EM>unit</EM> <EM>something</EM> <EM>verb</EM> is <EM>number</EM> .
+</PRE>
+
+<P>and so it generates the equations
+
+<P><PRE>Equal [number of pounds Joe weighs] 163
+
+Equal [number of officers United States Army has] 8742
+</PRE>
+
+<P>The original version of Student was written in a pattern matching
+language called Meteor, which Bobrow wrote in Lisp.  In Meteor, the
+instruction that handles this sentence type looks like this:
+
+<P><PRE>(*   ( (1 / verb) (fn nmtest) 1  (1 / dlm)) 0
+     (/ (*s shelf (*k equal (fn opform (*k the number of 4 1 2))
+                            (fn opform (*k 3 5 6)))))            return)
+</PRE>
+
+<P>The top line contains the pattern to be matched.  In the pattern,
+a dollar sign represents zero or more words; the notation <CODE>1</CODE>
+represents a single word.  The zero at the end of the line means that the
+text that matches the pattern should be deleted and nothing should replace
+it.  The rest of the instruction pushes a new equation onto a stack named
+<CODE>shelf</CODE>; that equation is formed out of the pieces of the matched
+pattern according to the numbers in the instruction.  That is, the number
+<CODE>4</CODE> represents the fourth component of the pattern, which is <CODE>1</CODE>.
+
+
+	Here is the corresponding instruction in the Logo version:
+
+<P><PRE>if match [^one !verb1:verb !factor:numberp #stuff1 !:dlm] :sent
+   [output (list (list &quot;equal
+                       opform (sentence [the number of]
+                                        :stuff1 :one :verb1)
+                       opform (list :factor) ))]
+</PRE>
+
+<P>The pattern matcher I used for Student is the same as the one in
+<EM>Advanced Techniques,</EM> the second volume of this series.<SUP>*</SUP>  Student often relies on the fact that
+Meteor's pattern matcher finds the <EM>first substring</EM> of the text that
+matches the pattern, rather than requiring the entire text to match.  Many
+patterns in the Logo version therefore take the form
+
+<P><PRE>[^beg <EM>interesting part</EM> #end]
+</PRE>
+
+<P>where the &quot;interesting part&quot; is all that appeared in the Meteor
+pattern.
+
+<P><SMALL><BLOCKQUOTE><SMALL><SUP>*</SUP>The
+version in this project is modified slightly; the <CODE>match</CODE> procedure
+first does a fast test to try to reject an irrelevant pattern in O(<EM>n</EM>)
+time before calling the actual pattern matcher, which could take as much
+as O(2<SUP><SMALL><EM>n</EM></SMALL></SUP>) time to reject a pattern, and which has been renamed <CODE>rmatch</CODE>
+(for &quot;real match&quot;) in this project.</SMALL></BLOCKQUOTE></SMALL>
+
+<P>Here is a very brief summary of the Logo pattern matcher included in this
+program.  For a fuller description with examples, please refer to Volume 2.
+<CODE>Match</CODE> is a predicate with two inputs, both lists.  The first input is
+the <EM>pattern</EM> and the second input is the <EM>sentence.</EM>  <CODE>Match</CODE>
+outputs <CODE>true</CODE> if the sentence <EM>matches</EM> the pattern.  A word in
+the pattern that does not begin with one of the special <EM>quantifier</EM>
+characters listed below matches the identical word in the sentence.  A word
+in the pattern that does begin with a quantifier matches zero or more words
+in the sentence, as follows:
+
+<P><TABLE>
+<TR><TD><CODE>#</CODE><TD>&nbsp;&nbsp;&nbsp;zero or more
+<TR><TD><CODE>&amp;</CODE><TD>&nbsp;&nbsp;&nbsp;one or more
+<TR><TD><CODE>?</CODE><TD>&nbsp;&nbsp;&nbsp;zero or one
+<TR><TD><CODE>!</CODE><TD>&nbsp;&nbsp;&nbsp;exactly one
+<TR><TD><CODE>@</CODE><TD>&nbsp;&nbsp;&nbsp;zero or more (test as group)
+<TR><TD><CODE>^</CODE><TD>&nbsp;&nbsp;&nbsp;zero or more (as few as possible)
+</TABLE>
+
+<P>
+All quantifiers match as many consecutive words as possible while
+still allowing the remaining portion of the pattern to be matched, except
+for <CODE>^</CODE>.  A quantifier may be used alone, or it can be followed by a
+variable name, a predicate name, or both:
+
+<P><PRE>#
+#var
+#:pred
+#var:pred
+</PRE>
+
+If a variable name is used, the word or words that match the
+quantifier will be stored in that variable if the match is successful.  (The
+value of the variable if the match is not successful is not guaranteed.)  If
+a predicate is used, it must take one word as input; in order for a word in
+the sentence to be accepted as (part of) a match for the quantifier, the
+predicate must output <CODE>true</CODE> when given that word as input.  For
+example, the word
+
+<P><PRE>!factor:numberp
+</PRE>
+
+<P>in the pattern above requires exactly one matching word in the
+sentence; that word must be a number, and it is remembered in the variable
+<CODE>factor</CODE>.  If the quantifier is <CODE>@</CODE> then the predicate must take a
+<EM>list</EM> as input, and it must output <CODE>true</CODE> for all the candidate
+matching words taken together as a list.  For example, if you define a
+procedure
+
+<P><PRE>to threep :list
+output equalp count :list 3
+end
+</PRE>
+
+<P>then the pattern word
+
+<P><PRE>@:threep
+</PRE>
+
+<P>will match exactly three words in the sentence.  (Student does not
+use this last feature of the pattern matcher.  In fact, predicates are
+applied only to the single-word quantifiers <CODE>?</CODE> and <CODE>!</CODE>.)
+
+<P>Pattern matching is also heavily used in converting words and phrases with
+mathematical meaning into the corresponding arithmetic operations
+(<CODE>opform</CODE>).  An equation is a list of three members; the first member is the
+word <CODE>equal</CODE> and the other two are expressions formed by applying
+operations to variables and numbers.  Each operation that is required is
+represented as a list whose first member is the name of the Logo procedure
+that carries out the operation and whose remaining members are expressions
+representing the operands.  For example, the equation
+<P><CENTER><EM>y</EM> = 3<EM>x</EM><SUP><SMALL>2</SMALL></SUP>
++ 6<EM>x</EM> &minus; 1</CENTER><P>
+would be represented by the list
+
+<P><PRE>[equal [y] [sum [product 3 [square [x]]] [product 6 [x]] [minus 1]]]
+</PRE>
+
+<P>The variables are represented by lists like <CODE>[x]</CODE> rather than
+just the words because in Student a variable can be a multi-word phrase like
+<CODE>price of radio</CODE>.  The difference between two expressions is represented
+by a <CODE>sum</CODE> of one expression and <CODE>minus</CODE> the other, rather than as
+the <CODE>difference</CODE> of the expressions, because this representation turns
+out to make the process of simplifying and solving the equations easier.
+
+<P>In word problems, as in arithmetic expressions, there is a precedence of
+operations.  Operations like <CODE>squared</CODE> apply to the variables right next
+to them; ones like <CODE>times</CODE> are intermediate, and ones like <CODE>plus</CODE>
+apply to the largest possible subexpressions.  Student looks first for the
+lowest-priority ones like <CODE>plus</CODE>; if one is found, the entire rest of
+the clause before and after the operation word provide the operands.  Those
+operands are recursively processed by <CODE>opform</CODE>; when all the
+low-priority operations have been found, the next level of priority will be
+found by matching the pattern
+
+<P><PRE>[^left !op:op1 #right]
+</PRE>
+
+<P><H2>Solving the Equations</H2>
+
+<P>Student uses the substitution technique to solve the equations.  That is,
+one equation is rearranged so that the left hand side contains only a single
+variable and the right hand side does not contain that variable.  Then, in
+some other equation, every instance of that variable is replaced by the
+right hand side of the first equation.  The result is a new equation from
+which one variable has been eliminated.  Repeating this process enough times
+should eventually yield an equation with only a single variable, which can
+be solved to find the value of that variable.
+
+<P>When a problem gives rise to several linear equations in several variables,
+the traditional technique for computer solution is to use matrix inversion;
+this technique is messy for human beings because there is a lot of
+arithmetic involved, but straightforward for computers because the algorithm
+can be specified in a simple way that doesn't depend on the particular
+equations in each problem.  Bobrow chose to use the substitution method
+because some problems give rise to equations that are linear in the variable
+for which a solution is desired but nonlinear in other variables.  Consider
+this problem:
+
+<P><PRE>? <U>student :tom</U>
+
+The problem to be solved is
+
+If the number of customers Tom gets is twice the square of 20 per cent of
+the number of advertisements he runs, and the number of advertisements he
+runs is 45, what is the number of customers Tom gets?
+
+
+With mandatory substitutions the problem is
+
+If the number numof customers Tom gets is 2 times the square 20 percent
+numof the number numof advertisements he runs , and the number numof
+advertisements he runs is 45 , what is the number numof customers
+Tom gets ?
+
+
+The simple sentences are
+
+The number numof customers Tom gets is 2 times the square 20 percent
+numof the number numof advertisements he runs .
+
+The number numof advertisements he runs is 45 .
+
+What is the number numof customers Tom gets ?
+
+
+The equations to be solved are
+
+Equal [number of customers Tom gets]
+      [product 2 [square [product 0.2 [number of advertisements
+                                       he runs]]]]
+
+Equal [number of advertisements he runs] 45
+
+
+The number of customers Tom gets is 162
+
+The problem is solved.
+</PRE>
+
+<P>The first equation that Student generates for this problem is
+linear in the number of customers Tom gets, but nonlinear in the number of
+advertisements he runs.  (That is, the equation refers to the <EM>square</EM>
+of the latter variable.  An equation is <EM>linear</EM> in a given variable
+if that variable isn't multiplied by anything other than a constant number.)
+Using the substitution method, Student can solve the problem by substituting
+the value 45, found in the second equation, for the number of advertisements
+variable in the first equation.
+
+<P>(Notice, in passing, that one of the special <CODE>numof</CODE> words in this
+problem was translated into a multiplication rather than back into the
+original word <CODE>of</CODE>.)
+
+<P>The actual sequence of steps required to solve a set of equations is quite
+intricate.  I recommend taking that part of Student on faith the first time
+you read the program, concentrating instead on the pattern matching
+techniques used to translate the English sentences into equations.  But here
+is a rough guide to the solution process.  Both <CODE>student1</CODE> and <CODE>
+student2</CODE> call <CODE>trysolve</CODE> with four inputs: a list of the equations to
+solve, a list of the variables for which values are wanted, and two lists of
+<EM>units.</EM>  A unit is a word or phrase like <CODE>dollars</CODE> or <CODE>feet</CODE>
+that may be part of a solution.  Student treats units like variables while
+constructing the equations, so the combination of a number and a unit is
+represented as a product, like
+
+<P><PRE>[product 69.7 [dollars]]
+</PRE>
+
+<P>for 69.70 in the first sample problem.  While constructing the
+equations, Student generates two lists of units.  The first, stored in the
+variable <CODE>units</CODE>, contains any word or phrase that appears along with a
+number in the problem statement, like the word <CODE>feet</CODE> in the phrase <CODE>
+3 feet</CODE> (<CODE>nmtest</CODE>).  The second, in the variable <CODE>aunits</CODE>, contains
+units mentioned explicitly in the <CODE>find</CODE> or <CODE>how many</CODE> sentences
+that tell Student what variables should be part of the solution
+(<CODE>senform1</CODE>).  If the problem includes a sentence like
+
+<P><PRE>How many inches is a yard?
+</PRE>
+
+<P>then the variable <CODE>[inches]</CODE>, and <EM>only</EM> that variable,
+is allowed to be part of the answer.  If there are no <CODE>aunits</CODE>-type
+variables in the problem, then any of the <CODE>units</CODE> variables may appear
+in the solution (<CODE>trysolve</CODE>).
+
+<P><CODE>Trysolve</CODE> first calls <CODE>solve</CODE> to solve the equations and then uses
+<CODE>pranswers</CODE> to print the results.  <CODE>Solve</CODE> calls <CODE>solver</CODE> to do
+most of the work and then passes its output through <CODE>solve.reduce</CODE> for
+some final cleaning up.  <CODE>Solver</CODE> works by picking one of the
+variables from the list <CODE>:wanted</CODE> and asking <CODE>solve1</CODE> to find a
+solution for that variable in terms of <EM>all</EM> the other variables--the
+other wanted variables as well as the units allowed in the ultimate answer.
+If <CODE>solve1</CODE> succeeds, then <CODE>solver</CODE> invokes itself,
+adding the newly-found expression for one variable to an <EM>
+association list</EM> (in the variable <CODE>alis</CODE>) so that, from then
+on, any occurrence of that variable will be replaced with the equivalent
+expression.  In effect, the problem is simplified by eliminating one
+variable and eliminating one equation, the one that was solved to find the
+equivalent expression.
+
+<P><CODE>Solve1</CODE> first looks for an equation containing the variable for which
+it is trying to find a solution.  When it finds such an equation, the next
+task is to eliminate from that equation any variables that aren't part of
+the wanted-plus-units list that <CODE>solver</CODE> gave <CODE>solve1</CODE> as an input.
+To eliminate these extra variables, <CODE>solve1</CODE> invokes <CODE>solver</CODE> with
+the extras as the list of wanted variables.  This mutual recursion between
+<CODE>solver</CODE> and <CODE>solve1</CODE> makes the structure of the solution process
+difficult to follow.  If <CODE>solver</CODE> manages to eliminate the extra
+variables by expressing them in terms of the originally wanted ones, then
+<CODE>solve1</CODE> can go on to substitute those expressions into its originally
+chosen equation and then use <CODE>solveq</CODE> to solve that one equation for the
+one selected variable in terms of all the other allowed variables.  <CODE>
+Solveq</CODE> manipulates the equation more or less the way students in algebra
+classes do, adding the same term to both sides, multiplying both sides by
+the denominator of a polynomial fraction, and so on.
+
+<P>Here is how <CODE>solve</CODE> solves the radio problem.  The equations, again, are
+
+<P><PRE>Equal [price of radio] [product 69.7 [dollars]]
+
+Equal [price of radio] [product 0.85 [marked price]]
+</PRE>
+
+<P><CODE>Trysolve</CODE> evaluates the expression
+
+<P><PRE>(1) solve [[marked price]]
+          [[equal [price of radio] [product 69.7 [dollars]]]
+           [equal [price of radio] [product 0.85 [marked price]]] ]
+          [[dollars]]
+</PRE>
+
+<P>(I'm numbering these expressions so that I can refer to them later
+in the text.)  The first input to <CODE>solve</CODE> is the list of variables
+wanted in the solution; in this case there is only one such variable.  The
+second input is the list of two equations.  The third is the list of unit
+variables that are allowed to appear in the solution; in this case only <CODE>
+[dollars]</CODE> is allowed.  <CODE>Solve</CODE> evaluates
+
+<P><PRE>(2) solver [[marked price]] [[dollars]] [] []
+</PRE>
+
+<P>(There is a fifth input, the word <CODE>insufficient</CODE>, but this is
+used only as an error flag if the problem can't be solved.  To simplify this
+discussion I'm going to ignore that input for both <CODE>solver</CODE> and <CODE>
+solve1</CODE>.)  <CODE>Solver</CODE> picks the first (in this case, the only) wanted
+variable as the major input to <CODE>solve1</CODE>:
+
+<P><PRE>(3) solve1 [marked price]
+           [[dollars]]
+           []
+           [[equal [price of radio] [product 69.7 [dollars]]]
+            [equal [price of radio] [product 0.85 [marked price]]] ]
+           []
+</PRE>
+
+<P>Notice that the first input to <CODE>solve1</CODE> is a single variable,
+not a list of variables.  <CODE>Solve1</CODE> examines the first equation in the
+list of equations making up its fourth input.  The desired variable does not
+appear in this equation, so <CODE>solve1</CODE> rejects that equation and invokes
+itself recursively:
+
+<P><PRE>(4) solve1 [marked price]
+           [[dollars]]
+           []
+           [[equal [price of radio] [product 0.85 [marked price]]]]
+           [[equal [price of radio] [product 69.7 [dollars]]]]
+</PRE>
+
+<P>This time, the first (and now only) equation on the list of
+candidates does contain the desired variable.  <CODE>Solve1</CODE> removes that
+equation, not from its own list of equations (<CODE>:eqns</CODE>), but from <CODE>
+solve</CODE>'s overall list (<CODE>:eqt</CODE>).  The equation, unfortunately, can't be
+solved directly to express <CODE>[marked price]</CODE> in terms of <CODE>[dollars]</CODE>,
+because it contains the extra, unwanted variable <CODE>[price of radio]</CODE>.
+We must eliminate this variable by solving the remaining equations for it:
+
+<P><PRE>(5) solver [[price of radio]] [[marked price] [dollars]] [] []
+</PRE>
+
+<P>As before, <CODE>solver</CODE> picks the first (again, in this case, the
+only) wanted variable and asks <CODE>solve1</CODE> to solve it:
+
+<P><PRE>(6) solve1 [price of radio]
+           [[marked price] [dollars]]
+           []
+           [[equal [price of radio] [product 69.7 [dollars]]]]
+           []
+</PRE>
+
+<P><CODE>Solve1</CODE> does find the desired variable in the first (and
+only) equation, and this time there are no extra variables.  <CODE>Solve1</CODE>
+can therefore ask <CODE>solveq</CODE> to solve the equation:
+
+<P><PRE>(7) solveq [price of radio]
+           [equal [price of radio] [product 69.7 [dollars]]]
+</PRE>
+
+<P>It isn't part of <CODE>solveq</CODE>'s job to worry about which variables
+may or may not be part of the solution; <CODE>solve1</CODE> doesn't call <CODE>
+solveq</CODE> until it's satisfied that the equation is okay.
+
+<P>In this case, <CODE>solveq</CODE> has little work to do because the equation is
+already in the desired form, with the chosen variable alone on the left side
+and an expression not containing that variable on the right.
+
+<P><PRE>solveq (7) <EM>outputs</EM> [[price of radio] [product 69.7 [dollars]]
+           <EM>to</EM> solve1 (6)
+</PRE>
+
+<P><CODE>Solve1</CODE> appends this result to the previously empty
+association list.
+
+<P><PRE>solve1 (6) <EM>outputs</EM> [[[price of radio] [product 69.7 [dollars]]]
+           <EM>to</EM> solver (5)
+</PRE>
+
+<P><CODE>Solver</CODE> only had one variable in its <CODE>:wanted</CODE> list, so
+its job is also finished.
+
+<P><PRE>solver (5) <EM>outputs</EM> [[[price of radio] [product 69.7 [dollars]]]
+           <EM>to</EM> solve1 (4,3)
+</PRE>
+
+<P>This outer invocation of <CODE>solve1</CODE> was trying to solve for
+<CODE>[marked price]</CODE> an equation that also involved <CODE>[price of radio]</CODE>.
+It is now able to use the new association list to substitute for this
+unwanted variable an expression in terms of wanted variables only; this
+modified equation is then passed on to <CODE>solveq</CODE>:
+
+<P><PRE>(8) solveq [marked price]
+           [equal [product 69.7 [dollars]] [product 0.85 [marked price]]]
+</PRE>
+
+<P>This time <CODE>solveq</CODE> has to work a little harder, exchanging the
+two sides of the equation and dividing by 0.85.
+
+<P><PRE>solveq (8) <EM>outputs</EM> [[marked price] [product 82 [dollars]]]
+           <EM>to</EM> solve1 (4,3)
+</PRE>
+
+<P><CODE>Solve1</CODE> appends this result to the association list:
+
+<P><PRE>solve1 (4,3) <EM>outputs</EM> [[[price of radio] [product 69.7 [dollars]]]
+                      [[marked price] [product 82 [dollars]]] ]
+             <EM>to</EM> solver (2)
+</PRE>
+
+<P>Since <CODE>solver</CODE> has no other wanted variables, it outputs the
+same list to <CODE>solve</CODE>, and <CODE>solve</CODE> outputs the same list to <CODE>
+trysolve</CODE>.  (In this example, <CODE>solve.reduce</CODE> has no effect because all
+of the expressions in the association list are in terms of allowed units
+only.  If the equations had been different, the expression for <CODE>[price
+of radio]</CODE> might have included <CODE>[marked price]</CODE> and then <CODE>
+solve.reduce</CODE> would have had to substitute and simplify (<CODE>subord</CODE>).)
+
+<P>It'll probably take tracing a few more examples and beating your head
+against the wall a bit before you really understand the structure of <CODE>
+solve</CODE> and its subprocedures.  Again, don't get distracted by this part of
+the program until you've come to understand the language processing part,
+which is our main interest in this chapter.
+
+<P><H2>Age Problems</H2>
+
+<P>The main reason why Student treats age problems specially is that the
+English form of such problems is often expressed as if the variables were
+people, like &quot;Bill,&quot; whereas the real variable is &quot;Bill's age.&quot; The
+pattern matching transformations look for proper names (<CODE>personp</CODE>) and
+insert the words <CODE>s age</CODE> after them (<CODE>ageify</CODE>).  The first such age
+variable in the problem is remembered specially so that it can be
+substituted for pronouns (<CODE>agepron</CODE>).  A special case is the phrase <CODE>
+their ages</CODE>, which is replaced (<CODE>ageprob</CODE>) with a list of all the age
+variables in the problem.
+
+<P><PRE>? <U>student :uncle</U>
+
+The problem to be solved is
+
+Bill's father's uncle is twice as old as Bill's father. 2 years from now
+Bill's father will be 3 times as old as Bill. The sum of their ages is
+92 . Find Bill's age.
+
+
+With mandatory substitutions the problem is
+
+Bill s father s uncle is 2 times as old as Bill s father . 2 years
+from now Bill s father will be 3 times as old as Bill . sum their
+ages is 92 . Find Bill s age .
+
+
+The simple sentences are
+
+Bill s father s uncle s age is 2 times Bill s father s age .
+
+Bill s father s age pluss 2 is 3 times Bill s age pluss 2 .
+
+Sum Bill s age and Bill s father s age and Bill s father s uncle s age
+is 92 .
+
+Find Bill s age .
+
+
+The equations to be solved are
+
+Equal [Bill s father s uncle s age] [product 2 [Bill s father s age]]
+
+Equal [sum [Bill s father s age] 2] [product 3 [sum [Bill s age] 2]]
+
+Equal [sum [Bill s age]
+           [sum [Bill s father s age] [Bill s father s uncle s age]]] 92
+
+
+Bill s age is 8
+
+The problem is solved.
+</PRE>
+
+<P>(Note that in the original problem statement there is a space
+between the number <CODE>92</CODE> and the following period.  I had to enter the
+problem in that form because of an inflexibility in Logo's input parser,
+which assumes that a period right after a number is part of the number, so
+that &quot;<CODE>92.</CODE>&quot; is reformatted into <CODE>92</CODE> without the dot.)
+
+<P>Student represents the possessive word <CODE>Bill's</CODE> as the two words
+<CODE>Bill s</CODE> because this representation allows the pattern matcher to
+manipulate the possessive marker as a separate element to be matched.
+A phrase like <CODE>as old as</CODE> is just deleted (<CODE>ageprob</CODE>) because the
+transformation from people to ages makes it redundant.
+
+<P>The phrase <CODE>2 years from now</CODE> in the original problem is first
+translated to <CODE>in 2 years</CODE>.  This phrase is further processed according
+to where it appears in a sentence.  When it is attached to a particular
+variable, in a phrase like <CODE>Bill s age in 2 years</CODE>, the entire phrase is
+translated into the arithmetic operation <CODE>Bill s age pluss 2 years</CODE>
+(<CODE>agewhen</CODE>).  (The special word <CODE>pluss</CODE> is an addition operator,
+just like <CODE>plus</CODE>, except for its precedence; <CODE>opform</CODE> treats it as a
+tightly binding operation like <CODE>squared</CODE> instead of a loosely binding
+one like the ordinary <CODE>plus</CODE>.)  When a phrase like <CODE>in 2 years</CODE>
+appears at the beginning of a sentence, it is remembered (<CODE>agesen</CODE>) as
+an implicit modifier for <EM>every</EM> age variable in that sentence that
+isn't explicitly modified.  In this example, <CODE>in 2 years</CODE> modifies both
+<CODE>Bill s father s age</CODE> and <CODE>Bill s age</CODE>.  The special precedence of
+<CODE>pluss</CODE> is needed in this example so that the equation will be based on
+the grouping
+
+<P><PRE>3 times [ Bill s age pluss 2 ]
+</PRE>
+
+<P>rather than
+
+<P><PRE>[ 3 times Bill s age ] plus 2
+</PRE>
+
+<P>as it would be with the ordinary <CODE>plus</CODE> operator.  You can
+also see how the substitution for <CODE>their ages</CODE> works in this example.
+
+<P>Here is a second sample age problem that illustrates a different kind of
+special handling:
+
+<P><PRE>? <U>student :ann</U>
+
+The problem to be solved is
+
+Mary is twice as old as Ann was when Mary was as old as Ann is now. If
+Mary is 24 years old, how old is Ann?
+
+
+With mandatory substitutions the problem is
+
+Mary is 2 times as old as Ann was when Mary was as old as Ann is now . If
+Mary is 24 years old , what is Ann ?
+
+
+The simple sentences are
+
+Mary s age is 2 times Ann s age minuss g1 .
+
+Mary s age minuss g1 is Ann s age .
+
+Mary s age is 24 .
+
+What is Ann s age ?
+
+
+The equations to be solved are
+
+Equal [Mary s age] [product 2 [sum [Ann s age] [minus [g1]]]]
+
+Equal [sum [Mary s age] [minus [g1]]] [Ann s age]
+
+Equal [Mary s age] 24
+
+
+Ann s age is 18
+
+The problem is solved.
+</PRE>
+
+<P>What is new in this example is Student's handling of the phrase <CODE>was
+when</CODE> in the sentence
+
+<P><PRE>Mary is 2 times as old as Ann was when Mary was as old as Ann is now .
+</PRE>
+
+<P>Sentences like this one often cause trouble for human algebra students
+because they make <EM>implicit</EM> reference to a quantity that is not
+explicitly present as a variable.  The sentence says that Mary's age <EM>
+now</EM> is twice Ann's age <EM>some number</EM> of years ago, but that number
+is not explicit in the problem.  Student makes this variable explicit by
+using a <EM>generated symbol</EM> like the word <CODE>g1</CODE> in this illustration.
+Student replaces the phrase <CODE>was when</CODE> with the words
+
+<P><PRE>was g1 years ago . g1 years ago
+</PRE>
+
+<P>This substitution (in <CODE>ageprob</CODE>) happens <EM>before</EM> the
+division of the problem statement into simple sentences (<CODE>bracket</CODE>).  As
+a result, this one sentence in the original problem becomes the two sentences
+
+<P><PRE>Mary s age is 2 times Ann s age g1 years ago .
+
+G1 years ago Mary s age was Ann s age now .
+</PRE>
+
+<P>The phrase <CODE>g1 years ago</CODE> in each of these sentences is
+further processed by <CODE>agesen</CODE> and <CODE>agewhen</CODE> as discussed earlier;
+the final result is
+
+<P><PRE>Mary s age is 2 times Ann s age minuss g1 .
+
+Mary s age minuss g1 is Ann s age .
+</PRE>
+
+<P>A new generated symbol is created each time this situation arises,
+so there is no conflict from trying to use the same variable name for two
+different purposes.  The phrase <CODE>will be when</CODE> is handled similarly,
+except that the translated version is
+
+<P><PRE>in g2 years . in g2 years
+</PRE>
+
+<P><H2>AI and Education</H2>
+
+<BLOCKQUOTE>
+<P><A NAME="bobrow2">These decoupling heuristics</A> are useful
+not only for the Student program but
+for people trying to solve age problems.  The classic age problem about Mary
+and Ann, given above, took an MIT graduate student over 5 minutes to solve
+because he did not know this heuristic.  With the heuristic he was able to
+set up the appropriate equations much more rapidly.  As a crude measure of
+Student's relative speed, note that Student took less than one minute to
+solve this problem.
+</BLOCKQUOTE>
+
+<P>This excerpt from Bobrow's thesis illustrates the idea that
+insights from artificial intelligence research can make a valuable
+contribution to the education of human beings.  An intellectual problem is
+solved, at least in many cases, by dividing it into pieces and developing a
+technique for each subproblem.  The subproblems are the same whether it is a
+computer or a person trying to solve the problem.  If a certain technique
+proves valuable for the computer, it may be helpful for a human problem
+solver to be aware of the computer's methods.  Bobrow's suggestion to teach
+people one specific heuristic for algebra word problems is a relatively
+modest example of this general theme.  (A <EM>heuristic</EM> is a rule that
+gives the right answer most of the time, as opposed to an <EM>
+algorithm,</EM> a
+rule that always works.)  Some researchers in cognitive science and
+education have proposed the idea of <EM>intelligent CAI</EM>
+(computer assisted instruction), in which a computer would be programmed as a
+&quot;tutor&quot; that would observe the efforts of a student in solving a problem.
+The tutor would know about some of the mistaken ideas people can have about
+a particular class of problem and would notice a student falling into one
+of those traps.  It could then offer advice tailored to the needs of that
+individual student.
+
+<P>The development of the Logo programming language (and so also, indirectly,
+this series of books) is another example of the relationship between AI and
+education.  Part of the idea behind Logo is that the process of programming
+a computer resembles, in some ways, the process of teaching a person to do
+something.  (This can include teaching oneself.)  For example, when a
+computer program doesn't work, the experienced programmer doesn't give up in
+despair, but instead <EM>debugs</EM> the program.  Yet many students are
+willing to give up and say &quot;I just don't get it&quot; if their understanding of
+some problem isn't perfect on the first try.
+
+<BLOCKQUOTE>
+<P><A NAME="papert">The critic</A> is afraid
+that children will adopt the computer as model and
+eventually come to &quot;think mechanically&quot; themselves.  Following the
+opposite tack, I have invented ways to take educational advantage of the
+opportunities to master the art of <EM>deliberately</EM> thinking like a
+computer, according, for example, to the stereotype of a computer program
+that proceeds in a step-by-step, literal, mechanical fashion.  There are
+situations where this style of thinking is appropriate and useful.  Some
+children's difficulties in learning formal subjects such as grammar or
+mathematics derive from their inability to see the point of such a style.
+
+<P>
+A second educational advantage is indirect but ultimately more important.
+By deliberately learning to imitate mechanical thinking, the learner becomes
+able to articulate what mechanical thinking is and what it is not.  The
+exercise can lead to greater confidence about the ability to choose a
+cognitive style that suits the problem.  Analysis of &quot;mechanical thinking&quot;
+and how it is different from other kinds and practice with problem analysis
+can result in a new degree of intellectual sophistication.  By providing a
+very concrete, down-to-earth model of a particular style of thinking, work
+with the computer can make it easier to understand that there is such a
+thing as a &quot;style of thinking.&quot; And giving children the opportunity to
+choose one style or another provides an opportunity to develop the skill
+necessary to choose between styles.  Thus instead of inducing mechanical
+thinking, contact with computers could turn out to be the best conceivable
+antidote to it.  And for me what is most important in this is that through
+these experiences these children would be serving their apprenticeships as
+epistemologists, that is to say learning to think articulately about
+thinking.  [Seymour Papert, <EM>Mindstorms</EM>, Basic Books, 1980, p. 27.]
+</BLOCKQUOTE>
+
+<P><H2>Combining Sentences Into One Equation</H2>
+
+<P>In age problems, as we've just seen, a single sentence may give rise to two
+equations.  Here is an example of the opposite, several sentences that
+together contribute a single equation.
+
+<P><PRE>? <U>student :nums</U>
+
+The problem to be solved is
+
+A number is multiplied by 6 . This product is increased by 44 . This
+result is 68 . Find the number.
+
+
+With mandatory substitutions the problem is
+
+A number ismulby 6 . This product is increased by 44 . This result is
+68 . Find the number .
+
+
+The simple sentences are
+
+A number ismulby 6 .
+
+This product is increased by 44 .
+
+This result is 68 .
+
+Find the number .
+
+
+The equations to be solved are
+
+Equal [sum [product [number] 6] 44] 68
+
+
+The number is 4
+
+The problem is solved.
+</PRE>
+
+<P>Student recognizes problems like this by recognizing the phrases &quot;is
+multiplied by,&quot; &quot;is divided by,&quot; and &quot;is increased by&quot; (<CODE>senform1</CODE>).
+A sentence containing one of these phrases is not translated into an
+equation; instead, a <EM>partial</EM> equation is saved until the next
+sentence is read.  That next sentence is expected to start with a phrase
+like &quot;this result&quot; or &quot;this product.&quot; The same procedure (<CODE>this</CODE>)
+that in other situations uses the left hand side of the last equation as the
+expression for the <CODE>this</CODE>-phrase notices that there is a remembered
+partial equation and uses that instead.  In this example, the sentence
+
+<P><PRE>A number ismulby 6 .
+</PRE>
+
+<P>remembers the algebraic expression
+
+<P><PRE>[product [number] 6]
+</PRE>
+
+<P>The second sentence uses that remembered expression as part of a
+new, larger expression to be remembered:
+
+<P><PRE>[sum [product [number] 6] 44]
+</PRE>
+
+<P>The third sentence does not contain one of the special &quot;is
+increased by&quot; phrases, but is instead a standard &quot;A is B&quot; sentence.
+That sentence, therefore, does give rise to an equation, as shown above.
+
+<P>Perhaps the most interesting thing to notice about this category of word
+problem is how narrowly defined Student's criterion for recognizing the
+category is.  Student gets away with it because algebra word problems are
+highly <EM>stereotyped;</EM> there are just a few categories, with
+traditional, standard wordings.  In principle there could be a word problem
+starting
+
+<P><PRE>Robert has a certain number of jelly beans.  This number is twice the
+number of jelly beans Linda has.
+</PRE>
+
+<P>These two sentences are together equivalent to
+
+<P><PRE>The number of jelly beans Robert has is twice the number of jelly beans
+Linda has.
+</PRE>
+
+<P>But Student would not recognize the situation because the first
+sentence doesn't talk about &quot;is increased by.&quot; We could teach Student to
+understand a word problem in this form by adding the instruction
+
+<P><PRE>if match [^one !verb1:verb a certain number of #stuff1 !:dlm] :sent
+    [push &quot;ref opform (se [the number of] :stuff1 :one :verb1)
+     op []]
+</PRE>
+
+<P>along with the other known sentence forms in <CODE>senform1</CODE>.
+(Compare this to the pattern matching instruction shown earlier for a
+similar sentence but with an explicitly specified number.)
+
+<P>Taking advantage of the stereotyped nature of word problems is an example of
+how the microworld strategy helped make the early AI programs possible.  If
+word problems were expressed with all the flexibility of language in general,
+Student would need many more sentence patterns than it actually has.  (How
+many different ways can you think of to express the same idea about Robert
+and Linda?  How many of those ways can Student handle?)
+
+<P><H2>Allowing Flexible Phrasing</H2>
+
+<P>In the examples we've seen so far, Student has relied on the repetition of
+identical or near-identical phrases such as &quot;the marked price&quot; or &quot;the
+number of advertisements he runs.&quot; (The requirement is not quite strictly
+identical phrases because articles are removed from the noun phrases to make
+variable names.)  In real writing, though, such phrases are often
+abbreviated when they appear for a second time.  Student will translate such
+a problem into a system of equations that can't be solved, because what
+should be one variable is instead a different variable in each equation.
+But Student can recognize this situation and apply heuristic rules to guess
+that two similar variable names are meant, in fact, to represent the same
+variable.  (Some early writers on AI considered the use of heuristic methods
+one of the defining characteristics of the field.  Computer scientists
+outside of AI were more likely to insist on fully reliable algorithms.  This
+distinction still has some truth to it, but it isn't emphasized so much as a
+critical issue these days.)  Student doesn't try to equate different
+variables until it has first tried to solve the equations as they are
+originally generated.  If the first attempt at solution fails, Student has
+recourse to less certain techniques (<CODE>student2</CODE> calls <CODE>vartest</CODE>).
+
+<P><PRE>? <U>student :sally</U>
+
+The problem to be solved is
+
+The sum of Sally's share of some money and Frank's share is 4.50.
+Sally's share is twice Frank's. Find Frank's and Sally's share.
+
+
+With mandatory substitutions the problem is
+
+sum Sally s share numof some money and Frank s share is 4.50 dollars .
+Sally s share is 2 times Frank s . Find Frank s and Sally s share .
+
+
+The simple sentences are
+
+Sum Sally s share numof some money and Frank s share is 4.50 dollars .
+
+Sally s share is 2 times Frank s .
+
+Find Frank s and Sally s share .
+
+
+The equations to be solved are
+
+Equal [sum [Sally s share of some money] [Frank s share]]
+      [product 4.50 [dollars]]
+
+Equal [Sally s share] [product 2 [Frank s]]
+
+
+The equations were insufficient to find a solution.
+
+Assuming that
+[Frank s] is equal to [Frank s share]
+
+Assuming that
+[Sally s share] is equal to [Sally s share of some money]
+
+Frank s is 1.5 dollars
+
+Sally s share is 3 dollars
+
+The problem is solved.
+</PRE>
+
+<P>In this problem Student has found two pairs of similar variable names.
+When it finds such a pair, Student adds an equation of the form
+
+<P><PRE>[equal <EM>variable1</EM> <EM>variable2</EM>]
+</PRE>
+
+<P>to the previous set of equations.  In both of the pairs in this
+example, the variable that appears later in the problem statement is
+entirely contained within the one that appears earlier.
+
+<P>Another point of interest in this example is that the variable <CODE>[dollars]</CODE>
+is included in the list of units that may be part of the answer.  The word
+problem does not explicitly ask &quot;How many dollars is Sally's share,&quot; but
+because one of the sentences sets an expression equal to &quot;4.50 dollars&quot;
+Student takes that as implicit permission to express the answer in dollars.
+
+<P>The only other condition under which Student will consider two variables
+equal is if their names are identical except that some phrase in the one
+that appears earlier is replaced with a pronoun in the one that appears
+later.  That is, a variable like <CODE>[the number of ice cream cones the
+children eat]</CODE> will be considered equal to a later variable <CODE>[the number
+of ice cream cones they eat]</CODE>.  Here is a problem in which this rule is
+applied:
+
+<P><PRE>? <U>student :guns</U>
+
+The problem to be solved is
+
+The number of soldiers the Russians have is one half of the number of
+guns they have. They have 7000 guns. How many soldiers do they have?
+
+
+With mandatory substitutions the problem is
+
+The number numof soldiers the Russians have is 0.5 numof the number numof
+guns they have . They have 7000 guns . howm soldiers do they have ?
+
+
+The simple sentences are
+
+The number numof soldiers the Russians have is 0.5 numof the number numof
+guns they have .
+
+They have 7000 guns .
+
+Howm soldiers do they have ?
+
+
+The equations to be solved are
+
+Equal [number of soldiers Russians have]
+      [product 0.5 [number of guns they have]]
+
+Equal [number of guns they have] 7000
+
+
+The equations were insufficient to find a solution.
+
+Assuming that
+[number of soldiers they have] is equal to
+  [number of soldiers Russians have]
+
+The number of soldiers they have is 3500
+
+The problem is solved.
+</PRE>
+
+<P><H2>Using Background Knowledge</H2>
+
+<P>In some word problems, not all of the necessary information is contained
+within the problem statement itself.  The problem requires the student to
+supply some piece of general knowledge about the world in order to determine
+the appropriate equations.  This knowledge may be about unit conversions
+(one foot is 12 inches) or about relationships among physical quantities
+(distance equals speed times time).  Student &quot;knows&quot; some of this <EM>
+background</EM> information and can apply it (<CODE>geteqns</CODE>) if the equations
+determined by the problem statement are insufficient.
+
+<P><PRE>? <U>student :jet</U>
+
+The problem to be solved is
+
+The distance from New York to Los Angeles is 3000 miles. If the average
+speed of a jet plane is 600 miles per hour, find the time it takes to
+travel from New York to Los Angeles by jet.
+
+
+With mandatory substitutions the problem is
+
+The distance from New York to Los Angeles is 3000 miles . If the average
+speed numof a jet plane is 600 miles per hour , find the time it takes to
+travel from New York to Los Angeles by jet .
+
+
+The simple sentences are
+
+The distance from New York to Los Angeles is 3000 miles .
+
+The average speed numof a jet plane is 600 miles per hour .
+
+Find the time it takes to travel from New York to Los Angeles by jet .
+
+
+The equations to be solved are
+
+Equal [distance from New York to Los Angeles] [product 3000 [miles]]
+
+Equal [average speed of jet plane]
+      [quotient [product 600 [miles]] [product 1 [hours]]]
+
+
+The equations were insufficient to find a solution.
+
+Using the following known relationships
+
+Equal [distance] [product [speed] [time]]
+
+Equal [distance] [product [gas consumption]
+                          [number of gallons of gas used]]
+
+
+Assuming that
+[speed] is equal to [average speed of jet plane]
+
+Assuming that
+[time] is equal to [time it takes to travel
+                    from New York to Los Angeles by jet]
+
+Assuming that
+[distance] is equal to [distance from New York to Los Angeles]
+
+The time it takes to travel from New York
+  to Los Angeles by jet is 5 hours
+
+The problem is solved.
+</PRE>
+
+<P>Student's library of known relationships is indexed according to the first
+word of the name of each variable involved in the relationship.  (If a
+variable starts with the words <CODE>number of</CODE> it is indexed under the
+following word.)  The relationships, in the form of equations, are stored in
+the property lists of these index words.
+
+<P>Property lists are also used to keep track of irregular plurals and the
+corresponding singulars.  Student tries to keep all units in plural form
+internally, so that if a problem refers to both <CODE>1 foot</CODE> and <CODE>
+2 feet</CODE> the same variable name will be used for both.  (That is, the first
+of these will be translated into
+
+<P><PRE>[product 1 [feet]]
+</PRE>
+
+<P>in Student's internal representation.  Then the opposite
+translation is needed if the product of <CODE>1</CODE> and some unit appears in an
+answer to be printed.
+
+<P>The original Student also used property lists to remember the parts of
+speech of words and the precedence of operators, but because of differences
+in the syntax of the Meteor pattern matcher and my Logo pattern matcher I've
+found it easier to use predicate operations for that purpose.
+
+<P>The original Student system included a separately invoked <CODE>remember</CODE>
+procedure that allowed all these kinds of global information to be entered
+in the form of English sentences.  You'd say
+
+<P><PRE>Feet is the plural of foot
+</PRE>
+
+<P>or
+
+<P><PRE>Distance equals speed times time
+</PRE>
+
+<P>and <CODE>remember</CODE> would use patterns much like those used in
+understanding word problems to translate these sentences into <CODE>pprop</CODE>
+instructions.  Since Lisp programs, like Logo programs, can themselves be
+manipulated as lists, <CODE>remember</CODE> could even accept information of a
+kind that's stored in
+the Student program itself, such as the wording transformations in <CODE>
+idioms</CODE>, and modify the program to reflect this information.  I haven't
+bothered to implement that part of the Student system because it takes up
+extra memory and doesn't exhibit any new techniques.
+
+<P>As the above example shows, it's important that Student's search for
+relevant known relationships comes before the attempt to equate variables
+with similar names.  The general relationship that uses a variable named
+simply <CODE>[distance]</CODE> doesn't help unless Student can identify it as
+relevant to the variable named <CODE>[distance from New York to Los Angeles]</CODE>
+in the specific problem under consideration.
+
+<P>Here is another example in which known relationships are used:
+
+<P><PRE>? <U>student :span</U>
+
+The problem to be solved is
+
+If 1 span is 9 inches, and 1 fathom is 6 feet,
+  how many spans is 1 fathom?
+
+
+With mandatory substitutions the problem is
+
+If 1 span is 9 inches , and 1 fathom is 6 feet , howm spans is 1 fathom ?
+
+
+The simple sentences are
+
+1 span is 9 inches .
+
+1 fathom is 6 feet .
+
+Howm spans is 1 fathom ?
+
+
+The equations to be solved are
+
+Equal [product 1 [spans]] [product 9 [inches]]
+
+Equal [product 1 [fathoms]] [product 6 [feet]]
+
+Equal g2 [product 1 [fathoms]]
+
+
+The equations were insufficient to find a solution.
+
+Using the following known relationships
+
+Equal [product 1 [yards]] [product 3 [feet]]
+
+Equal [product 1 [feet]] [product 12 [inches]]
+
+
+1 fathom is 8 spans
+
+The problem is solved.
+</PRE>
+
+<P>Besides the use of known relationships, this example illustrates two other
+features of Student.  One is the use of an explicitly requested unit in the
+answer.  Since the problem asks
+
+<P><PRE>How many spans is 1 fathom?
+</PRE>
+
+<P>Student knows that the answer must be expressed in <CODE>spans</CODE>.
+Had there been no explicit request for a particular unit, all the units that
+appear in phrases along with a number would be eligible to appear in the
+answer: <CODE>inches</CODE>, <CODE>feet</CODE>, and <CODE>fathoms</CODE>.  Student might then
+blithely inform us that
+
+<P><PRE>1 fathom is 1 fathom
+
+The problem is solved.
+</PRE>
+
+<P>The other new feature demonstrated by this example is the use of a generated
+symbol to represent the desired answer.  In the statement of this problem,
+there is no explicit variable representing the unknown.  <CODE>[Fathoms]</CODE> is
+a <EM>unit,</EM> not a variable for which a value could be found.  The problem
+asks for the value of the expression
+
+<P><PRE>[product 1 [fathoms]]
+</PRE>
+
+<P>in terms of spans.  Student generates a variable name (<CODE>g2</CODE>)
+to represent the unknown and produces an equation
+
+<P><PRE>[equal g2 [product 1 [fathoms]]
+</PRE>
+
+<P>to add to the list of equations.  A generated symbol will be
+needed whenever the &quot;Find&quot; or &quot;What is&quot; sentence asks for an expression
+rather than a simple variable name.  For example, an age problem that asks
+&quot;What is the sum of their ages&quot; would require the use of a generated
+symbol.  (The original Student <EM>always</EM> used a generated symbol for
+the unknowns, even if there was already a single variable in the problem
+representing an unknown.  It therefore had equations like
+
+<P><PRE>[equal g3 [marked price]]
+</PRE>
+
+<P>in its list, declaring one variable equal to another.  I chose to
+check for this case and avoid the use of a generated symbol because the time
+spent in the actual solution of the equations increases quadratically with
+the number of equations.)
+
+<P><H2>Optional Substitutions</H2>
+
+<P>We have seen many cases in which Student replaces a phrase in the statement
+of a problem with a different word or phrase that fits better with the later
+stages of processing, like the substitution of <CODE>2 times</CODE> for <CODE>twice</CODE>
+or a special keyword like <CODE>perless</CODE> for <CODE>percent less than</CODE>.
+Student also has a few cases of <EM>optional</EM> substitutions that may or
+may not be made (<CODE>tryidiom</CODE>).
+
+<P>There are two ways in which optional substitutions can happen.  One is
+exemplified by the phrase <CODE>the perimeter of the rectangle</CODE>.  Student
+first attempts the problem without any special processing of this phrase.
+If a solution is not found, Student then replaces the phrase with <CODE>twice
+the sum of the length and width of the rectangle</CODE> and processes the
+resulting new problem from the beginning.  Unlike the use of known
+relationships or similarity of variable names, which Student handles by
+adding to the already-determined equations, this optional substitution
+requires the entire translation process to begin again.  For example, the
+word <CODE>twice</CODE> that begins the replacement phrase will be further
+translated to <CODE>2 times</CODE>.
+
+<P>The second category of optional substitution is triggered by the phrase <CODE>
+two numbers</CODE>.  This phrase must always be translated to something, because
+it indicates that two different variables are needed.  But the precise
+translation depends on the wording of the rest of the problem.  Student
+tries two alternative translations: <CODE>one of the numbers and the other
+number</CODE> and <CODE>one number and the other number</CODE>.  Here is an example in
+which the necessary translation is the one Student tries second:
+
+<P><PRE>? <U>student :sumtwo</U>
+
+The problem to be solved is
+
+The sum of two numbers is 96, and one number is 16 larger than the other
+number. Find the two numbers.
+
+
+The problem with an idiomatic substitution is
+
+The sum of one of the numbers and the other number is 96 , and one
+number is16 larger than the other number . Find the one of the numbers
+and the other number .
+
+
+With mandatory substitutions the problem is
+
+sum one numof the numbers and the other number is 96 , and one number
+is 16 plus the other number . Find the one numof the numbers and the
+other number .
+
+
+The simple sentences are
+
+Sum one numof the numbers and the other number is 96 .
+
+One number is 16 plus the other number .
+
+Find the one numof the numbers and the other number .
+
+
+The equations to be solved are
+
+Equal [sum [one of numbers] [other number]] 96
+
+Equal [one number] [sum 16 [other number]]
+
+
+The equations were insufficient to find a solution.
+
+The problem with an idiomatic substitution is
+
+The sum of one number and the other number is 96 , and one number is 16
+larger than the other number . Find the one number and the other number .
+
+
+With mandatory substitutions the problem is
+
+sum one number and the other number is 96 , and one number is 16 plus the
+other number . Find the one number and the other number .
+
+
+The simple sentences are
+
+Sum one number and the other number is 96 .
+
+One number is 16 plus the other number .
+
+Find the one number and the other number .
+
+
+The equations to be solved are
+
+Equal [sum [one number] [other number]] 96
+
+Equal [one number] [sum 16 [other number]]
+
+
+The one number is 56
+
+The other number is 40
+
+The problem is solved.
+</PRE>
+
+<P>There is no essential reason why Student uses one mechanism rather than
+another to deal with a particular problematic situation.  The difficulties
+about perimeters and about the phrase &quot;two numbers&quot; might have been solved
+using mechanisms other than this optional substitution one.  For example,
+the equation
+
+<P><PRE>[equal [perimeter] [product 2 [sum [length] [width]]]]
+</PRE>
+
+<P>might have been added to the library of known relationships.  The
+difficulty about alternate phrasings for &quot;two numbers&quot; could be solved by
+adding
+
+<P><PRE>[[one of the !word:pluralp] [&quot;one singular :word]]
+</PRE>
+
+<P>to the list of idiomatic substitutions in <CODE>idiom</CODE>.
+
+<P>Not all the mechanisms are equivalent, however.  The &quot;two numbers&quot; problem
+couldn't be solved by adding equations to the library of known relationships,
+because that phrase appears as part of a larger phrase like &quot;the sum of two
+numbers,&quot; and Student's understanding of the word <CODE>sum</CODE> doesn't allow
+it to be part of a variable name.  The word <CODE>sum</CODE> only makes sense to
+Student in the context of a phrase like <CODE>the sum of <CODE><EM>
+something</EM></CODE> and <CODE><EM>something else</EM></CODE></CODE>.  (See procedure <CODE>tst.sum</CODE>.)
+
+<P><H2>If All Else Fails</H2>
+
+<P>Sometimes Student fails to solve a problem because the problem is beyond
+either its linguistic capability or its algebraic capability.  For example,
+Student doesn't know how to solve quadratic equations.  But sometimes a
+problem that Student could solve in principle stumps it because it happens
+to lack a particular piece of common knowledge.  When a situation like that
+arises, Student is capable of asking the user for help (<CODE>student2</CODE>).
+
+<P><PRE>? <U>student :ship</U>
+
+The problem to be solved is
+
+The gross weight of a ship is 20000 tons. If its net weight is 15000
+tons, what is the weight of the ships cargo?
+
+
+With mandatory substitutions the problem is
+
+The gross weight numof a ship is 20000 tons . If its net weight is 15000
+tons , what is the weight numof the ships cargo ?
+
+
+The simple sentences are
+
+The gross weight numof a ship is 20000 tons .
+
+Its net weight is 15000 tons .
+
+What is the weight numof the ships cargo ?
+
+
+The equations to be solved are
+
+Equal [gross weight of ship] [product 20000 [tons]]
+
+Equal [its net weight] [product 15000 [tons]]
+
+
+The equations were insufficient to find a solution.
+
+Do you know any more relationships among these variables?
+
+Weight of ships cargo
+
+Its net weight
+
+Tons
+
+Gross weight of ship
+
+<U>The weight of a ships cargo is the gross weight minus the net weight</U>
+
+Assuming that
+[net weight] is equal to [its net weight]
+
+Assuming that
+[gross weight] is equal to [gross weight of ship]
+
+The weight of the ships cargo is 5000 tons
+
+The problem is solved.
+</PRE>
+
+<P><H2>Limitations of Pattern Matching</H2>
+
+
+<P>Student relies on certain stereotyped forms of sentences in the problems it
+solves.  It's easy to make up problems that will completely bewilder it:
+
+<P><PRE>Suppose you have 14 jelly beans.  You give 2 each to Tom, Dick, and
+Harry.  How many do you have left?
+</PRE>
+
+<P>The first mistake Student makes is that it thinks the word <CODE>
+and</CODE> following a comma separates two clauses; it generates simple sentences
+
+<P><PRE>You give 2 each to Tom , Dick .
+
+Harry .
+</PRE>
+
+<P>This is quite a fundamental problem; Student's understanding of
+the difference between a phrase and a clause is extremely primitive and
+prone to error.  Adding another pattern won't solve this one; the trouble
+is that Student pays no attention to the words in between the key words like
+<CODE>and</CODE>.
+
+<P>There are several other difficulties with this problem, some worse than
+others.  Student doesn't recognize the word <CODE>suppose</CODE> as having a
+special function in the sentence, so it makes up a noun phrase <CODE>suppose
+you</CODE> just like <CODE>the russians</CODE>.  This could be fixed with an idiomatic
+substitution that just ignored <CODE>suppose</CODE>.  Another relatively small
+problem is that the sentence starting <CODE>how many</CODE> doesn't say how many of
+what; Student needs a way to understand that the relevant noun phrase is
+<CODE>jelly beans</CODE> and not, for example, <CODE>Tom</CODE>.  The words <CODE>give</CODE>
+(representing subtraction) and <CODE>each</CODE> (representing counting a set and
+then multiplying) have special mathematical meanings comparable to <CODE>
+percent less</CODE>.  A much more subtle problem
+in knowledge representation is
+that in this problem there are two different quantities that could be called
+<CODE>the number of jelly beans you have</CODE>: the number you have at the
+beginning of the problem and the number you have at the end.  Student has a
+limited understanding of this passage-of-time difficulty when it's doing an
+age problem, but not in general.
+
+<P>How many more difficulties can you find in this problem?  For how many of
+them can you invent improvements to Student to get around them?
+
+<P>Some difficulties seem to require a &quot;more of the same&quot; strategy: adding
+some new patterns to Student that are similar to the ones already there.
+Other difficulties seem to require a more fundamental redesign.  Can that
+redesign be done using a pattern matcher as the central tool, or are more
+powerful tools needed?  How powerful <EM>is</EM> pattern matching, anyway?
+
+<P>Answering questions like these is the job of automata theory.  From that
+point of view, the answer is that it depends exactly what you mean by
+&quot;pattern matching.&quot;  The pattern matcher used in Student is equivalent
+to a finite-state machine.  The important thing to note about the patterns
+used in Student is that they only apply predicates to one word at a time,
+not to groups of words.  In other words, they don't use the <CODE>@</CODE>
+quantifier.  Here is a typical <CODE>student</CODE> pattern:
+
+<P><PRE>[^ what !:in [is are] #one !:dlm]
+</PRE>
+
+<P>For the purposes of this discussion, you can ignore the fact that
+the pattern matcher can set variables to remember which words matched each
+part of the pattern.  In comparing a pattern matcher to a finite-state
+machine, the question we're asking is what categories of strings can the
+pattern matcher accept.  This particular pattern is equivalent to the
+following machine:
+
+<P><CENTER><IMG SRC="pattern.gif" ALT="figure: pattern"></CENTER>
+
+<P>The arrow that I've labeled <EM>dlm</EM> is actually several arrows
+connecting the same states, one for each symbol that the predicate <CODE>dlm</CODE>
+accepts, i.e., period, question mark, and semicolon.  Similarly, the arrows
+labeled <EM>any</EM> are followed for any symbol at all.  This machine is
+nondeterministic, but you'll recall that that doesn't matter; we can turn it
+into a deterministic one if necessary.
+
+<P>To be sure you understand the equivalence of patterns and finite-state
+machines, see if you can draw a machine equivalent to this pattern:
+
+<P><PRE>[I see !:in [the a an] ?:numberp &amp;:adjective !:noun #:adverb]
+</PRE>
+
+<P>This pattern uses all the quantifiers that test words one at a
+time.
+
+<P>If these patterns are equivalent to finite-state machines, you'd expect them
+to have trouble recognizing sentences that involve <EM>embedding</EM> of
+clauses within clauses, since these pose the same problem as keeping track
+of balancing of parentheses.  For example, a sentence like &quot;The book that
+the boy whom I saw yesterday was reading is interesting&quot; would strain the
+capabilities of a finite-state machine.  (As in the case of parentheses, we
+could design a FSM that could handle such sentences up to some fixed depth
+of embedding, but not one that could handle arbitrarily deep embedding.)
+
+<P><H2>Context-Free Languages</H2>
+
+
+<P>If we allow the use of the <CODE>@</CODE> quantifier in patterns, and if the
+predicates used to test substrings of the sentences are true functions
+without side effects, then the pattern matcher is equivalent to an RTN or a
+production rule grammar.  What makes an RTN different from a finite-state
+machine is that the former can include arrows that match several symbols
+against another (or the same) RTN.  Equivalently, the <CODE>@</CODE> quantifier
+matches several symbols against another (or the same) pattern.
+
+<P>A language that can be represented by an RTN is called a <EM>
+context-free</EM> language.  The reason for the name is that in such a
+language a given string consistently matches or doesn't match a given
+predicate regardless of the rest of the sentence.  That's the point of what
+I said just above about side effects; the output from a test predicate
+can't depend on anything other than its input.  Pascal is a context-free
+language because
+
+<P><PRE>this := that
+</PRE>
+
+<P>is always an assignment statement regardless of what other statements
+might be in the program with it.
+
+<P>What <EM>isn't</EM> a context-free language?  The classic example in automata
+theory is the language consisting of the strings
+
+<P><PRE>abc
+aabbcc
+aaabbbccc
+aaaabbbbcccc
+</PRE>
+
+<P>and so on, with the requirement that the number of <CODE>a</CODE>s be
+equal to the number of <CODE>b</CODE>s and also equal to the number of <CODE>c</CODE>s.
+That language can't be represented as RTNs or production rules.  (Try it.
+Don't confuse it with the language that accepts any number of <CODE>a</CODE>s
+followed by any number of <CODE>b</CODE>s and so on; even a finite-state machine
+can represent that one.  The equal number requirement is important.)
+
+<P>The classic formal system that can represent <EM>any</EM> language for which
+there are precise rules is the Turing machine.  Its advantage over
+the RTN is precisely that it can &quot;jump around&quot; in its memory, looking at
+one part while making decisions about another part.
+
+<P>There is a sharp theoretical boundary between context-free and
+context-sensitive languages, but in practice the boundary is sometimes fuzzy.
+Consider again the case of Pascal and that assignment statement.  I said
+that it's recognizably an assignment statement because it matches a
+production rule like
+
+<P><PRE>assignment    :  identifier := expression
+</PRE>
+
+<P>(along with a bunch of other rules that determine what qualifies
+as an expression).  But that production rule doesn't really express <EM>
+all</EM> the requirements for a legal Pascal assignment statement.  For
+example, the identifier and the expression must be of the same type.  The
+actual Pascal compiler (any Pascal compiler, not just mine) includes
+instructions that represent the formal grammar plus extra instructions that
+represent the additional requirements.
+
+<P>The type agreement rule is an example of context sensitivity.  The types of
+the relevant identifiers were determined in <CODE>var</CODE> declarations earlier
+in the program; those declarations are part of what determines whether the
+given string of symbols is a legal assignment.
+
+<P><H2>Augmented Transition Networks</H2>
+
+<P>One could create a clean formal description of Pascal, type agreement rules
+and all, by designing a Turing machine to accept Pascal programs.  However,
+Turing machines aren't easy to work with for any practical problem.  It's
+much easier to set up a context-free grammar for Pascal and then throw in a
+few side effects to handle the context-sensitive aspects of the language.
+
+<P>Much the same is true of English.  It's possible to set up an RTN (or a
+production rule grammar) for noun phrases, for example, and another one for
+verb phrases.  It's tempting then to set up an RTN for a sentence like this:
+
+<P><CENTER><IMG SRC="sentence.gif" ALT="figure: sentence"></CENTER>
+
+<P>This machine captures some, but not all, of the rules of English.
+It's true that a sentence requires a noun phrase (the subject) and a verb
+phrase (the predicate).  But there are <EM>agreement</EM> rules for person
+and number (I <EM>run</EM> but he <EM>runs</EM>) analogous to the type
+agreement rules of Pascal.
+
+<P>Some artificial intelligence researchers, understanding all this, parse
+English sentences using a formal description called an <EM>
+augmented transition network</EM> (ATN).  An ATN is just
+like an RTN except
+that each transition arrow can have associated with it not only the name of
+a symbol or another RTN but also some <EM>conditions</EM> that must be met in
+order to follow the arrow and some <EM>actions</EM> that the program should
+take if the arrow is followed.  For example, we could turn the RTN just
+above into an ATN by adding an action to the first arrow saying &quot;store the
+number (singular or plural) of the noun phrase in the variable <CODE>
+number</CODE>&quot; and adding a condition to the second arrow saying &quot;the number of
+the verb phrase must be equal to the variable <CODE>number</CODE>.&quot;
+
+<P>Subject-predicate agreement is not the only rule in English grammar best
+expressed as a side effect in a transition network.  Below is an ATN
+for noun phrases taken from <EM>Language as a Cognitive Process, Volume 1:
+Syntax</EM> by Terry Winograd (page 598).  I'm not going to attempt to explain
+the notation or the detailed rules here, but just to give one example, the
+condition labeled &quot;h16p&quot; says that the transition for apostrophe-s can be
+followed if the head of the phrase is an ordinary noun (&quot;the book's&quot;) but
+not if it's a pronoun (&quot;you's&quot;).
+
+<P>
+<CENTER><A NAME="winograd"><IMG SRC="atn.gif" ALT="figure: atn"></A></CENTER>
+
+<P>The ATN is equivalent in power to a Turing machine; there is no known
+mechanism that is more flexible in carrying out algorithms.  The flexibility
+has a cost, though.  The time required to parse a string with an ATN is not
+bounded by a polynomial function.  (Remember, the time for an RTN is
+O(<EM>n</EM><SUP><SMALL>3</SMALL></SUP>).)  It can easily be exponential, O(2<SUP><SMALL><EM>n</EM></SMALL></SUP>).  One reason is that a
+context-sensitive procedure can't be subject to memoization.  If two
+invocations of the same procedure with the same inputs can give different
+results because of side effects, it does no good to remember what result we
+got the last time.  Turning an ATN into a practical program is often
+possible, but not a trivial task.
+
+<P>In thinking about ATNs we've brought together most of the topics in this
+book: formal systems, algorithms, language parsing, and artificial
+intelligence.  Perhaps that's a good place to stop.
+
+<P>
+<TABLE width="100%"><TR><TD><A HREF="../v3-toc2.html">(back to Table of Contents)</A>
+<TD align="right"><A HREF="../v3ch5/v3ch5.html"><STRONG>BACK</STRONG></A>
+chapter thread <A HREF="https://people.eecs.berkeley.edu/~bh/v3ch7/v3ch7.html"><STRONG>NEXT</STRONG></A>
+</TABLE>
+
+<H2>Program Listing</H2>
+
+<P><PRE>
+to student :prob
+say [The problem to be solved is] :prob
+make "prob map.se [depunct ?] :prob
+localmake "orgprob :prob
+student1 :prob ~
+         [[[the perimeter of ! rectangle]
+           [twice the sum of the length and width of the rectangle]]
+          [[two numbers] [one of the numbers and the other number]]
+          [[two numbers] [one number and the other number]]]
+end
+
+to student1 :prob :idioms
+local [simsen shelf aunits units wanted ans var lasteqn
+       ref eqt1 beg end idiom reply]
+make "prob idioms :prob
+if match [^ two numbers #] :prob ~
+   [make "idiom find [match (sentence "^beg first ? "#end) :orgprob] :idioms ~
+    tryidiom stop]
+while [match [^beg the the #end] :prob] [make "prob (sentence :beg "the :end)]
+say [With mandatory substitutions the problem is] :prob
+ifelse match [# @:in [[as old as] [age] [years old]] #] :prob ~
+       [ageprob] [make "simsen bracket :prob]
+lsay [The simple sentences are] :simsen
+foreach [aunits wanted ans var lasteqn ref units] [make ? []]
+make "shelf filter [not emptyp ?] map.se [senform ?] :simsen
+lsay [The equations to be solved are] :shelf
+make "units remdup :units
+if trysolve :shelf :wanted :units :aunits [print [The problem is solved.] stop]
+make "eqt1 remdup geteqns :var
+if not emptyp :eqt1 [lsay [Using the following known relationships] :eqt1]
+student2 :eqt1
+end
+
+to student2 :eqt1
+make "var remdup sentence (map.se [varterms ?] :eqt1) :var
+make "eqt1 sentence :eqt1 vartest :var
+if not emptyp :eqt1 ~
+   [if trysolve (sentence :shelf :eqt1) :wanted :units :aunits
+       [print [The problem is solved.] stop]]
+make "idiom find [match (sentence "^beg first ? "#end) :orgprob] :idioms
+if not emptyp :idiom [tryidiom stop]
+lsay [Do you know any more relationships among these variables?] :var
+make "reply readlist
+if equalp :reply [yes] [print [Tell me.] make "reply readlist]
+if equalp :reply [no] [print [] print [I can't solve this problem.] stop]
+make "reply map.se [depunct ?] :reply
+if dlm last :reply [make "reply butlast :reply]
+if not match [^beg is #end] :reply [print [I don't understand that.] stop]
+make "shelf sentence :shelf :eqt1
+student2 (list (list "equal opform :beg opform :end))
+end
+
+;; Mandatory substitutions
+
+to depunct :word
+if emptyp :word [output []]
+if equalp first :word "$ [output sentence "$ depunct butfirst :word]
+if equalp last :word "% [output sentence depunct butlast :word "percent]
+if memberp last :word [. ? |;| ,] [output sentence depunct butlast :word last :word]
+if emptyp butfirst :word [output :word]
+if equalp last2 :word "'s [output sentence depunct butlast butlast :word "s]
+output :word
+end
+
+to last2 :word
+output word (last butlast :word) (last :word)
+end
+
+to idioms :sent
+local "number
+output changes :sent ~
+    [[[the sum of] ["sum]] [[square of] ["square]] [[of] ["numof]]
+     [[how old] ["what]] [[is equal to] ["is]]
+     [[years younger than] [[less than]]] [[years older than] ["plus]]
+     [[percent less than] ["perless]] [[less than] ["lessthan]]
+     [[these] ["the]] [[more than] ["plus]]
+     [[first two numbers] [[the first number and the second number]]]
+     [[three numbers]
+      [[the first number and the second number and the third number]]]
+     [[one half] [0.5]] [[twice] [[2 times]]]
+     [[$ !number] [sentence :number "dollars]] [[consecutive to] [[1 plus]]]
+     [[larger than] ["plus]] [[per cent] ["percent]] [[how many] ["howm]]
+     [[is multiplied by] ["ismulby]] [[is divided by] ["isdivby]]
+     [[multiplied by] ["times]] [[divided by] ["divby]]]
+end
+
+to changes :sent :list
+localmake "keywords map.se [findkey first ?] :list
+output changes1 :sent :list :keywords
+end
+
+to findkey :pattern
+if equalp first :pattern "!:in [output first butfirst :pattern]
+if equalp first :pattern "?:in [output sentence (item 2 :pattern) (item 3 :pattern)]
+output first :pattern
+end
+
+to changes1 :sent :list :keywords
+if emptyp :sent [output []]
+if memberp first :sent :keywords [output changes2 :sent :list :keywords]
+output fput first :sent changes1 butfirst :sent :list :keywords
+end
+
+to changes2 :sent :list :keywords
+changes3 :list :list
+output fput first :sent changes1 butfirst :sent :list :keywords
+end
+
+to changes3 :biglist :nowlist
+if emptyp :nowlist [stop]
+if changeone first :nowlist [changes3 :biglist :biglist stop]
+changes3 :biglist butfirst :nowlist
+end
+
+to changeone :change
+local "end
+if not match (sentence first :change [#end]) :sent [output "false]
+make "sent run (sentence "sentence last :change ":end)
+output "true
+end
+
+;; Division into simple sentences
+
+to bracket :prob
+output bkt1 finddelim :prob
+end
+
+to finddelim :sent
+output finddelim1 :sent [] []
+end
+
+to finddelim1 :in :out :simples
+if emptyp :in ~
+   [ifelse emptyp :out [output :simples] [output lput (sentence :out ".) :simples]]
+if dlm first :in ~
+   [output finddelim1 (nocap butfirst :in) []
+                      (lput (sentence :out first :in) :simples)]
+output finddelim1 (butfirst :in) (sentence :out first :in) :simples
+end
+
+to nocap :words
+if emptyp :words [output []]
+if personp first :words [output :words]
+output sentence (lowercase first :words) butfirst :words
+end
+
+to bkt1 :problist
+local [first word rest]
+if emptyp :problist [output []]
+if not memberp ", first :problist ~
+   [output fput first :problist bkt1 butfirst :problist]
+if match [if ^first , !word:qword #rest] first :problist ~
+   [output bkt1 fput (sentence :first ".)
+                     fput (sentence :word :rest) butfirst :problist]
+if match [^first , and #rest] first :problist ~
+   [output fput (sentence :first ".) (bkt1 fput :rest butfirst :problist)]
+output fput first :problist bkt1 butfirst :problist
+end
+
+;; Age problems
+
+to ageprob
+local [beg end sym who num subj ages]
+while [match [^beg as old as #end] :prob] [make "prob sentence :beg :end]
+while [match [^beg years old #end] :prob] [make "prob sentence :beg :end]
+while [match [^beg will be when #end] :prob] ~
+      [make "sym gensym
+       make "prob (sentence :beg "in :sym [years . in] :sym "years :end)]
+while [match [^beg was when #end] :prob] ~
+      [make "sym gensym
+       make "prob (sentence :beg :sym [years ago .] :sym [years ago] :end)]
+while [match [^beg !who:personp will be in !num years #end] :prob] ~
+      [make "prob (sentence :beg :who [s age in] :num "years #end)]
+while [match [^beg was #end] :prob] [make "prob (sentence :beg "is :end)]
+while [match [^beg will be #end] :prob] [make "prob (sentence :beg "is :end)]
+while [match [^beg !who:personp is now #end] :prob] ~
+      [make "prob (sentence :beg :who [s age now] :end)]
+while [match [^beg !num years from now #end] :prob] ~
+      [make "prob (sentence :beg "in :num "years :end)]
+make "prob ageify :prob
+ifelse match [^ !who:personp ^end s age #] :prob ~
+       [make "subj sentence :who :end] [make "subj "someone]
+make "prob agepron :prob
+make "end :prob
+make "ages []
+while [match [^ !who:personp ^beg age #end] :end] ~
+      [push "ages (sentence "and :who :beg "age)]
+make "ages butfirst reduce "sentence remdup :ages
+while [match [^beg their ages #end] :prob] [make "prob (sentence :beg :ages :end)]
+make "simsen map [agesen ?] bracket :prob
+end
+
+to ageify :sent
+if emptyp :sent [output []]
+if not personp first :sent [output fput first :sent ageify butfirst :sent]
+catch "error [if equalp first butfirst :sent "s
+                 [output fput first :sent ageify butfirst :sent]]
+output (sentence first :sent [s age] ageify butfirst :sent)
+end
+
+to agepron :sent
+if emptyp :sent [output []]
+if not pronoun first :sent [output fput first :sent agepron butfirst :sent]
+if posspro first :sent [output (sentence :subj "s agepron butfirst :sent)]
+output (sentence :subj [s age] agepron butfirst :sent)
+end
+
+to agesen :sent
+local [when rest num]
+make "when []
+if match [in !num years #rest] :sent ~
+   [make "when sentence "pluss :num make "sent :rest]
+if match [!num years ago #rest] :sent ~
+   [make "when sentence "minuss :num make "sent :rest]
+output agewhen :sent
+end
+
+to agewhen :sent
+if emptyp :sent [output []]
+if not equalp first :sent "age [output fput first :sent agewhen butfirst :sent]
+if match [in !num years #rest] butfirst :sent ~
+   [output (sentence [age pluss] :num agewhen :rest)]
+if match [!num years ago #rest] butfirst :sent ~
+   [output (sentence [age minuss] :num agewhen :rest)]
+if equalp "now first butfirst :sent ~
+   [output sentence "age agewhen butfirst butfirst :sent]
+output (sentence "age :when agewhen butfirst :sent)
+end
+
+;; Translation from sentences into equations
+
+to senform :sent
+make "lasteqn senform1 :sent
+output :lasteqn
+end
+
+to senform1 :sent
+local [one two verb1 verb2 stuff1 stuff2 factor]
+if emptyp :sent [output []]
+if match [^ what are ^one and ^two !:dlm] :sent ~
+   [output fput (qset :one) (senform (sentence [what are] :two "?))]
+if match [^ what !:in [is are] #one !:dlm] :sent ~
+   [output (list qset :one)]
+if match [^ howm !one is #two !:dlm] :sent ~
+   [push "aunits (list :one) output (list qset :two)]
+if match [^ howm ^one do ^two have !:dlm] :sent ~
+   [output (list qset (sentence [the number of] :one :two "have))]
+if match [^ howm ^one does ^two have !:dlm] :sent ~
+   [output (list qset (sentence [the number of] :one :two "has))]
+if match [^ find ^one and #two] :sent ~
+   [output fput (qset :one) (senform sentence "find :two)]
+if match [^ find #one !:dlm] :sent [output (list qset :one)]
+make "sent filter [not article ?] :sent
+if match [^one ismulby #two] :sent ~
+   [push "ref (list "product opform :one opform :two) output []]
+if match [^one isdivby #two] :sent ~
+   [push "ref (list "quotient opform :one opform :two) output []]
+if match [^one is increased by #two] :sent ~
+   [push "ref (list "sum opform :one opform :two) output []]
+if match [^one is #two] :sent ~
+   [output (list (list "equal opform :one opform :two))]
+if match [^one !verb1:verb ^factor as many ^stuff1 as
+          ^two !verb2:verb ^stuff2 !:dlm] ~
+         :sent ~
+   [if emptyp :stuff2 [make "stuff2 :stuff1]
+    output (list (list "equal ~
+                   opform (sentence [the number of] :stuff1 :one :verb1) ~
+                   opform (sentence :factor [the number of] :stuff2 :two :verb2)))]
+if match [^one !verb1:verb !factor:numberp #stuff1 !:dlm] :sent ~
+   [output (list (list "equal ~
+                   opform (sentence [the number of] :stuff1 :one :verb1) ~
+                   opform (list :factor)))]
+say [This sentence form is not recognized:] :sent
+throw "error
+end
+
+to qset :sent
+localmake "opform opform filter [not article ?] :sent
+if not operatorp first :opform ~
+   [queue "wanted :opform queue "ans list :opform oprem :sent output []]
+localmake "gensym gensym
+queue "wanted :gensym
+queue "ans list :gensym oprem :sent
+output (list "equal :gensym opform (filter [not article ?] :sent))
+end
+
+to oprem :sent
+output map [ifelse equalp ? "numof ["of] [?]] :sent
+end
+
+to opform :expr
+local [left right op]
+if match [^left !op:op2 #right] :expr [output optest :op :left :right]
+if match [^left !op:op1 #right] :expr [output optest :op :left :right]
+if match [^left !op:op0 #right] :expr [output optest :op :left :right]
+if match [#left !:dlm] :expr [make "expr :left]
+output nmtest filter [not article ?] :expr
+end
+
+to optest :op :left :right
+output run (list (word "tst. :op) :left :right)
+end
+
+to tst.numof :left :right
+if numberp last :left [output (list "product opform :left opform :right)]
+output opform (sentence :left "of :right)
+end
+
+to tst.divby :left :right
+output (list "quotient opform :left opform :right)
+end
+
+to tst.tothepower :left :right
+output (list "expt opform :left opform :right)
+end
+
+to expt :num :pow
+if :pow < 1 [output 1]
+output :num * expt :num :pow - 1
+end
+
+to tst.per :left :right
+output (list "quotient ~
+          opform :left ~
+          opform (ifelse numberp first :right [:right] [fput 1 :right]))
+end
+
+to tst.lessthan :left :right
+output opdiff opform :right opform :left
+end
+
+to opdiff :left :right
+output (list "sum :left (list "minus :right))
+end
+
+to tst.minus :left :right
+if emptyp :left [output list "minus opform :right]
+output opdiff opform :left opform :right
+end
+
+to tst.minuss :left :right
+output tst.minus :left :right
+end
+
+to tst.sum :left :right
+local [one two three]
+if match [^one and ^two and #three] :right ~
+   [output (list "sum opform :one opform (sentence "sum :two "and :three))]
+if match [^one and #two] :right ~
+   [output (list "sum opform :one opform :two)]
+say [sum used wrong:] :right
+throw "error
+end
+
+to tst.squared :left :right
+output list "square opform :left
+end
+
+to tst.difference :left :right
+local [one two]
+if match [between ^one and #two] :right [output opdiff opform :one opform :two]
+say [Incorrect use of difference:] :right
+throw "error
+end
+
+to tst.plus :left :right
+output (list "sum opform :left opform :right)
+end
+
+to tst.pluss :left :right
+output tst.plus :left :right
+end
+
+to square :x
+output :x * :x
+end
+
+to tst.square :left :right
+output list "square opform :right
+end
+
+to tst.percent :left :right
+if not numberp last :left ~
+   [say [Incorrect use of percent:] :left throw "error]
+output opform (sentence butlast :left ((last :left) / 100) :right)
+end
+
+to tst.perless :left :right
+if not numberp last :left ~
+   [say [Incorrect use of percent:] :left throw "error]
+output (list "product ~
+          (opform sentence butlast :left ((100 - (last :left)) / 100)) ~
+          opform :right)
+end
+
+to tst.times :left :right
+if emptyp :left [say [Incorrect use of times:] :right throw "error]
+output (list "product opform :left opform :right)
+end
+
+to nmtest :expr
+if match [& !:numberp #] :expr [say [argument error:] :expr throw "error]
+if and (equalp first :expr 1) (1 < count :expr) ~
+   [make "expr (sentence 1 plural (first butfirst :expr) (butfirst butfirst :expr))]
+if and (numberp first :expr) (1 < count :expr) ~
+   [push "units (list first butfirst :expr) ~
+    output (list "product (first :expr) (opform butfirst :expr))]
+if numberp first :expr [output first :expr]
+if memberp "this :expr [output this :expr]
+if not memberp :expr :var [push "var :expr]
+output :expr
+end
+
+to this :expr
+if not emptyp :ref [output pop "ref]
+if not emptyp :lasteqn [output first butfirst last :lasteqn]
+if equalp first :expr "this [make "expr butfirst :expr]
+push "var :expr
+output :expr
+end
+
+;; Solving the equations
+
+to trysolve :shelf :wanted :units :aunits
+local "solution
+make "solution solve :wanted :shelf (ifelse emptyp :aunits [:units] [:aunits])
+output pranswers :ans :solution
+end
+
+to solve :wanted :eqt :terms
+output solve.reduce solver :wanted :terms [] [] "insufficient
+end
+
+to solve.reduce :soln
+if emptyp :soln [output []]
+if wordp :soln [output :soln]
+if emptyp butfirst :soln [output :soln]
+local "part
+make "part solve.reduce butfirst :soln
+output fput (list (first first :soln) (subord last first :soln :part)) :part
+end
+
+to solver :wanted :terms :alis :failed :err
+local [one result restwant]
+if emptyp :wanted [output :err]
+make "one solve1 (first :wanted) ~
+                 (sentence butfirst :wanted :failed :terms) ~
+                 :alis :eqt [] "insufficient
+if wordp :one ~
+   [output solver (butfirst :wanted) :terms :alis (fput first :wanted :failed) :one]
+make "restwant (sentence :failed butfirst :wanted)
+if emptyp :restwant [output :one]
+make "result solver :restwant :terms :one [] "insufficient
+if listp :result [output :result]
+output solver (butfirst :wanted) :terms :alis (fput first :wanted :failed) :one
+end
+
+to solve1 :x :terms :alis :eqns :failed :err
+local [thiseq vars extras xterms others result]
+if emptyp :eqns [output :err]
+make "thiseq subord (first :eqns) :alis
+make "vars varterms :thiseq
+if not memberp :x :vars ~
+   [output solve1 :x :terms :alis (butfirst :eqns) (fput first :eqns :failed) :err]
+make "xterms fput :x :terms
+make "extras setminus :vars :xterms
+make "eqt remove (first :eqns) :eqt
+if not emptyp :extras ~
+   [make "others solver :extras :xterms :alis [] "insufficient
+    ifelse wordp :others
+           [make "eqt sentence :failed :eqns
+            output solve1 :x :terms :alis (butfirst :eqns)
+                      (fput first :eqns :failed) :others]
+           [make "alis :others
+            make "thiseq subord (first :eqns) :alis]]
+make "result solveq :x :thiseq
+if listp :result [output lput :result :alis]
+make "eqt sentence :failed :eqns
+output solve1 :x :terms :alis (butfirst :eqns) (fput first :eqns :failed) :result
+end
+
+to solveq :var :eqn
+local [left right]
+make "left first butfirst :eqn
+ifelse occvar :var :left ~
+   [make "right last :eqn] [make "right :left make "left last :eqn]
+output solveq1 :left :right "true
+end
+
+to solveq1 :left :right :bothtest
+if :bothtest [if occvar :var :right [output solveqboth :left :right]]
+if equalp :left :var [output list :var :right]
+if wordp :left [output "unsolvable]
+local "oper
+make "oper first :left
+if memberp :oper [sum product minus quotient] [output run (list word "solveq. :oper)]
+output "unsolvable
+end
+
+to solveqboth :left :right
+if not equalp first :right "sum [output solveq1 (subterm :left :right) 0 "false]
+output solveq.rplus :left butfirst :right []
+end
+
+to solveq.rplus :left :right :newright
+if emptyp :right [output solveq1 :left (simone "sum :newright) "false]
+if occvar :var first :right ~
+   [output solveq.rplus (subterm :left first :right) butfirst :right :newright]
+output solveq.rplus :left butfirst :right (fput first :right :newright)
+end
+
+to solveq.sum
+if emptyp butfirst butfirst :left [output solveq1 first butfirst :left :right "true]
+output solveq.sum1 butfirst :left :right []
+end
+
+to solveq.sum1 :left :right :newleft
+if emptyp :left [output solveq.sum2]
+if occvar :var first :left ~
+   [output solveq.sum1 butfirst :left :right fput first :left :newleft]
+output solveq.sum1 butfirst :left (subterm :right first :left) :newleft
+end
+
+to solveq.sum2
+if emptyp butfirst :newleft [output solveq1 first :newleft :right "true]
+localmake "factor factor :newleft :var
+if equalp first :factor "unknown [output "unsolvable]
+if equalp last :factor 0 [output "unsolvable]
+output solveq1 first :factor (divterm :right last :factor) "true
+end
+
+to solveq.minus
+output solveq1 (first butfirst :left) (minusin :right) "false
+end
+
+to solveq.product
+output solveq.product1 :left :right
+end
+
+to solveq.product1 :left :right
+if emptyp butfirst butfirst :left [output solveq1 (first butfirst :left) :right "true]
+if not occvar :var first butfirst :left ~
+   [output solveq.product1 (fput "product butfirst butfirst :left)
+                           (divterm :right first butfirst :left)]
+localmake "rest simone "product butfirst butfirst :left
+if occvar :var :rest [output "unsolvable]
+output solveq1 (first butfirst :left) (divterm :right :rest) "false
+end
+
+to solveq.quotient
+if occvar :var first butfirst :left ~
+   [output solveq1 (first butfirst :left) (simtimes list :right last :left) "true]
+output solveq1 (simtimes list :right last :left) (first butfirst :left) "true
+end
+
+to denom :fract :addends
+make "addends simplus :addends
+localmake "den last :fract
+if not equalp first :addends "quotient ~
+   [output simdiv list (simone "sum
+                               (remop "sum list (distribtimes (list :addends) :den)
+                                                first butfirst :fract))
+                       :den]
+if equalp :den last :addends ~
+   [output simdiv (simplus list (first butfirst :fract) (first butfirst :addends))
+                  :den]
+localmake "lowterms simdiv list :den last :addends
+output simdiv list (simplus (simtimes list first butfirst :fract last :lowterms)
+                            (simtimes list first butfirst :addends
+                                           first butfirst :lowterms)) ~
+                   (simtimes list first butfirst :lowterms last :addends)
+end
+
+to distribtimes :trms :multiplier
+output simplus map [simtimes (list ? :multiplier)] :trms
+end
+
+to distribx :expr
+local [oper args]
+if emptyp :expr [output :expr]
+make "oper first :expr
+if not operatorp :oper [output :expr]
+make "args map [distribx ?] butfirst :expr
+if reduce "and map [numberp ?] :args [output run (sentence [(] :oper :args [)])]
+if equalp :oper "sum [output simplus :args]
+if equalp :oper "minus [output minusin first :args]
+if equalp :oper "product [output simtimes :args]
+if equalp :oper "quotient [output simdiv :args]
+output fput :oper :args
+end
+
+to divterm :dividend :divisor
+if equalp :dividend 0 [output 0]
+output simdiv list :dividend :divisor
+end
+
+to factor :exprs :var
+local "trms
+make "trms map [factor1 :var ?] :exprs
+if memberp "unknown :trms [output fput "unknown :exprs]
+output list :var simplus :trms
+end
+
+to factor1 :var :expr
+localmake "negvar minusin :var
+if equalp :var :expr [output 1]
+if equalp :negvar :expr [output -1]
+if emptyp :expr [output "unknown]
+if equalp first :expr "product [output factor2 butfirst :expr]
+if not equalp first :expr "quotient [output "unknown]
+localmake "dividend first butfirst :expr
+if equalp :var :dividend [output (list "quotient 1 last :expr)]
+if not equalp first :dividend "product [output "unknown]
+localmake "result factor2 butfirst :dividend
+if equalp :result "unknown [output "unknown]
+output (list "quotient :result last :expr)
+end
+
+to factor2 :trms
+if memberp :var :trms [output simone "product (remove :var :trms)]
+if memberp :negvar :trms [output minusin simone "product (remove :negvar :trms)]
+output "unknown
+end
+
+to maybeadd :num :rest
+if equalp :num 0 [output :rest]
+output fput :num :rest
+end
+
+to maybemul :num :rest
+if equalp :num 1 [output :rest]
+output fput :num :rest
+end
+
+to minusin :expr
+if emptyp :expr [output -1]
+if equalp first :expr "sum [output fput "sum map [minusin ?] butfirst :expr]
+if equalp first :expr "minus [output last :expr]
+if memberp first :expr [product quotient] ~
+   [output fput first :expr
+                (fput (minusin first butfirst :expr) butfirst butfirst :expr)]
+if numberp :expr [output minus :expr]
+output list "minus :expr
+end
+
+to occvar :var :expr
+if emptyp :expr [output "false]
+if wordp :expr [output equalp :var :expr]
+if operatorp first :expr [output not emptyp find [occvar :var ?] butfirst :expr]
+output equalp :var :expr
+end
+
+to remfactor :num :den
+foreach butfirst :num [remfactor1 ?]
+output (list "quotient (simone "product butfirst :num) (simone "product butfirst :den))
+end
+
+to remfactor1 :expr
+local "neg
+if memberp :expr :den ~
+   [make "num remove :expr :num  make "den remove :expr :den  stop]
+make "neg minusin :expr
+if not memberp :neg :den [stop]
+make "num remove :expr :num
+make "den minusin remove :neg :den
+end
+
+to remop :oper :exprs
+output map.se [ifelse equalp first ? :oper [butfirst ?] [(list ?)]] :exprs
+end
+
+to simdiv :list
+local [num den numop denop]
+make "num first :list
+make "den last :list
+if equalp :num :den [output 1]
+if numberp :den [output simtimes (list (quotient 1 :den) :num)]
+make "numop first :num
+make "denop first :den
+if equalp :numop "quotient ~
+   [output simdiv list (first butfirst :num) (simtimes list last :num :den)]
+if equalp :denop "quotient ~
+   [output simdiv list (simtimes list :num last :den) (first butfirst :den)]
+if and equalp :numop "product equalp :denop "product [output remfactor :num :den]
+if and equalp :numop "product memberp :den :num [output remove :den :num]
+output fput "quotient :list
+end
+
+to simone :oper :trms
+if emptyp :trms [output ifelse equalp :oper "product [1] [0]]
+if emptyp butfirst :trms [output first :trms]
+output fput :oper :trms
+end
+
+to simplus :exprs
+make "exprs remop "sum :exprs
+localmake "factor [unknown]
+catch "simplus ~
+      [foreach :terms ~
+               [make "factor (factor :exprs ?) ~
+                if not equalp first :factor "unknown [throw "simplus]]]
+if not equalp first :factor "unknown [output fput "product remop "product :factor]
+localmake "nums 0
+localmake "nonnums []
+localmake "quick []
+catch "simplus [simplus1 :exprs]
+if not emptyp :quick [output :quick]
+if not equalp :nums 0 [push "nonnums :nums]
+output simone "sum :nonnums
+end
+
+to simplus1 :exprs
+if emptyp :exprs [stop]
+simplus2 first :exprs
+simplus1 butfirst :exprs
+end
+
+to simplus2 :pos
+local "neg
+make "neg minusin :pos
+if numberp :pos [make "nums sum :pos :nums stop]
+if memberp :neg butfirst :exprs [make "exprs remove :neg :exprs stop]
+if equalp first :pos "quotient ~
+   [make "quick (denom :pos (maybeadd :nums sentence :nonnums butfirst :exprs)) ~
+    throw "simplus]
+push "nonnums :pos
+end
+
+to simtimes :exprs
+local [nums nonnums quick]
+make "nums 1
+make "nonnums []
+make "quick []
+catch "simtimes [foreach remop "product :exprs [simtimes1 ?]]
+if not emptyp :quick [output :quick]
+if equalp :nums 0 [output 0]
+if not equalp :nums 1 [push "nonnums :nums]
+output simone "product :nonnums
+end
+
+to simtimes1 :expr
+if equalp :expr 0 [make "nums 0 throw "simtimes]
+if numberp :expr [make "nums product :expr :nums stop]
+if equalp first :expr "sum ~
+   [make "quick distribtimes (butfirst :expr)
+                             (simone "product maybemul :nums sentence :nonnums ?rest)
+    throw "simtimes]
+if equalp first :expr "quotient ~
+   [make "quick
+          simdiv (list (simtimes (list (first butfirst :expr)
+                                       (simone "product
+                                               maybemul :nums
+                                                        sentence :nonnums ?rest)))
+                       (last :expr))
+    throw "simtimes]
+push "nonnums :expr
+end
+
+to subord :expr :alist
+output distribx subord1 :expr :alist
+end
+
+to subord1 :expr :alist
+if emptyp :alist [output :expr]
+output subord (substop (last first :alist) (first first :alist) :expr) ~
+              (butfirst :alist)
+end
+
+to substop :val :var :expr
+if emptyp :expr [output []]
+if equalp :expr :var [output :val]
+if not operatorp first :expr [output :expr]
+output fput first :expr map [substop :val :var ?] butfirst :expr
+end
+
+to subterm :minuend :subtrahend
+if equalp :minuend 0 [output minusin :subtrahend]
+if equalp :minuend :subtrahend [output 0]
+output simplus (list :minuend minusin :subtrahend)
+end
+
+to varterms :expr
+if emptyp :expr [output []]
+if numberp :expr [output []]
+if wordp :expr [output (list :expr)]
+if operatorp first :expr [output map.se [varterms ?] butfirst :expr]
+output (list :expr)
+end
+
+;; Printing the solutions
+
+to pranswers :ans :solution
+print []
+if equalp :solution "unsolvable ~
+   [print [Unable to solve this set of equations.] output "false]
+if equalp :solution "insufficient ~
+   [print [The equations were insufficient to find a solution.] output "false]
+localmake "gotall "true
+foreach :ans [if prans ? :solution [make "gotall "false]]
+if not :gotall [print [] print [Unable to solve this set of equations.]]
+output :gotall
+end
+
+to prans :ans :solution
+localmake "result find [equalp first ? first :ans] :solution
+if emptyp :result [output "true]
+print (sentence cap last :ans "is unitstring last :result)
+print []
+output "false
+end
+
+to unitstring :expr
+if numberp :expr [output roundoff :expr]
+if equalp first :expr "product ~
+   [output sentence (unitstring first butfirst :expr)
+                    (reduce "sentence butfirst butfirst :expr)]
+if (and (listp :expr)
+         (not numberp first :expr)
+         (not operatorp first :expr)) ~
+   [output (sentence 1 (singular first :expr) (butfirst :expr))]
+output :expr
+end
+
+to roundoff :num
+if (abs (:num - round :num)) < 0.0001 [output round :num]
+output :num
+end
+
+to abs :num
+output ifelse (:num < 0) [-:num] [:num]
+end
+
+;; Using known relationships
+
+to geteqns :vars
+output map.se [gprop varkey ? "eqns] :vars
+end
+
+to varkey :var
+local "word
+if match [number of !word #] :var [output :word]
+output first :var
+end
+
+;; Assuming equality of similar variables
+
+to vartest :vars
+if emptyp :vars [output []]
+local [var beg end]
+make "var first :vars
+output (sentence (ifelse match [^beg !:pronoun #end] :var
+                         [vartest1 :var (sentence :beg "& :end) butfirst :vars]
+                         [[]])
+                 (vartest1 :var (sentence "# :var "#) butfirst :vars)
+                 (vartest butfirst :vars))
+end
+
+to vartest1 :target :pat :vars
+output map [varequal :target ?] filter [match :pat ?] :vars
+end
+
+to varequal :target :var
+print []
+print [Assuming that]
+print (sentence (list :target) [is equal to] (list :var))
+output (list "equal :target :var)
+end
+
+;; Optional substitutions
+
+to tryidiom
+make "prob (sentence :beg last :idiom :end)
+while [match (sentence "^beg first :idiom "#end) :prob] ~
+      [make "prob (sentence :beg last :idiom :end)]
+say [The problem with an idiomatic substitution is] :prob
+student1 :prob (remove :idiom :idioms)
+end
+
+;; Utility procedures
+
+to qword :word
+output memberp :word [find what howm how]
+end
+
+to dlm :word
+output memberp :word [. ? |;|]
+end
+
+to article :word
+output memberp :word [a an the]
+end
+
+to verb :word
+output memberp :word [have has get gets weigh weighs]
+end
+
+to personp :word
+output memberp :word [Mary Ann Bill Tom Sally Frank father uncle]
+end
+
+to pronoun :word
+output memberp :word [he she it him her they them his her its]
+end
+
+to posspro :word
+output memberp :word [his her its]
+end
+
+to op0 :word
+output memberp :word [pluss minuss squared tothepower per sum difference numof]
+end
+
+to op1 :word
+output memberp :word [times divby square]
+end
+
+to op2 :word
+output memberp :word [plus minus lessthan percent perless]
+end
+
+to operatorp :word
+output memberp :word [sum minus product quotient expt square equal]
+end
+
+to plural :word
+localmake "plural gprop :word "plural
+if not emptyp :plural [output :plural]
+if not emptyp gprop :word "sing [output :word]
+if equalp last :word "s [output :word]
+output word :word "s
+end
+
+to singular :word
+localmake "sing gprop :word "sing
+if not emptyp :sing [output :sing]
+if not emptyp gprop :word "plural [output :word]
+if equalp last :word "s [output butlast :word]
+output :word
+end
+
+to setminus :big :little
+output filter [not memberp ? :little] :big
+end
+
+to say :herald :text
+print []
+print :herald
+print []
+print :text
+print []
+end
+
+to lsay :herald :text
+print []
+print :herald
+print []
+foreach :text [print cap ? print []]
+end
+
+to cap :sent
+if emptyp :sent [output []]
+output sentence (word uppercase first first :sent butfirst first :sent) ~
+                butfirst :sent
+end
+
+;; The pattern matcher
+
+to match :pat :sen
+if prematch :pat :sen [output rmatch :pat :sen]
+output "false
+end
+
+to prematch :pat :sen
+if emptyp :pat [output "true]
+if listp first :pat [output prematch butfirst :pat :sen]
+if memberp first first :pat [! @ # ^ & ?] [output prematch butfirst :pat :sen]
+if emptyp :sen [output "false]
+localmake "rest member first :pat :sen
+if not emptyp :rest [output prematch butfirst :pat :rest]
+output "false
+end
+
+to rmatch :pat :sen
+local [special.var special.pred special.buffer in.list]
+if or wordp :pat wordp :sen [output "false]
+if emptyp :pat [output emptyp :sen]
+if listp first :pat [output special fput "!: :pat :sen]
+if memberp first first :pat [? # ! & @ ^] [output special :pat :sen]
+if emptyp :sen [output "false]
+if equalp first :pat first :sen [output rmatch butfirst :pat butfirst :sen]
+output "false
+end
+
+to special :pat :sen
+set.special parse.special butfirst first :pat "
+output run word "match first first :pat
+end
+
+to parse.special :word :var
+if emptyp :word [output list :var "always]
+if equalp first :word ": [output list :var butfirst :word]
+output parse.special butfirst :word word :var first :word
+end
+
+to set.special :list
+make "special.var first :list
+make "special.pred last :list
+if emptyp :special.var [make "special.var "special.buffer]
+if memberp :special.pred [in anyof] [set.in]
+if not emptyp :special.pred [stop]
+make "special.pred first butfirst :pat
+make "pat fput first :pat butfirst butfirst :pat
+end
+
+to set.in
+make "in.list first butfirst :pat
+make "pat fput first :pat butfirst butfirst :pat
+end
+
+to match!
+if emptyp :sen [output "false]
+if not try.pred [output "false]
+make :special.var first :sen
+output rmatch butfirst :pat butfirst :sen
+end
+
+to match?
+make :special.var []
+if emptyp :sen [output rmatch butfirst :pat :sen]
+if not try.pred [output rmatch butfirst :pat :sen]
+make :special.var first :sen
+if rmatch butfirst :pat butfirst :sen [output "true]
+make :special.var []
+output rmatch butfirst :pat :sen
+end
+
+to match#
+make :special.var []
+output #test #gather :sen
+end
+
+to #gather :sen
+if emptyp :sen [output :sen]
+if not try.pred [output :sen]
+make :special.var lput first :sen thing :special.var
+output #gather butfirst :sen
+end
+
+to #test :sen
+if rmatch butfirst :pat :sen [output "true]
+if emptyp thing :special.var [output "false]
+output #test2 fput last thing :special.var :sen
+end
+
+to #test2 :sen
+make :special.var butlast thing :special.var
+output #test :sen
+end
+
+to match&
+output &test match#
+end
+
+to &test :tf
+if emptyp thing :special.var [output "false]
+output :tf
+end
+
+to match^
+make :special.var []
+output ^test :sen
+end
+
+to ^test :sen
+if rmatch butfirst :pat :sen [output "true]
+if emptyp :sen [output "false]
+if not try.pred [output "false]
+make :special.var lput first :sen thing :special.var
+output ^test butfirst :sen
+end
+
+to match@
+make :special.var :sen
+output @test []
+end
+
+to @test :sen
+if @try.pred [if rmatch butfirst :pat :sen [output "true]]
+if emptyp thing :special.var [output "false]
+output @test2 fput last thing :special.var :sen
+end
+
+to @test2 :sen
+make :special.var butlast thing :special.var
+output @test :sen
+end
+
+to try.pred
+if listp :special.pred [output rmatch :special.pred first :sen]
+output run list :special.pred quoted first :sen
+end
+
+to quoted :thing
+if listp :thing [output :thing]
+output word "" :thing
+end
+
+to @try.pred
+if listp :special.pred [output rmatch :special.pred thing :special.var]
+output run list :special.pred thing :special.var
+end
+
+to always :x
+output "true
+end
+
+to in :word
+output memberp :word :in.list
+end
+
+to anyof :sen
+output anyof1 :sen :in.list
+end
+
+to anyof1 :sen :pats
+if emptyp :pats [output "false]
+if rmatch first :pats :sen [output "true]
+output anyof1 :sen butfirst :pats
+end
+
+;; Sample word problems
+
+make "ann [Mary is twice as old as Ann was when Mary was as old as Ann is now.
+  If Mary is 24 years old, how old is Ann?]
+make "guns [The number of soldiers the Russians have is
+  one half of the number of guns they have. They have 7000 guns.
+  How many soldiers do they have?]
+make "jet [The distance from New York to Los Angeles is 3000 miles.
+  If the average speed of a jet plane is 600 miles per hour,
+  find the time it takes to travel from New York to Los Angeles by jet.]
+make "nums [A number is multiplied by 6 . This product is increased by 44 .
+  This result is 68 . Find the number.]
+make "radio [The price of a radio is $69.70.
+  If this price is 15 percent less than the marked price, find the marked price.]
+make "sally [The sum of Sally's share of some money and Frank's share is $4.50.
+  Sally's share is twice Frank's. Find Frank's and Sally's share.]
+make "ship [The gross weight of a ship is 20000 tons.
+  If its net weight is 15000 tons, what is the weight of the ships cargo?]
+make "span [If 1 span is 9 inches, and 1 fathom is 6 feet,
+  how many spans is 1 fathom?]
+make "sumtwo [The sum of two numbers is 96,
+  and one number is 16 larger than the other number. Find the two numbers.]
+make "tom [If the number of customers Tom gets is
+  twice the square of 20 per cent of the number of advertisements he runs,
+  and the number of advertisements he runs is 45,
+  what is the number of customers Tom gets?]
+make "uncle [Bill's father's uncle is twice as old as Bill's father.
+  2 years from now Bill's father will be 3 times as old as Bill.
+  The sum of their ages is 92 . Find Bill's age.]
+
+;; Initial data base
+
+pprop "distance "eqns ~
+  [[equal [distance] [product [speed] [time]]]
+   [equal [distance] [product [gas consumtion] [number of gallons of gas used]]]]
+pprop "feet "eqns ~
+  [[equal [product 1 [feet]] [product 12 [inches]]]
+   [equal [product 1 [yards]] [product 3 [feet]]]]
+pprop "feet "sing "foot
+pprop "foot "plural "feet
+pprop "gallons "eqns ~
+  [[equal [distance] [product [gas consumtion] [number of gallons of gas used]]]]
+pprop "gas "eqns ~
+  [[equal [distance] [product [gas consumtion] [number of gallons of gas used]]]]
+pprop "inch "plural "inches
+pprop "inches "eqns [[equal [product 1 [feet]] [product 12 [inches]]]]
+pprop "people "sing "person
+pprop "person "plural "people
+pprop "speed "eqns [[equal [distance] [product [speed] [time]]]]
+pprop "time "eqns [[equal [distance] [product [speed] [time]]]]
+pprop "yards "eqns [[equal [product 1 [yards]] [product 3 [feet]]]]
+</PRE>
+
+<P><A HREF="../v3-toc2.html">(back to Table of Contents)</A>
+<P><A HREF="../v3ch5/v3ch5.html"><STRONG>BACK</STRONG></A>
+chapter thread <A HREF="https://people.eecs.berkeley.edu/~bh/v3ch7/v3ch7.html"><STRONG>NEXT</STRONG></A>
+
+<P>
+<ADDRESS>
+<A HREF="../index.html">Brian Harvey</A>, 
+<CODE>bh@cs.berkeley.edu</CODE>
+</ADDRESS>
+</BODY>
+</HTML>