COMMENT
REDUCE INTERACTIVE LESSON NUMBER 5
David R. Stoutemyer
University of Hawaii
COMMENT This is lesson 5 of 7 REDUCE lessons.
There are at least two good reasons for wanting to save REDUCE
expression assignments on secondary storage:
1. So that one can logout, then resume computation at a later
time.
2. So that needed storage space can be cleared without
irrecoverably losing the values of variables which are not
needed in the next expression but will be needed later.
Using trivial small expressions, the following sequence illustrates
how this could be done:
OFF NAT,
OUT TEMP,
F1 := (F + G)**2,
G1 := G*F1,
OUT T,
CLEAR F1,
H1 := H*G1,
OUT TEMP,
CLEAR G1,
H2 := F*H1,
CLEAR H1,
SHUT TEMP,
IN TEMP,
F1,
ON NAT,
F1 .
ON NAT yields the natural output style with raised exponents, which
is unsuitable for subsequent input.
The OUT-statement causes subsequent output to be directed to the file
named in the statement, until overridden by a different OUT-statement
or until the file is closed by a SHUT-statement. File T is the
terminal, and any other name designates a file on secondary storage.
Such names must comply with the local file-naming conventions as well
as with the REDUCE syntax. If the output is not of lasting
importance, I find that including something like "TEMPORARY" or
"SCRATCH" in the name helps remind me to delete it later.
Successive OUT-statements to the same file will append rather than
overwrite output if and only if there is no intervening SHUT-
statement for that file. The SHUT-statement also has the effect of
an implied OUT T.
Note:
1. The generated output is the simplified expression rather than
the raw form entered at the terminal.
2. Each output assignment automatically has a dollar-sign
appended so that it is legal input and so that (perhaps
lengthy) output will not unavoidably be generated at the
terminal when the file is read in later.
3. Output cannot be sent simultaneously to 2 or more files.
4. Statements entered at the terminal which do not generate
output -- such as declarations, LET rules, and procedure
definitions -- do not appear in the secondary storage file.
5. One could get declarations, procedure definitions, rules, etc.
written on secondary storage from the terminal by typing
statements such as
WRITE "
ALGEBRAIC PROCEDURE ...
... " .
This could serve as a means of generating permanent copies
of LET rules, procedures, etc., but it is quite awkward
compared with the usual way, which is to generate a file
containing the REDUCE program by using a text editor, then
load the program by using the IN-statement. If you have
refrained from learning a local text editor and the operating-
system file-management commands, hesitate no longer. A half
dozen of the most basic commands will enable you to produce
(and modify!) programs more conveniently than any other method.
To keep from confusing the editor from REDUCE, I suggest that
your first text-editing exercise be to create an IN file for
(re)defining the function FACTORIAL(n).
5. The reason I didn't actually execute the above sequence of
statements is that when the input to REDUCE comes from a batch
file, both the input and output are sent to the output file,
(which is convenient for producing a file containing both the
input and output of a demonstration.) Consequently, you would
have seen none of the statements between the "OUT TEMP" and
"OUT T" as well as between the second "OUT TEMP" and the
"SHUT TEMP", until the IN statement was executed. The example
is confusing enough without having things scrambled from the
order you would type them. To clarify all of this, I encourage
you to actually execute the above sequence, with an
appropriately chosen file name and using semicolons rather
than commas. Afterwards, to return to the lesson, type CONT;
PAUSE;
COMMENT Suppose you and your colleagues developed or obtained a set
of REDUCE files containing supplementary packages such as trigono-
metric simplification, Laplace transforms, etc. It would be a waste
of time (and perhaps paper) to have these files printed at the
terminal every time they were loaded, so this printing can be
suppressed by inserting the statement "OFF ECHO" at the beginning of
the file, together with the statement "ON ECHO" at the end of the
file.
The lessons have amply demonstrated the PAUSE-statement, which is
useful for insertion in batch files at the top-level or within
functions when input from the user is necessary or desired.
It often happens that after generating an expression, one decides
that it would be convenient to use it as the body of a function
definition, with one or more of the indeterminates therein as
parameters. This can be done as follows (say yes to the define
operator prompt);
(1-(V/C)**2)**(1/2);
FOR ALL V SAVEAS F(V);
F(5);
COMMENT Here the indeterminate V became a parameter of F.
Alternatively, we can save the previous expression as an indeterminate;
SAVEAS FOF5;
FOF5;
COMMENT I find this technique more convenient than referring to the
special variable WS;
PAUSE;
COMMENT The FOR-loop provides a convenient way to form finite sums or
products with specific integer index limits. However, this need is
so ubiquitous that REDUCE provides even more convenient syntax of
the forms
FOR index := initial STEP increment UNTIL final SUM expression,
FOR index := initial STEP increment UNTIL final PRODUCT expression.
As before, ":" is an acceptable abbreviation for "STEP 1 UNTIL". As
an example of their use, here is a very concise definition of a
function which computes Taylor-series expansions of symbolic
expressions:;
ALGEBRAIC PROCEDURE TAYLOR(EX, X, PT, N);
COMMENT This function returns the degree N Taylor-series
expansion of expression EX with respect to indeterminate X,
expanded about expression PT. For a series-like appearance,
display the answer under the influence of FACTOR X, ON RAT,
and perhaps also ON DIV;
SUB(X=PT, EX) + FOR K:=1:N SUM(SUB(X=PT, DF(EX,X,K))*(X-PT)**K
/ FOR J:=1:K PRODUCT J);
CLEAR A, X; FACTOR X; ON RAT, DIV;
G1 := TAYLOR(E**X, X, 0, 4);
G2 := TAYLOR(E**COS(X)*COS(SIN(X)), X, 0, 3);
%This illustrates the Zero denominator limitation, continue anyway;
TAYLOR(LOG(X), X, 0, 4);
COMMENT It would, of course, be more efficient to compute each
derivative and factorial from the preceding one. (Similarly for
(X-PT)**K if and only if PT NEQ 0).
The Fourier series expansion of our example E**COS(X)*COS(SIN(X))
is 1 + cos(x) + cos(2*x)/2 + cos(3*x)/(3*2) + ... .
Use the above SUM and PRODUCT features to generate the partial sum of
this series through terms of order COS(6*X);
PAUSE;
COMMENT Closed-form solutions are often unobtainable for nontrivial
problems, even using computer algebra. When this is the case,
truncated symbolic series solutions are often worth trying before
resorting to approximate numerical solutions.
When we combine truncated series it is pointless (and worse yet,
misleading) to retain terms of higher order than is justified by the
constituents. For example, if we wish to multiply together the
truncated series G1 and G2 generated above, there is no point in
retaining terms higher than third degree in X. We can avoid even
generating such terms as follows;
LET X**4 = 0;
G3 := G1*G2;
COMMENT Replacing X**4 with 0 has the effect of also replacing all
higher powers of X with 0. We could, of course, use our TAYLOR
function to compute G3 directly, but differentiation is time
consuming compared to truncated polynomial algebra. Moreover, our
TAYLOR function requires a closed-form expression to begin with,
whereas iterative techniques often permit us to construct symbolic
series solutions even when we have no such closed form.
Now consider the truncated series;
CLEAR Y; FACTOR Y;
H1 := TAYLOR(COS Y, Y, 0, 6);
COMMENT Suppose we regard terms of order X**N in G1 as being
comparable to terms of order Y**(2*N) in H1, and we want to form
(G1*H1)**2. This can be done as follows;
LET Y**7 = 0;
F1 := (G1*H1)**2;
COMMENT Note however that any terms of the form C*X**M*Y**N with
2*M+N > 6 are inconsistent with the accuracy of the constituent
series, and we have generated several such misleading terms by
independently truncating powers of X and Y. To avoid generating
such junk, we can specify that a term be replaced by 0 whenever a
weighted sum of exponents of specified indeterminates and functional
forms exceeds a specified weight level. In our example this is done
as follows;
WEIGHT X=2, Y=1;
WTLEVEL 6;
F1 := F1;
COMMENT variables not mentioned in a WEIGHT declaration have a
weight of 0, and the default weight-level is 2;
PAUSE;
COMMENT In lesson 2 I promised to show you ways to overcome the lack
in most REDUCE implementations of automatic numerical techniques
for approximating fractional powers and transcendental functions of
numerical values. One way is to provide a supplementary LET rule
for numerical arguments. For example, since our TAYLOR function
would reveal that the Taylor series for cos x is
1 - x**2/2! + x**4/4! - ...;
FOR ALL X SUCH THAT NUMBERP X LET ABS(X)=X,ABS(-X)=X;
EPSRECIP := 1024 $
ON ROUNDED;
WHILE 1.0 + 1.0/EPSRECIP NEQ 1.0 DO
EPSRECIP := EPSRECIP + EPSRECIP;
FOR ALL X SUCH THAT NUMBERP NUM X AND NUMBERP DEN X LET COS X =
BEGIN COMMENT X is integer, real, or a rational number. This rule
returns the Taylor-series approximation to COS X, truncated when
the last included term is less than (1/EPSRECIP) of the returned
answer. EPSRECIP is a global variable initialized to a value
that is appropriate to the local floating-point precision.
Arbitrarily larger values are justifiable when X is exact and
ROUNDED is off. No angle reduction is performed, so this
function is not recommended for ABS(X) >= about PI/2;
INTEGER K; SCALAR MXSQ, TERM, ANS;
K := 1;
MXSQ := -X*X;
TERM := MXSQ/2;
ANS := TERM + 1;
WHILE ABS(NUM TERM)*EPSRECIP*DEN(ANS)-ABS(NUM ANS)*DEN(TERM)>0 DO
<< TERM:= TERM*MXSQ/K/(K+1);
ANS:= TERM + ANS;
K := K+2 >>;
RETURN ANS
END;
COS(F) + COS(1/2);
OFF ROUNDED;
COS(1/2);
COMMENT As an exercise, write a similar rule for the SIN or LOG, or
replace the COS rule with an improved one which uses angle reduction
so that angles outside a modest range are represented as equivalent
angles within the range, before computing the Taylor series;
PAUSE;
COMMENT There is a REDUCE compiler, and you may wish to learn the
local incantations for using it. However, even if rules such as
the above ones are compiled, they will be slow compared to the
implementation-dependent hand-coded ones used by most FORTRAN-like
systems, so REDUCE provides a way to generate FORTRAN programs which
can then be compiled and executed in a subsequent job step. This is
useful when there is a lot of floating-point computation or when we
wish to exploit an existing FORTRAN program. Suppose, for example,
that we wish to utilize an existing FORTRAN subroutine which uses the
Newton-Rapheson iteration
Xnew := Xold - SUB(X=Xold, F(X)/DF(F(X),X))
to attempt an approximate solution to the equation F(X)=0. Most such
subroutines require the user to provide a FORTRAN function or
subroutine which, given Xold, returns F(X)/DF(F(X),X) evaluated at
X=Xold. If F(X) is complicated, manual symbolic derivation of
DF(F(X),X) is a tedious and error-prone process. We can get
REDUCE to relieve us of this responsibility as is illustrated below
for the trivial example F(X) = X*E**X - 1:
ON FORT, ROUNDED,
OUT FONDFFILE,
WRITE " REAL FUNCTION FONDF(XOLD)",
WRITE " REAL XOLD, F",
F := XOLD*E**XOLD - 1.0,
FONDF := F/DF(F,XOLD),
WRITE " RETURN",
WRITE " END",
SHUT FONDFFILE .
COMMENT Under the influence of ON FORT, the output generated by
assignments is printed as valid FORTRAN assignment statements, using
as many continuation lines as necessary up to the amount specified
by the global variable !*CARDNO, which is initially set to 20. The
output generated by an expression which is not an assignment is a
corresponding assignment to a variable named ANS. In either case,
expressions which would otherwise exceed !*CARDNO continuation
lines are evaluated piecewise, using ANS as an intermediate variable.
Try executing the above sequence, using an appropriate filename and
using semicolons rather than commas at the end of the lines, then
print the file after the lesson to see how it worked;
PAUSE;
OFF FORT, ROUNDED;
COMMENT To make this technique usable by non-REDUCE programmers, we
could write a more general REDUCE program which given merely the
expression F by the user, outputs not only the function FONDF, but
also any necessary Job-control commands and an appropriate main
program for calling the Newton-Rapheson subroutine and printing the
results.
Sometimes it is desirable to modify or supplement the syntax
of REDUCE. For example:
1. Electrical engineers may prefer to input J as the representation
of (-1)**(1/2).
2. Many users may prefer to input LN to denote natural logarithms.
3. A user with previous exposure to the PL/I-FORMAC computer-
algebra system might prefer to use DERIV instead of DF to
request differentiation.
Such lexical macros can be established by the DEFINE declaration:;
CLEAR X,J;
DEFINE J=I, LN=LOG, DERIV=DF;
COMMENT Now watch!;
N := 3;
G1 := SUB(X=LN(J**3*X), DERIV(X**2,X));
COMMENT Each "equation" in a DEFINE declaration must be of the form
"name = item", where each item is an expression, an operator, or a
REDUCE-reserved word such as "FOR". Such replacements take place
during the lexical scanning, before any evaluation, LET rules, or
built-in simplification. Think of a good application for this
facility, then try it;
PAUSE;
COMMENT When REDUCE is being run in batch mode, it is preferable to
have REDUCE make reasonable decisions and proceed when it encounters
apparently undeclared operators, divisions by zero, etc. In
interactive mode, it is preferable to pause and query the user. ON
INT specifies the latter style, and OFF INT specifies the
former. Under the influence of OFF INT, we can also have most
error messages suppressed by specifying OFF MSG. This is sometimes
useful when we expect abnormal conditions and do not want our listing
marred by the associated messages. INT is automatically turned off
during input from a batch file in response to an IN-command from a
terminal.
Some implementations permit the user to dynamically request more
storage by executing a command of the form
CORE number,
where the number is an integer specifying the total desired core in
some units such as bytes, words, kilobytes, or kilowords;
PAUSE;
COMMENT Some implementations have a trace command for debugging,
which employs the syntax
TR functionname1, functionname2, ..., functionnameN .
An analogous command named UNTR removes function names from trace
status;
PAUSE;
COMMENT Some implementations have an assignment-tracing command for
debugging, which employs the syntax
TRST functionname1, functionname2, ..., functionnameN.
An analogous command named UNTRST removes functionnames from
this status. All assignments in the designated functions are
reported, except for assignments to array elements. Such functions
must be uncompiled and must have a top-level BEGIN-block. To apply
both TRST and TR to a function simultaneously, it is crucial to
request them in that order, and it is necessary to relinquish the two
kinds of tracing in the opposite order;
PAUSE;
COMMENT The REDUCE algebraic algorithms are written in a subset of
REDUCE called RLISP. In turn, the more sophisticated features of
RLISP are written in a small subset of RLISP which is written in a
subset of LISP that is relatively common to most LISP systems.
RLISP is ideal for implementing algebraic algorithms, but the RLISP
environment is not most suitable for the routine use of these
algorithms in the natural mathematical style of the preceding
lessons. Accordingly, REDUCE jobs are initially in a mode called
ALGEBRAIC, which provides the user with the environment illustrated
in the preceding lessons, while insulating him from accidental
interaction with the numerous functions, global variables, etc.
necessary for implementing the built-in algebra. In contrast, the
underlying RLISP system together with all of the algebraic
simplification algorithms written therein is called SYMBOLIC mode.
As we have seen, algebraic-mode rules and procedures can be used to
extend the built-in algebraic capabilities. However, some extensions
can be accomplished most easily or efficiently by descending to
SYMBOLIC mode.
To make REDUCE operate in symbolic mode, we merely execute the top
level mode-declaration statement consisting of the word SYMBOLIC. We
can subsequently switch back by executing the statement consisting of
the word ALGEBRAIC.
RLISP has the semantics of LISP with the syntax of our by-now-familiar
algebraic-mode REDUCE, so RLISP provides a natural tool for many
applications besides computer algebra, such as games, theorem-proving,
natural-language translation, computer-aided instruction, and
artificial intelligence in general. For this reason, it is possible
to run RLISP without any of the symbolic-mode algebraic algorithms
that are written in RLISP, and it is advisable to thus save space
when the application does not involve computer algebra.
We have now discussed virtually every feature that is available in
algebraic mode, so lesson 6 will deal solely with RLISP, and
lesson 7 will deal with communication between ALGEBRAIC and
SYMBOLIC mode for mathematical purposes. However, I suggest that
you proceed to those lessons only if and when:
1. You have consolidated and fully absorbed the information in
lessons 1 through 5 by considerable practice beyond the
exercises therein. (The exercises were intended to also
suggest good related project ideas.)
2. You feel the need for a facility which you believe is impossible
or quite awkward to implement solely in ALGEBRAIC mode.
3. You have read the pamphlet "Introduction to LISP", by D. Lurie,
or an equivalent.
4. You are familiar with definition of Standard LISP, as described
in the "Standard LISP Report" which was published in the October
1979 SIGPLAN Notices.
Remember, when you decide to take lesson 6, it is better to do so from
a RLISP job than from a REDUCE job. Also, don't forget to print your
newly generated FORTRAN file and to delete any temporary files created
by this lesson.
;END;