Up | Next | Prev | PrevTail | Tail |
A considerable degree of flexibility is available in REDUCE in the printing of expressions generated during calculations. No explicit format statements are supplied, as these are in most cases of little use in algebraic calculations, where the size of output or its composition is not generally known in advance. Instead, REDUCE provides a series of mode options to the user that should enable him to produce his output in a comprehensible and possibly pleasing form.
The most extreme option offered is to suppress the output entirely from any top level
evaluation. This is accomplished by turning off the switch output
which is normally
on. It is useful for limiting output when loading large files or producing “clean” output
from the prettyprint programs.
In most circumstances, however, we wish to view the output, so we need to know how to format it appropriately. As we mentioned earlier, an algebraic expression is normally printed in an expanded form, filling the whole output line with terms. Certain output declarations, however, can be used to affect this format. To begin with, we look at an operator for changing the length of the output line.
This operator is used with the syntax
linelength(num:integer):integer
and sets the output line length to the integer num
. It returns the previous output line
length (so that it can be stored for later resetting of the output line if needed).
We now describe a number of switches and declarations that are available for controlling
output formats. It should be noted, however, that the transformation of large expressions
to produce these varied output formats can take a lot of computing time and space. If a
user wishes to speed up the printing of the output in such cases, he can turn off the switch
pri
. If this is done, then output is produced in one fixed format, which basically reflects
the internal form of the expression, and none of the options below apply. pri
is normally
on.
With pri
on, the output declarations and switches available are as follows:
The declaration order
may be used to order variables on output. The syntax
is:
order v1,...vn;
where the vi
are kernels. Thus,
order x,y,z;
orders x
ahead of y
, y
ahead of z
and all three ahead of other variables not
given an order. order nil;
resets the output order to the system default.
The order of variables may be changed by further calls of order
, but then the
reordered variables would have an order lower than those in earlier order
calls.
Thus,
order x,y,z; order y,x;
would order z
ahead of y
and x
. The default ordering is usually alphabetic.
This declaration takes a list of identifiers or kernels as argument. factor
is not a
factoring command (use factorize
or the factor
switch for this purpose); rather
it is a separation command. All terms involving fixed powers of the declared
expressions are printed as a product of the fixed powers and a sum of the rest of the
terms.
For example, after the declaration
factor x;
the polynomial \((x+y+1)^{2}\) will be printed as
2 2 x + 2*x*(y + 1) + y + 2*y + 1
All expressions involving a given prefix operator may also be factored by putting the operator name in the list of factored identifiers. For example:
factor x,cos,sin(x);
causes all powers of x
and sin(x)
and all functions of cos
to be factored.
Note that factor
does not affect the order of its arguments. You should also use
order
if this is important.
The declaration remfac v1,...,vn;
removes the factoring flag from the
expressions v1
through vn
.
In addition to these declarations, the form of the output can be modified by switching
various output control switches using the declarations on
and off
. We shall
illustrate the use of these switches by an example, namely the printing of the
expression
x^2*(y^2+2*y)+x*(y^2+z)/(2*a) .
The relevant switches are as follows:
This switch will cause the system to search the whole expression, or any sub-expression
enclosed in parentheses, for simple multiplicative factors and print them outside the
parentheses. Thus our expression with allfac
off will print as
2 2 2 2 (2*x *y *a + 4*x *y*a + x*y + x*z)/(2*a)
and with allfac
on as
2 2 x*(2*x*y *a + 4*x*y*a + y + z)/(2*a) .
allfac
is normally on, and is on in the following examples, except where otherwise
stated.
This switch makes the system search the denominator of an expression for simple factors
that it divides into the numerator, so that rational fractions and negative powers appear in
the output. With div
on, our expression would print as
2 2 (-1) (-1) x*(x*y + 2*x*y + 1/2*y *a + 1/2*a *z) .
div
is normally off.
This switch causes the system to print polynomials according to Horner’s rule. With
horner
on, our expression prints as
2 x*(y + z + 2*(y + 2)*a*x*y)/(2*a) .
horner
is normally off.
This switch causes the system to print each term in any sum on a separate line. With
list
on, our expression prints as
2 x*(2*x*y *a + 4*x*y*a 2 + y + z)/(2*a) .
list
is normally off.
Under normal circumstances, the printing routines try to break an expression across
lines at a natural point. This is a fairly expensive process. If you are not overly
concerned about where the end-of-line breaks come, you can speed up the printing
of expressions by turning off the switch nosplit
. This switch is normally
on.
This switch is only useful with expressions in which variables are factored with
factor
. With this mode, the overall denominator of the expression is printed with each
factored sub-expression. We assume a prior declaration factor x;
in the following
output. We first print the expression with rat
set to off:
2 2 (2*x *y*a*(y + 2) + x*(y + z))/(2*a) .
With rat
on the output becomes:
2 2 x *y*(y + 2) + x*(y + z)/(2*a) .
rat
is normally off.
Next, if we leave x
factored, and turn on both div
and rat
, the result becomes
2 (-1) 2 x *y*(y + 2) + 1/2*x*a *(y + z) .
Finally, with x
factored, rat
on and allfac
off we retrieve the original structure
2 2 2 X *(Y + 2*Y) + X*(Y + Z)/(2*A) .
If the numerator and denominator of an expression can each be printed in one line, the
output routines will print them in a two dimensional notation, with numerator and
denominator on separate lines and a line of dashes in between. For example, (a+b)/2
will print as
a + b ----- 2
Turning this switch off causes such expressions to be output in a linear form.
The normal ordering of terms in output is from highest to lowest power. In
some situations (e.g., when a power series is output), the opposite ordering is
more convenient. The switch revpri
if on causes such a reverse ordering of
terms. For example, the expression y*(x+1)^2+(y+3)^2
will normally print
as
2 2 x *y + 2*x*y + y + 7*y + 9
whereas with REVPRI
on, it will print as
2 2 9 + 7*y + y + 2*x*y + x *y.
In simple cases no explicit output command is necessary in REDUCE, since the value of any expression is automatically printed if a semicolon is used as a delimiter. There are, however, several situations in which such a command is useful.
In a for
, while
, or repeat
statement it may be desired to output something each time
the statement within the loop construct is repeated.
It may be desired for a procedure to output intermediate results or other information while it is running. It may be desired to have results labeled in special ways, especially if the output is directed to a file or device other than the terminal.
The write
command consists of the word write
followed by one or more items
separated by commas, and followed by a terminator. There are three kinds of items that
can be used:
:=
operator is
evaluated, and is assigned to the variable on the left; then the symbol
on the left is printed, followed by a “:=
”, followed by the value of the
expression on the right – almost exactly the way an assignment followed by
a semicolon prints out normally. (The difference is that if the write
is in a
for
statement and the left-hand side of the assignment is an array position
or something similar containing the variable of the for
iteration, then the
value of that variable is inserted in the printout.)
"string"
).The items specified by a single write
statement print side by side on one line. (The line
is broken automatically if it is too long.) Strings print exactly as quoted. The write
command itself however does not return a value.
The print line is closed at the end of a write
command evaluation. Therefore the
command write "";
(specifying nothing to be printed except the empty string) causes
a line to be skipped.
Examples:
a
is x+5
, b
is itself, c
is 123, m
is an array, and q
=3, then
write m(q):=a," ",b/c," THANK YOU";
will set m(3)
to x+5
and print
b m(3) := x + 5 ----- THANK YOU 123
The blanks between the 5
and the fraction, and the fraction and t
, come from the
blanks in the quoted strings.
for i:=1:20 do write i," ",i^2;
a
:
for i:=1:20 do <<a(i):=i^2; write i," ",a(i)>>;
This will give us two columns of numbers. If we had used
for i:=1:20 do write i," ",a(i):=i^2;
we would also get a(
i) :=
repeated on each line.
x1:= -sig*(mu+2*eps)$ x2:= eps - 2*sig^2$ x3:= -3*mu*sig$ f:= 1$ g:= 0$ for i:= 1 step 1 until 10 do begin f1:= -mu*g+x1*df(f,eps)+x2*df(f,sig)+x3*df(f,mu); write "f(",i,") := ",f1; g1:= f+x1*df(g,eps)+x2*df(g,sig)+x3*df(g,mu); write "g(",i,") := ",g1; f:=f1$ g:=g1$ end;
A portion of the output, to illustrate the printout from the write
command, is as
follows:
... <prior output> ... 2 f(4) := mu*(3*eps - 15*sig + mu) g(4) := 6*sig*mu 2 f(5) := 15*sig*mu*( - 3*eps + 7*sig - mu) 2 g(5) := mu*(9*eps - 45*sig + mu) ... <more output> ...
When the switch nat
is turned off, write
adds a $
character to the end of the output
line, as illustrated below.
It is sometimes annoying to have zero assignments (i.e. assignments of the form
\(\langle \)expression\(\rangle \) := 0
) printed, especially in printing large arrays with many zero elements.
The output from such assignments can be suppressed by turning on the switch
nero
.
It is naturally possible to evaluate expressions numerically in REDUCE by giving all
variables and sub-expressions numerical values. However, as we pointed out elsewhere
the user must declare real arithmetical operation by turning on the switch rounded
.
However, it should be remembered that arithmetic in REDUCE is not particularly fast,
since results are interpreted rather than evaluated in a compiled form. The user
with a large amount of numerical computation after all necessary algebraic
manipulations have been performed is therefore well advised to perform these
calculations in a FORTRAN or similar system. For this purpose, REDUCE
offers facilities for users to produce FORTRAN compatible files for numerical
processing.
First, when the switch fort
is on, the system will print expressions in a FORTRAN
notation. Expressions begin in column seven. If an expression extends over one
line, a continuation mark (.) followed by a blank appears on subsequent cards.
After a certain number of lines have been produced (according to the value of
the variable card_no
), a new expression is started. If the expression printed
arises from an assignment to a variable, the variable is printed as the name
of the expression. Otherwise the expression is given the default name ans
.
An error occurs if identifiers or numbers are outside the bounds permitted by
FORTRAN.
A second option is to use the write
command to produce other programs.
Example:
The following REDUCE statements
on fort; out "forfil"; write "C this is a fortran program"; write " 1 format(e13.5)"; write " u=1.23"; write " v=2.17"; write " w=5.2"; x:=(u+v+w)^11; write "C it was foolish to expand this expression"; write " print 1,x"; write " end"; shut "forfil"; off fort;
will generate a file forfil
that contains:
c this is a fortran program 1 format(e13.5) u=1.23 v=2.17 w=5.2 ans1=1980.0*u**2*v**7*w**2+4620.0*u**2*v**6*w**3+6930.0*u**2*v . **5*w**4+6930.0*u**2*v**4*w**5+4620.0*u**2*v**3*w**6+1980.0*u . **2*v**2*w**7+495.0*u**2*v*w**8+55.0*u**2*w**9+11.0*u*v**10+ . 110.0*u*v**9*w+495.0*u*v**8*w**2+1320.0*u*v**7*w**3+2310.0*u*v . **6*w**4+2772.0*u*v**5*w**5+2310.0*u*v**4*w**6+1320.0*u*v**3*w . **7+495.0*u*v**2*w**8+110.0*u*v*w**9+11.0*u*w**10+v**11+11.0*v . **10*w+55.0*v**9*w**2+165.0*v**8*w**3+330.0*v**7*w**4+462.0*v . **6*w**5+462.0*v**5*w**6+330.0*v**4*w**7+165.0*v**3*w**8+55.0* . v**2*w**9+11.0*v*w**10+w**11 x=u**11+11.0*u**10*v+11.0*u**10*w+55.0*u**9*v**2+110.0*u**9*v*w . +55.0*u**9*w**2+165.0*u**8*v**3+495.0*u**8*v**2*w+495.0*u**8*v . *w**2+165.0*u**8*w**3+330.0*u**7*v**4+1320.0*u**7*v**3*w+ . 1980.0*u**7*v**2*w**2+1320.0*u**7*v*w**3+330.0*u**7*w**4+462.0 . *u**6*v**5+2310.0*u**6*v**4*w+4620.0*u**6*v**3*w**2+4620.0*u** . 6*v**2*w**3+2310.0*u**6*v*w**4+462.0*u**6*w**5+462.0*u**5*v**6 . +2772.0*u**5*v**5*w+6930.0*u**5*v**4*w**2+9240.0*u**5*v**3*w** . 3+6930.0*u**5*v**2*w**4+2772.0*u**5*v*w**5+462.0*u**5*w**6+ . 330.0*u**4*v**7+2310.0*u**4*v**6*w+6930.0*u**4*v**5*w**2+ . 11550.0*u**4*v**4*w**3+11550.0*u**4*v**3*w**4+6930.0*u**4*v**2 . *w**5+2310.0*u**4*v*w**6+330.0*u**4*w**7+165.0*u**3*v**8+ . 1320.0*u**3*v**7*w+4620.0*u**3*v**6*w**2+9240.0*u**3*v**5*w**3 . +11550.0*u**3*v**4*w**4+9240.0*u**3*v**3*w**5+4620.0*u**3*v**2 . *w**6+1320.0*u**3*v*w**7+165.0*u**3*w**8+55.0*u**2*v**9+495.0* . u**2*v**8*w+ans1 c it was foolish to expand this expression print 1,x end
If the arguments of a write
statement include an expression that requires continuation
records, the output will need editing, since the output routine prints the arguments of
write
sequentially, and the continuation mechanism therefore generates its auxiliary
variables after the preceding expression has been printed.
Finally, since there is no direct analog of list in FORTRAN, a comment line of the form
c ***** invalid fortran construct (list) not printed
will be printed if you try to print a list with fort
on.
There are a number of methods available to change the default format of the FORTRAN output.
The breakup of the expression into subparts is such that the number of continuation lines produced is less than a given number. This number can be modified by the assignment
card_no :=
\(\langle \)number\(\rangle \);
where \(\langle \)number\(\rangle \) is the total number of cards allowed in a statement. The default value of
card_no
is 20.
The width of the output expression is also adjustable by the assignment
fort_width :=
\(\langle \)integer\(\rangle \);
fort_width
which sets the total width of a given line to \(\langle \)integer\(\rangle \). The initial
FORTRAN output width is 70.
REDUCE automatically inserts a decimal point after each isolated integer coefficient in a
FORTRAN expression (so that, for example, 4 becomes 4.
). To prevent this, set the
period
mode switch to off
.
FORTRAN output is normally produced in lower case. If upper case is desired, the
switch fortupper
should be turned on.
Finally, the default name ans
assigned to an unnamed expression and its subparts can
be changed by the operator varname
. This takes a single identifier as argument,
which then replaces ans
as the expression name. The value of varname
is its
argument.
Further facilities for the production of FORTRAN and other language output are provided by the GENTRAN and SCOPE packages described in sections 20.24 and 20.53.
It is often useful to save an expression on an external file for use later as input in further
calculations. The commands for opening and closing output files are explained
elsewhere. However, we see in the examples on output of expressions that the standard
“natural” method of printing expressions is not compatible with the input syntax. So to
print the expression in an input compatible form we must inhibit this natural style by
turning off the switch nat
. If this is done, a dollar sign will also be printed at the end of
the expression.
Example:
The following sequence of commands
off nat; out "out"; x := (y+z)^2; write "end"; shut "out"; on nat;
will generate a file out
that contains
x := y**2 + 2*y*z + z**2$ end$
In those cases where the final result has a complicated form, it is often convenient to
display the skeletal structure of the answer. The operator structr
, that takes a single
expression as argument, will do this for you. Its syntax is:
structr(exprn:algebraic [,id1:identifier[,id2:identifier]]);
The structure is printed effectively as a tree, in which the subparts are laid out with
auxiliary names. If the optional id1
is absent, the auxiliary names are prefixed by the
root ans
. This root may be changed by the operator varname
. If the optional id1
is
present, and is an array name, the subparts are named as elements of that array, otherwise
id1
is used as the root prefix. (The second optional argument id2
is explained
later.)
The exprn
can be either a scalar or a matrix expression. Use of any other will result in
an error.
Example:
Let us suppose that the workspace contains ((a+b)^2+c)^3+d
. Then the input
STRUCTR ws;
will (with exp
off) result in the output:
ans3 where 3 ans3 := ans2 + d 2 ans2 := ans1 + c ans1 := a + b
The workspace remains unchanged after this operation, since structr
in the default
situation returns no value (if structr
is used as a sub-expression, its value is taken to
be 0). In addition, the sub-expressions are normally only displayed and not retained. If
you wish to access the sub-expressions with their displayed names, the switch
savestructr
should be turned on. In this case, structr
returns a list whose first
element is a representation for the expression, and subsequent elements are the
sub-expression relations. Thus, with savestructr
on, structr ws
in the above
example would return
3 2 {ans3,ans3=ans2 + d,ans2=ans1 + c,ans1=a + b}
The part
operator can be used to retrieve the required parts of the expression. For
example, to get the value of ans2
in the above, one could say:
part(ws,3,2);
If fort
is on, then the results are printed in the reverse order; the algorithm in fact
guaranteeing that no sub-expression will be referenced before it is defined. The second
optional argument id2
may also be used in this case to name the actual expression (or
expressions in the case of a matrix argument).
Example:
Let us suppose that m
, a 2 by 1 matrix, contains the elements ((a+b)^2 + c)^3 +
d
and (a + b)*(c + d)
respectively, and that v
has been declared to be an array.
With exp
off and fort
on, the statement structr(2*m,v,k);
will result in the
output
v(1)=a+b v(2)=v(1)**2+c v(3)=v(2)**3+d v(4)=c+d k(1,1)=2.*v(3) k(2,1)=2.*v(1)*v(4)
Up | Next | Prev | PrevTail | Front |