f2c04ccdad 2021-03-03 1: COMMENT
f2c04ccdad 2021-03-03 2:
f2c04ccdad 2021-03-03 3: REDUCE INTERACTIVE LESSON NUMBER 4
f2c04ccdad 2021-03-03 4:
f2c04ccdad 2021-03-03 5: David R. Stoutemyer
f2c04ccdad 2021-03-03 6: University of Hawaii
f2c04ccdad 2021-03-03 7:
f2c04ccdad 2021-03-03 8:
f2c04ccdad 2021-03-03 9: COMMENT This is lesson 4 of 7 REDUCE lessons. As before, please
f2c04ccdad 2021-03-03 10: refrain from using variables beginning with the letters F through H
f2c04ccdad 2021-03-03 11: during the lesson.
f2c04ccdad 2021-03-03 12:
f2c04ccdad 2021-03-03 13: In theory, assignments and LET statements are sufficient to accomplish
f2c04ccdad 2021-03-03 14: anything that any other practical computing mechanism is capable of
f2c04ccdad 2021-03-03 15: doing. However, it is more convenient for some purposes to use
f2c04ccdad 2021-03-03 16: function procedures which can employ branch selection and iteration as
f2c04ccdad 2021-03-03 17: do most traditional programming languages. As a trivial example, if
f2c04ccdad 2021-03-03 18: we invariably wanted to replace cotangents with the corresponding
f2c04ccdad 2021-03-03 19: tangents, we could input:;
f2c04ccdad 2021-03-03 20:
f2c04ccdad 2021-03-03 21: algebraic procedure cotan(x); 1/tan(x);
f2c04ccdad 2021-03-03 22:
f2c04ccdad 2021-03-03 23: COMMENT As an example of the use of this function, we have;
f2c04ccdad 2021-03-03 24:
f2c04ccdad 2021-03-03 25: cotan(log(f));
f2c04ccdad 2021-03-03 26:
f2c04ccdad 2021-03-03 27: pause;
f2c04ccdad 2021-03-03 28:
f2c04ccdad 2021-03-03 29: COMMENT Note:
f2c04ccdad 2021-03-03 30:
f2c04ccdad 2021-03-03 31: 1. The procedure definition automatically declares the procedure
f2c04ccdad 2021-03-03 32: name as an operator.
f2c04ccdad 2021-03-03 33: 2. A procedure can be executed any time after its definition,
f2c04ccdad 2021-03-03 34: until it is cleared.
f2c04ccdad 2021-03-03 35: 3. Any parameters are dummy variables that are distinct from any
f2c04ccdad 2021-03-03 36: other variables with the same name outside the procedure
f2c04ccdad 2021-03-03 37: definition, and the corresponding arguments can be arbitrary
f2c04ccdad 2021-03-03 38: expressions.
f2c04ccdad 2021-03-03 39: 4. The value returned by a procedure is the value of the
f2c04ccdad 2021-03-03 40: expression following the procedure statement.
f2c04ccdad 2021-03-03 41: 5. The function COT is already defined in REDUCE and should not be
f2c04ccdad 2021-03-03 42: redefined.
f2c04ccdad 2021-03-03 43:
f2c04ccdad 2021-03-03 44: We can replace this definition with a different one:;
f2c04ccdad 2021-03-03 45:
f2c04ccdad 2021-03-03 46: algebraic procedure cotan(y); cos(y)/sin(y);
f2c04ccdad 2021-03-03 47:
f2c04ccdad 2021-03-03 48: g1 := cotan(log(f));
f2c04ccdad 2021-03-03 49:
f2c04ccdad 2021-03-03 50: COMMENT In place of the word ALGEBRAIC, we can optionally use the word
f2c04ccdad 2021-03-03 51: INTEGER when a function always returns an integer value, or we can
f2c04ccdad 2021-03-03 52: optionally use the word REAL when a function always returns a
f2c04ccdad 2021-03-03 53: floating-point value. (ALGEBRAIC can also be omitted, since it is the
f2c04ccdad 2021-03-03 54: default procedure type.)
f2c04ccdad 2021-03-03 55:
f2c04ccdad 2021-03-03 56: Try writing a procedure definition for the sine in terms of the
f2c04ccdad 2021-03-03 57: cosine, then type G1.;
f2c04ccdad 2021-03-03 58:
f2c04ccdad 2021-03-03 59: pause;
f2c04ccdad 2021-03-03 60:
f2c04ccdad 2021-03-03 61: COMMENT Here is a more complicated function which introduces the
f2c04ccdad 2021-03-03 62: notion of a conditional expression:;
f2c04ccdad 2021-03-03 63:
f2c04ccdad 2021-03-03 64: algebraic procedure sumcheck(aj, j, m, n, s);
f2c04ccdad 2021-03-03 65: COMMENT J is an indeterminate and the other parameters are
f2c04ccdad 2021-03-03 66: expressions. This function returns the global variable named
f2c04ccdad 2021-03-03 67: PROVED if the function can inductively verify that S equals the
f2c04ccdad 2021-03-03 68: sum of AJ for J going from M through N, returning the global
f2c04ccdad 2021-03-03 69: variable named UNPROVED otherwise. For the best chance of
f2c04ccdad 2021-03-03 70: proving a correct sum, the function should be executed under the
f2c04ccdad 2021-03-03 71: influence of ON EXP, ON MCD, and any other user-supplied
f2c04ccdad 2021-03-03 72: simplification rules relevant to the expression classes of AJ
f2c04ccdad 2021-03-03 73: and S;
f2c04ccdad 2021-03-03 74: if sub(j=m,aj) - sub(n=m,s) neq 0 or
f2c04ccdad 2021-03-03 75: s + sub(j=n+1,aj) - sub(n=n+1,s) neq 0 then unproved
f2c04ccdad 2021-03-03 76: else proved;
f2c04ccdad 2021-03-03 77:
f2c04ccdad 2021-03-03 78: on exp, mcd;
f2c04ccdad 2021-03-03 79:
f2c04ccdad 2021-03-03 80: clear x, j, n;
f2c04ccdad 2021-03-03 81:
f2c04ccdad 2021-03-03 82: sumcheck(j, j, 1, n, n*(n+1)/2);
f2c04ccdad 2021-03-03 83:
f2c04ccdad 2021-03-03 84: sumcheck(x^j, j, 0, n, (x^(n+1)-1)/(x-1));
f2c04ccdad 2021-03-03 85:
f2c04ccdad 2021-03-03 86: COMMENT Within procedures of this sort a global variable is any
f2c04ccdad 2021-03-03 87: variable which is not one of the parameters, and a global variable has
f2c04ccdad 2021-03-03 88: the value, if any, which is current for that name at the point from
f2c04ccdad 2021-03-03 89: where the procedure is used.;
f2c04ccdad 2021-03-03 90:
f2c04ccdad 2021-03-03 91: pause;
f2c04ccdad 2021-03-03 92:
f2c04ccdad 2021-03-03 93: COMMENT Conditional expressions have the form
f2c04ccdad 2021-03-03 94:
f2c04ccdad 2021-03-03 95: IF condition THEN expression1 ELSE expression2.
f2c04ccdad 2021-03-03 96:
f2c04ccdad 2021-03-03 97: There are generally several equivalent ways of writing a conditional
f2c04ccdad 2021-03-03 98: expression. For example, the body of the above procedure could have
f2c04ccdad 2021-03-03 99: been written
f2c04ccdad 2021-03-03 100:
f2c04ccdad 2021-03-03 101: IF SUB(J=M,AJ) - SUB(N=M,S) = 0 AND
f2c04ccdad 2021-03-03 102: S + SUB(J=N+1,AJ) - SUB(N=N+1,S) = 0 THEN PROVED
f2c04ccdad 2021-03-03 103: ELSE UNPROVED.
f2c04ccdad 2021-03-03 104:
f2c04ccdad 2021-03-03 105: Note how we compare a difference with 0, rather than comparing two
f2c04ccdad 2021-03-03 106: nonzero expressions, for reasons explained in lesson 3.
f2c04ccdad 2021-03-03 107:
f2c04ccdad 2021-03-03 108: As an exercise, write a procedure analogous to SUMCHECK for proving
f2c04ccdad 2021-03-03 109: closed-form product formulas, then test it on the valid formula that
f2c04ccdad 2021-03-03 110: COS(N*X) equals the product of COS(J*X)/COS(J*X-X) for J ranging from
f2c04ccdad 2021-03-03 111: 1 through N. You do not need to include prefatory comments describing
f2c04ccdad 2021-03-03 112: parameters and the returned value until you learn how to use a text
f2c04ccdad 2021-03-03 113: editor.;
f2c04ccdad 2021-03-03 114:
f2c04ccdad 2021-03-03 115: pause;
f2c04ccdad 2021-03-03 116:
f2c04ccdad 2021-03-03 117: COMMENT Most REDUCE statements are also expressions because they have
f2c04ccdad 2021-03-03 118: a value. The value is usually 0 if nothing else makes sense, but I
f2c04ccdad 2021-03-03 119: will mention the value only if it is useful.
f2c04ccdad 2021-03-03 120:
f2c04ccdad 2021-03-03 121: The value of an assignment statement is the assigned value. Thus a
f2c04ccdad 2021-03-03 122: multiple assignment, performed right to left, can be achieved by a
f2c04ccdad 2021-03-03 123: sequence of the form
f2c04ccdad 2021-03-03 124:
f2c04ccdad 2021-03-03 125: variable1 := variable2 := ... := variableN := expression.
f2c04ccdad 2021-03-03 126:
f2c04ccdad 2021-03-03 127: Moreover, assignments can be inserted within ordinary expressions such
f2c04ccdad 2021-03-03 128: as X*(Y:=5). Such assignments must usually be parenthesized because
f2c04ccdad 2021-03-03 129: of the low precedence of the assignment operator, and excessive use of
f2c04ccdad 2021-03-03 130: this construct tends to make programs confusing.;
f2c04ccdad 2021-03-03 131:
f2c04ccdad 2021-03-03 132: pause;
f2c04ccdad 2021-03-03 133:
f2c04ccdad 2021-03-03 134: COMMENT REDUCE treats as a single expression any sequence of
f2c04ccdad 2021-03-03 135: statements preceded by the pair of adjacent characters << and followed
f2c04ccdad 2021-03-03 136: by the pair >>. The value of such a group expression is the value of
f2c04ccdad 2021-03-03 137: the last statement in the group.
f2c04ccdad 2021-03-03 138:
f2c04ccdad 2021-03-03 139: Group expressions facilitate the implementation of tasks that are most
f2c04ccdad 2021-03-03 140: easily stated as a sequence of operations. However, such sequences
f2c04ccdad 2021-03-03 141: often utilize temporary variables to count, hold intermediate results,
f2c04ccdad 2021-03-03 142: etc., and it is hazardous to use global variables for that purpose.
f2c04ccdad 2021-03-03 143: If a top-level REDUCE statement or another function directly or
f2c04ccdad 2021-03-03 144: indirectly uses that variable name, then its value or its virgin
f2c04ccdad 2021-03-03 145: indeterminate status there might be damaged by our use as a temporary
f2c04ccdad 2021-03-03 146: variable. In large programs or programs which rely on the work of
f2c04ccdad 2021-03-03 147: others, such interference has a non-negligible probability, even if
f2c04ccdad 2021-03-03 148: all programmers agree to the convention that all such temporary
f2c04ccdad 2021-03-03 149: variables should begin with the function name as a prefix and all
f2c04ccdad 2021-03-03 150: programmers attempt to comply with the convention. For this reason,
f2c04ccdad 2021-03-03 151: REDUCE provides another expression-valued sequence called a
f2c04ccdad 2021-03-03 152: BEGIN-block, which permits the declaration of local variables that are
f2c04ccdad 2021-03-03 153: distinct from any other variables outside the block having the same
f2c04ccdad 2021-03-03 154: name. Another advantage of using local variables for temporary
f2c04ccdad 2021-03-03 155: variables is that the perhaps large amount of storage occupied by
f2c04ccdad 2021-03-03 156: their values can be reclaimed after leaving their block.;
f2c04ccdad 2021-03-03 157:
f2c04ccdad 2021-03-03 158: pause;
f2c04ccdad 2021-03-03 159:
f2c04ccdad 2021-03-03 160: COMMENT A BEGIN-block consists of the word BEGIN, followed by optional
f2c04ccdad 2021-03-03 161: declarations, followed by a sequence of statements, followed by the
f2c04ccdad 2021-03-03 162: word END. Within BEGIN-blocks, it is often convenient to return
f2c04ccdad 2021-03-03 163: control and possibly a value from someplace other than the end of the
f2c04ccdad 2021-03-03 164: block. Control and a value may be returned via a RETURN-statement of
f2c04ccdad 2021-03-03 165: the form
f2c04ccdad 2021-03-03 166:
f2c04ccdad 2021-03-03 167: RETURN expression
f2c04ccdad 2021-03-03 168: or
f2c04ccdad 2021-03-03 169: RETURN,
f2c04ccdad 2021-03-03 170:
f2c04ccdad 2021-03-03 171: 0 being returned in the latter case. A BEGIN-block does not return
f2c04ccdad 2021-03-03 172: the value of the last statement. If a value is to be returned then
f2c04ccdad 2021-03-03 173: RETURN must be used. These features and others are illustrated by the
f2c04ccdad 2021-03-03 174: following function:;
f2c04ccdad 2021-03-03 175:
f2c04ccdad 2021-03-03 176: pause;
f2c04ccdad 2021-03-03 177:
f2c04ccdad 2021-03-03 178: algebraic procedure limit(ex, indet, pnt);
f2c04ccdad 2021-03-03 179: begin COMMENT This function uses up through 4 iterations of L'Hospital's
f2c04ccdad 2021-03-03 180: rule to attempt determination of the limit of expression EX as
f2c04ccdad 2021-03-03 181: indeterminate INDET approaches expression PNT. This function is
f2c04ccdad 2021-03-03 182: intended for the case where SUB(INDET=PNT, EX) yields 0/0,
f2c04ccdad 2021-03-03 183: provoking a zero-divide message. This function returns the
f2c04ccdad 2021-03-03 184: global variable named UNDEFINED when the limit is 0 dividing an
f2c04ccdad 2021-03-03 185: expression which did not simplify to 0, and this function
f2c04ccdad 2021-03-03 186: returns the global variable named UNKNOWN when it cannot
f2c04ccdad 2021-03-03 187: determine the limit. Otherwise this function returns an
f2c04ccdad 2021-03-03 188: expression which is the limit. For best results, this function
f2c04ccdad 2021-03-03 189: should be executed under the influence of ON EXP, ON MCD, and
f2c04ccdad 2021-03-03 190: any user-supplied simplification rules appropriate to the
f2c04ccdad 2021-03-03 191: expression classes of EX and PNT;
f2c04ccdad 2021-03-03 192: integer iteration;
f2c04ccdad 2021-03-03 193: scalar n, d, nlim, dlim;
f2c04ccdad 2021-03-03 194: iteration := 0;
f2c04ccdad 2021-03-03 195: n := num(ex);
f2c04ccdad 2021-03-03 196: d := den(ex);
f2c04ccdad 2021-03-03 197: nlim := sub(indet=pnt, n);
f2c04ccdad 2021-03-03 198: dlim := sub(indet=pnt, d);
f2c04ccdad 2021-03-03 199: while nlim=0 and dlim=0 and iteration<5 do <<
f2c04ccdad 2021-03-03 200: n := df(n, indet);
f2c04ccdad 2021-03-03 201: d := df(d, indet);
f2c04ccdad 2021-03-03 202: nlim := sub(indet=pnt, n);
f2c04ccdad 2021-03-03 203: dlim := sub(indet=pnt, d);
f2c04ccdad 2021-03-03 204: iteration := iteration + 1 >>;
f2c04ccdad 2021-03-03 205: return (if nlim=0 then
f2c04ccdad 2021-03-03 206: if dlim=0 then unknown
f2c04ccdad 2021-03-03 207: else 0
f2c04ccdad 2021-03-03 208: else if dlim=0 then undefined
f2c04ccdad 2021-03-03 209: else nlim/dlim)
f2c04ccdad 2021-03-03 210: end;
f2c04ccdad 2021-03-03 211:
f2c04ccdad 2021-03-03 212: % Examples follow...
f2c04ccdad 2021-03-03 213: pause;
f2c04ccdad 2021-03-03 214:
f2c04ccdad 2021-03-03 215: g1 := (e^x-1)/x;
f2c04ccdad 2021-03-03 216:
f2c04ccdad 2021-03-03 217: % Evaluation at 0 causes a zero denominator error at top level but
f2c04ccdad 2021-03-03 218: % continue anyway.
f2c04ccdad 2021-03-03 219: sub(x=0, g1);
f2c04ccdad 2021-03-03 220:
f2c04ccdad 2021-03-03 221: limit(g1, x, 0);
f2c04ccdad 2021-03-03 222:
f2c04ccdad 2021-03-03 223: g1:= ((1-x)/log(x))^2;
f2c04ccdad 2021-03-03 224:
f2c04ccdad 2021-03-03 225: % Evaluation at 1 causes a zero denominator error at top level but
f2c04ccdad 2021-03-03 226: % continue anyway.
f2c04ccdad 2021-03-03 227: sub(x=1, g1);
f2c04ccdad 2021-03-03 228:
f2c04ccdad 2021-03-03 229: limit(g1, x, 1);
f2c04ccdad 2021-03-03 230:
f2c04ccdad 2021-03-03 231: COMMENT Note:
f2c04ccdad 2021-03-03 232:
f2c04ccdad 2021-03-03 233: 1. The idea behind L'Hospital's rule is that as long as the
f2c04ccdad 2021-03-03 234: numerator and denominator are both zero at the limit point, we
f2c04ccdad 2021-03-03 235: can replace them by their derivatives without altering the
f2c04ccdad 2021-03-03 236: limit of the quotient.
f2c04ccdad 2021-03-03 237: 2. Assignments within groups and BEGIN-blocks do not automatically
f2c04ccdad 2021-03-03 238: cause output.
f2c04ccdad 2021-03-03 239: 3. Local variables are declared INTEGER, REAL, or SCALAR, the
f2c04ccdad 2021-03-03 240: latter corresponding to the same most general class denoted by
f2c04ccdad 2021-03-03 241: ALGEBRAIC in a procedure statement. All local variables are
f2c04ccdad 2021-03-03 242: initialized to zero, so they cannot serve as indeterminates.
f2c04ccdad 2021-03-03 243: Moreover, if we attempted to overcome this by clearing them, we
f2c04ccdad 2021-03-03 244: would clear all variables with their names.
f2c04ccdad 2021-03-03 245: 4. We do not declare the attributes of parameters.
f2c04ccdad 2021-03-03 246: 5. The NUM and DEN functions respectively extract the numerator
f2c04ccdad 2021-03-03 247: and denominator of their arguments. (With OFF MCD, the
f2c04ccdad 2021-03-03 248: denominator of 1+1/X would be 1.)
f2c04ccdad 2021-03-03 249: 6. The WHILE-loop has the general form
f2c04ccdad 2021-03-03 250:
f2c04ccdad 2021-03-03 251: WHILE condition DO statement.
f2c04ccdad 2021-03-03 252:
f2c04ccdad 2021-03-03 253: REDUCE also has a "GO TO" statement, and using commas rather
f2c04ccdad 2021-03-03 254: than semicolons to prevent termination of this comment, the
f2c04ccdad 2021-03-03 255: above general form of a WHILE-loop is equivalent to
f2c04ccdad 2021-03-03 256:
f2c04ccdad 2021-03-03 257: BEGIN GO TO TEST,
f2c04ccdad 2021-03-03 258: LOOP: statement,
f2c04ccdad 2021-03-03 259: TEST: IF condition THEN GO TO LOOP,
f2c04ccdad 2021-03-03 260: RETURN 0
f2c04ccdad 2021-03-03 261: END.
f2c04ccdad 2021-03-03 262:
f2c04ccdad 2021-03-03 263: A GOTO statement is permitted only within a block, and the GOTO
f2c04ccdad 2021-03-03 264: statement cannot refer to a label outside the same block or to
f2c04ccdad 2021-03-03 265: a label inside a block that the GOTO statement is not also
f2c04ccdad 2021-03-03 266: within. Actually, 99.99% of REDUCE BEGIN-blocks are less
f2c04ccdad 2021-03-03 267: confusing if written entirely without GOTOs, and I mention them
f2c04ccdad 2021-03-03 268: primarily to explain WHILE-loops in terms of a more primitive
f2c04ccdad 2021-03-03 269: notion.;
f2c04ccdad 2021-03-03 270:
f2c04ccdad 2021-03-03 271: pause;
f2c04ccdad 2021-03-03 272:
f2c04ccdad 2021-03-03 273: COMMENT
f2c04ccdad 2021-03-03 274: 7. The LIMIT function provides a good illustration of nested
f2c04ccdad 2021-03-03 275: conditional expressions. Proceeding sequentially through such
f2c04ccdad 2021-03-03 276: nests, each ELSE clause is matched with the nearest preceding
f2c04ccdad 2021-03-03 277: unmatched THEN clause in the group or block. In order to help
f2c04ccdad 2021-03-03 278: reveal their structure, I have consistently indented nested
f2c04ccdad 2021-03-03 279: conditional statements, continuations of multi-line statements
f2c04ccdad 2021-03-03 280: and loop-bodies according to one of the many staunchly defended
f2c04ccdad 2021-03-03 281: indentation styles. (If you have an instructor, I also urge
f2c04ccdad 2021-03-03 282: you to humor him by adopting his style for the duration of the
f2c04ccdad 2021-03-03 283: course.)
f2c04ccdad 2021-03-03 284: 8. C and Java programmers take note: "IF ... THEN ... ELSE ..." is
f2c04ccdad 2021-03-03 285: regarded as one expression, and semicolons are used to separate
f2c04ccdad 2021-03-03 286: rather than terminate statements. Moreover, BEGIN and END are
f2c04ccdad 2021-03-03 287: brackets rather than statements, so a semicolon is never needed
f2c04ccdad 2021-03-03 288: immediately after BEGIN, and a semicolon is necessary
f2c04ccdad 2021-03-03 289: immediately preceding END only if the END is intended as a
f2c04ccdad 2021-03-03 290: labeled destination for a GOTO. Within conditional
f2c04ccdad 2021-03-03 291: expressions, an inappropriate semicolon after an END, a >>, or
f2c04ccdad 2021-03-03 292: an ELSE-clause is likely to be one of your most prevalent
f2c04ccdad 2021-03-03 293: mistakes.;
f2c04ccdad 2021-03-03 294:
f2c04ccdad 2021-03-03 295: pause;
f2c04ccdad 2021-03-03 296:
f2c04ccdad 2021-03-03 297: COMMENT The next exercise is based on the above LIMIT function:
f2c04ccdad 2021-03-03 298:
f2c04ccdad 2021-03-03 299: For the sum of positive expressions AJ for J ranging from some finite
f2c04ccdad 2021-03-03 300: initial value to infinity, the infinite series converges if the limit
f2c04ccdad 2021-03-03 301: of the ratio SUB(J=J+1,AJ)/AJ is less than 1 as J approaches infinity.
f2c04ccdad 2021-03-03 302: The series diverges if this limit exceeds 1, and the test is
f2c04ccdad 2021-03-03 303: inconclusive if the limit is 1. To convert the problem to the form
f2c04ccdad 2021-03-03 304: required by the above LIMIT program, we can replace J by 1/!*FOO in
f2c04ccdad 2021-03-03 305: the ratio, then take the limit as the indeterminate !*FOO approaches
f2c04ccdad 2021-03-03 306: zero. (Since an indeterminate is necessary here, I picked the weird
f2c04ccdad 2021-03-03 307: name !*FOO to make the chance of conflict negligible.)
f2c04ccdad 2021-03-03 308:
f2c04ccdad 2021-03-03 309: After writing such a function to perform the ratio test, test it on
f2c04ccdad 2021-03-03 310: the examples AJ=J/2^J, AJ=1/J^2, AJ=2^J/J^10, and AJ=1/J. (The first
f2c04ccdad 2021-03-03 311: two converge and the second two diverge.);
f2c04ccdad 2021-03-03 312:
f2c04ccdad 2021-03-03 313: pause;
f2c04ccdad 2021-03-03 314:
f2c04ccdad 2021-03-03 315: COMMENT Groups or blocks can be used wherever any arbitrary expression
f2c04ccdad 2021-03-03 316: is allowed, including the right-hand side of a LET rule.
f2c04ccdad 2021-03-03 317:
f2c04ccdad 2021-03-03 318: The need for loops with an integer index variable running from a given
f2c04ccdad 2021-03-03 319: initial value through a given final value by a given increment is so
f2c04ccdad 2021-03-03 320: prevalent that REDUCE offers a convenient special way of accomplishing
f2c04ccdad 2021-03-03 321: it via a FOR-loop, which has the general form
f2c04ccdad 2021-03-03 322:
f2c04ccdad 2021-03-03 323: FOR index := initial STEP increment UNTIL final DO statement.
f2c04ccdad 2021-03-03 324:
f2c04ccdad 2021-03-03 325: Except for the use of commas as statement separators, this construct
f2c04ccdad 2021-03-03 326: is equivalent to
f2c04ccdad 2021-03-03 327:
f2c04ccdad 2021-03-03 328: BEGIN INTEGER index,
f2c04ccdad 2021-03-03 329: index := initial,
f2c04ccdad 2021-03-03 330: IF increment>0 THEN WHILE index <= final DO <<
f2c04ccdad 2021-03-03 331: statement,
f2c04ccdad 2021-03-03 332: index := index + increment >>
f2c04ccdad 2021-03-03 333: ELSE WHILE index >= final DO <<
f2c04ccdad 2021-03-03 334: statement,
f2c04ccdad 2021-03-03 335: index := index + increment >>,
f2c04ccdad 2021-03-03 336: RETURN 0
f2c04ccdad 2021-03-03 337: END;
f2c04ccdad 2021-03-03 338:
f2c04ccdad 2021-03-03 339: pause;
f2c04ccdad 2021-03-03 340:
f2c04ccdad 2021-03-03 341: COMMENT Note:
f2c04ccdad 2021-03-03 342:
f2c04ccdad 2021-03-03 343: 1. The index variable is automatically declared local to the FOR-
f2c04ccdad 2021-03-03 344: loop.
f2c04ccdad 2021-03-03 345: 2. "initial", "increment", and "final" must have integer values.
f2c04ccdad 2021-03-03 346: 3. FORTRAN programmers take note: the body of the loop is not
f2c04ccdad 2021-03-03 347: automatically executed at least once.
f2c04ccdad 2021-03-03 348: 4. An abbreviation for "STEP 1 UNTIL" is ":".
f2c04ccdad 2021-03-03 349: 5. Since the WHILE-loop and the FOR-loop have implied BEGIN-
f2c04ccdad 2021-03-03 350: blocks, a RETURN statement within their bodies cannot transfer
f2c04ccdad 2021-03-03 351: control further than the point following the loops.
f2c04ccdad 2021-03-03 352:
f2c04ccdad 2021-03-03 353: Another frequent need is to produce output from within a group or
f2c04ccdad 2021-03-03 354: block, because such output is not automatically produced. This can be
f2c04ccdad 2021-03-03 355: done using the WRITE-statement, which has the form
f2c04ccdad 2021-03-03 356:
f2c04ccdad 2021-03-03 357: WRITE expression1, expression2, ..., expressionN.
f2c04ccdad 2021-03-03 358:
f2c04ccdad 2021-03-03 359: Beginning a new line with expression1, the expressions are printed
f2c04ccdad 2021-03-03 360: immediately adjacent to each other, split over line boundaries if
f2c04ccdad 2021-03-03 361: necessary. The value of the WRITE-statement is the value of its last
f2c04ccdad 2021-03-03 362: expression, and any of the expressions can be a character-string of
f2c04ccdad 2021-03-03 363: the form "character1 character2 ... characterM".
f2c04ccdad 2021-03-03 364:
f2c04ccdad 2021-03-03 365: Inserting the word "WRITE" on a separate line before an assignment is
f2c04ccdad 2021-03-03 366: convenient for debugging, because the word is then easily deleted
f2c04ccdad 2021-03-03 367: afterward. These features and others are illustrated by the following
f2c04ccdad 2021-03-03 368: equation solver:;
f2c04ccdad 2021-03-03 369:
f2c04ccdad 2021-03-03 370: pause;
f2c04ccdad 2021-03-03 371:
f2c04ccdad 2021-03-03 372: operator solvefor, soln;
f2c04ccdad 2021-03-03 373:
f2c04ccdad 2021-03-03 374: for all x, lhs, rhs let solvefor(x, lhs, rhs) = solvefor(x, lhs-rhs);
f2c04ccdad 2021-03-03 375:
f2c04ccdad 2021-03-03 376: COMMENT LHS and RHS are expressions such that P=NUM(LHS-RHS) is a
f2c04ccdad 2021-03-03 377: polynomial of degree at most 2 in the indeterminate or functional form
f2c04ccdad 2021-03-03 378: X. Otherwise an error message is printed. As a convenience, RHS can
f2c04ccdad 2021-03-03 379: be omitted if it is 0. If P is quadratic in X, the two values of X
f2c04ccdad 2021-03-03 380: which satisfy P=0 are stored as the values of the functional forms
f2c04ccdad 2021-03-03 381: SOLN(1) and SOLN(2). If P is a first-degree polynomial in X, SOLN(1)
f2c04ccdad 2021-03-03 382: is set to the one solution. If P simplifies to 0, SOLN(1) is set to
f2c04ccdad 2021-03-03 383: the identifier ARBITRARY. If P is an expression which does not
f2c04ccdad 2021-03-03 384: simplify to zero but does not contain X, SOLN(1) is set to the
f2c04ccdad 2021-03-03 385: identifier NONE. In all other cases, SOLN(1) is set to the identifier
f2c04ccdad 2021-03-03 386: UNKNOWN. The function then returns the number of SOLN forms which
f2c04ccdad 2021-03-03 387: were set. This function prints a well deserved warning message if the
f2c04ccdad 2021-03-03 388: denominator of LHS-RHS contains X. If LHS-RHS is not polynomial in X,
f2c04ccdad 2021-03-03 389: it is wise to execute this function under the influence of ON GCD.;
f2c04ccdad 2021-03-03 390:
f2c04ccdad 2021-03-03 391: pause;
f2c04ccdad 2021-03-03 392:
f2c04ccdad 2021-03-03 393: for all x, lhsmrhs let solvefor(x, lhsmrhs) =
f2c04ccdad 2021-03-03 394: begin integer hipow; scalar temp, cflist, cf0, cf1, cf2;
f2c04ccdad 2021-03-03 395: if lhsmrhs = 0 then <<
f2c04ccdad 2021-03-03 396: soln(1) := arbitrary;
f2c04ccdad 2021-03-03 397: return 1 >>;
f2c04ccdad 2021-03-03 398: cflist := coeff(lhsmrhs, x);
f2c04ccdad 2021-03-03 399: hipow := hipow!*;
f2c04ccdad 2021-03-03 400: if hipow = 0 then <<
f2c04ccdad 2021-03-03 401: soln(1) := none;
f2c04ccdad 2021-03-03 402: return 1 >>;
f2c04ccdad 2021-03-03 403: if hipow > 2 then <<
f2c04ccdad 2021-03-03 404: soln(1) := unknown;
f2c04ccdad 2021-03-03 405: return 1 >>;
f2c04ccdad 2021-03-03 406: if hipow = 1 then <<
f2c04ccdad 2021-03-03 407: soln(1) := first(cflist)/second(cflist);
f2c04ccdad 2021-03-03 408: if df(sub(x=!*foo, soln(1)), !*foo) neq 0 then
f2c04ccdad 2021-03-03 409: soln(1) := unknown;
f2c04ccdad 2021-03-03 410: return 1 >>;
f2c04ccdad 2021-03-03 411: cf0 := first(cflist)/third(cflist);
f2c04ccdad 2021-03-03 412: cf1 := -second(cflist)/third(cflist)/2;
f2c04ccdad 2021-03-03 413: if df(sub(x=!*foo, cf0), !*foo) neq 0
f2c04ccdad 2021-03-03 414: or df(sub(x=!*foo, cf1), !*foo) neq 0 then <<
f2c04ccdad 2021-03-03 415: soln(1) := unknown;
f2c04ccdad 2021-03-03 416: return 1 >>;
f2c04ccdad 2021-03-03 417: temp := (cf1^2 - cf0)^(1/2);
f2c04ccdad 2021-03-03 418: soln(1) := cf1 + temp;
f2c04ccdad 2021-03-03 419: soln(2) := cf1 - temp;
f2c04ccdad 2021-03-03 420: return 2
f2c04ccdad 2021-03-03 421: end;
f2c04ccdad 2021-03-03 422:
f2c04ccdad 2021-03-03 423: COMMENT And some examples:;
f2c04ccdad 2021-03-03 424:
f2c04ccdad 2021-03-03 425: pause;
f2c04ccdad 2021-03-03 426:
f2c04ccdad 2021-03-03 427: for k:=1:solvefor(x, a*x^2, -b*x-c) do write soln(k) := soln(k);
f2c04ccdad 2021-03-03 428:
f2c04ccdad 2021-03-03 429: for k:=1:solvefor(log(x), 5*log(x)-7) do write soln(k) := soln(k);
f2c04ccdad 2021-03-03 430:
f2c04ccdad 2021-03-03 431: for k:=1:solvefor(x, x, x) do write soln(k) := soln(k);
f2c04ccdad 2021-03-03 432:
f2c04ccdad 2021-03-03 433: for k:= 1:solvefor(x, 5) do write soln(k) := soln(k);
f2c04ccdad 2021-03-03 434:
f2c04ccdad 2021-03-03 435: for k:=1:solvefor(x, x^3+x+1) do write soln(k) := soln(k);
f2c04ccdad 2021-03-03 436:
f2c04ccdad 2021-03-03 437: for k:=1:solvefor(x, x*e^x, 1) do write soln(k) := soln(k);
f2c04ccdad 2021-03-03 438:
f2c04ccdad 2021-03-03 439: g1 := x/(e^x-1);
f2c04ccdad 2021-03-03 440:
f2c04ccdad 2021-03-03 441: % Results in 'invalid as polynomial' error, continue anyway:;
f2c04ccdad 2021-03-03 442: for k:=1:solvefor(x, g1) do write soln(k) := soln(k);
f2c04ccdad 2021-03-03 443:
f2c04ccdad 2021-03-03 444: sub(x=soln(1), g1);
f2c04ccdad 2021-03-03 445:
f2c04ccdad 2021-03-03 446: limit(g1, x, soln(1));
f2c04ccdad 2021-03-03 447:
f2c04ccdad 2021-03-03 448: pause;
f2c04ccdad 2021-03-03 449:
f2c04ccdad 2021-03-03 450: COMMENT Here we have used LET rules to permit the user the convenience
f2c04ccdad 2021-03-03 451: of omitting default arguments. (Function definitions have to have a
f2c04ccdad 2021-03-03 452: fixed number of parameters.)
f2c04ccdad 2021-03-03 453:
f2c04ccdad 2021-03-03 454: Array elements are designated by the same syntax as matrix elements,
f2c04ccdad 2021-03-03 455: namely as functional forms having integer arguments. Here are some
f2c04ccdad 2021-03-03 456: desiderata that may help you decide which of these alternatives is
f2c04ccdad 2021-03-03 457: most appropriate for a particular application:
f2c04ccdad 2021-03-03 458:
f2c04ccdad 2021-03-03 459: 1. The lower bound of each array subscript is 0 vs. 1 for
f2c04ccdad 2021-03-03 460: matrices vs. unrestricted for functional forms.
f2c04ccdad 2021-03-03 461: 2. The upper bound of each array subscript must have a specific
f2c04ccdad 2021-03-03 462: integer value at the time the array is declared, as must the
f2c04ccdad 2021-03-03 463: upper bounds of matrix subscripts when a matrix is first
f2c04ccdad 2021-03-03 464: referred to, on the left side of a matrix assignment. In
f2c04ccdad 2021-03-03 465: contrast, functional forms never require a commitment to a
f2c04ccdad 2021-03-03 466: specific upper bound.
f2c04ccdad 2021-03-03 467: 3. An array can have any fixed number of subscripts, a matrix must
f2c04ccdad 2021-03-03 468: have exactly 2, and a functional form can have a varying
f2c04ccdad 2021-03-03 469: arbitrary number.
f2c04ccdad 2021-03-03 470: 4. Matrix operations, such as transpose and inverse, are built-in
f2c04ccdad 2021-03-03 471: only for matrices.
f2c04ccdad 2021-03-03 472: 5. For most implementations, access to array elements requires
f2c04ccdad 2021-03-03 473: time approximately proportional to the number of subscripts,
f2c04ccdad 2021-03-03 474: whereas access to matrix elements takes time approximately
f2c04ccdad 2021-03-03 475: proportional to the sum of the two subscript values, whereas
f2c04ccdad 2021-03-03 476: access to functional forms takes average time approximately
f2c04ccdad 2021-03-03 477: proportional to the number of bound functional forms having
f2c04ccdad 2021-03-03 478: that name.
f2c04ccdad 2021-03-03 479: 6. Only functional forms permit the effect of a subscripted
f2c04ccdad 2021-03-03 480: indeterminate such as having an answer be "A(M,N) + B(3,4)".
f2c04ccdad 2021-03-03 481: 7. Only functional forms can be used alone in the LHS of LET
f2c04ccdad 2021-03-03 482: substitutions.;
f2c04ccdad 2021-03-03 483:
f2c04ccdad 2021-03-03 484: pause;
f2c04ccdad 2021-03-03 485:
f2c04ccdad 2021-03-03 486: COMMENT
f2c04ccdad 2021-03-03 487: 8. All arrays, matrices, and operators are global regardless of
f2c04ccdad 2021-03-03 488: where they are declared, so declaring them within a BEGIN-block
f2c04ccdad 2021-03-03 489: does not afford the protection and automatic storage recovery
f2c04ccdad 2021-03-03 490: of local variables. Moreover, clearing them within a
f2c04ccdad 2021-03-03 491: BEGIN-block will clear them globally, and normal functions
f2c04ccdad 2021-03-03 492: cannot return an array or a matrix value. Furthermore, REDUCE
f2c04ccdad 2021-03-03 493: parameters are referenced by value, which means that an
f2c04ccdad 2021-03-03 494: assignment to a parameter has no effect on the corresponding
f2c04ccdad 2021-03-03 495: argument. Thus, matrix or array results cannot be transmitted
f2c04ccdad 2021-03-03 496: back to an argument either.
f2c04ccdad 2021-03-03 497:
f2c04ccdad 2021-03-03 498: 9. It is often advantageous to use two or more of these
f2c04ccdad 2021-03-03 499: alternatives to represent a set of quantities at different
f2c04ccdad 2021-03-03 500: times in the same program. For example, to get the general
f2c04ccdad 2021-03-03 501: form of the inverse of a 3-by-3 matrix, we could write
f2c04ccdad 2021-03-03 502:
f2c04ccdad 2021-03-03 503: MATRIX AA(3,3),
f2c04ccdad 2021-03-03 504: OPERATOR A,
f2c04ccdad 2021-03-03 505: FOR J:=1:3 DO
f2c04ccdad 2021-03-03 506: FOR K:=1:3 DO AA(J,K) := A(J,K),
f2c04ccdad 2021-03-03 507: AA^-1.
f2c04ccdad 2021-03-03 508:
f2c04ccdad 2021-03-03 509: As another example, we might use an array to receive some
f2c04ccdad 2021-03-03 510: polynomial coefficients, then transfer the values to a matrix
f2c04ccdad 2021-03-03 511: for inversion.;
f2c04ccdad 2021-03-03 512:
f2c04ccdad 2021-03-03 513: pause;
f2c04ccdad 2021-03-03 514:
f2c04ccdad 2021-03-03 515: COMMENT The COEFF function is the remaining new feature in our
f2c04ccdad 2021-03-03 516: SOLVEFOR example. The first argument is a polynomial expression in
f2c04ccdad 2021-03-03 517: the indeterminate or functional form which is the second argument.
f2c04ccdad 2021-03-03 518: The polynomial coefficients of the integer powers of the indeterminate
f2c04ccdad 2021-03-03 519: are returned as a LIST, with the independent coefficient first. The
f2c04ccdad 2021-03-03 520: highest and lowest non-zero powers are placed in the variables HIPOW!*
f2c04ccdad 2021-03-03 521: and LOWPOW!* respectively.
f2c04ccdad 2021-03-03 522:
f2c04ccdad 2021-03-03 523: A LIST is a kind of data structure, just as matrices and arrays are.
f2c04ccdad 2021-03-03 524: It is represented as a comma-separated sequence of elements enclosed
f2c04ccdad 2021-03-03 525: in braces. The elements can be accessed with the functions FIRST,
f2c04ccdad 2021-03-03 526: SECOND, THIRD, PART(i) which returns the i-th element, and REST, which
f2c04ccdad 2021-03-03 527: returns a list of all but the first element. For example:;
f2c04ccdad 2021-03-03 528:
f2c04ccdad 2021-03-03 529: clear x;
f2c04ccdad 2021-03-03 530:
f2c04ccdad 2021-03-03 531: coeff(x^5+2, x);
f2c04ccdad 2021-03-03 532:
f2c04ccdad 2021-03-03 533: lowpow!*;
f2c04ccdad 2021-03-03 534:
f2c04ccdad 2021-03-03 535: hipow!*;
f2c04ccdad 2021-03-03 536:
f2c04ccdad 2021-03-03 537: pause;
f2c04ccdad 2021-03-03 538:
f2c04ccdad 2021-03-03 539: COMMENT COEFF does not check to make sure that the coefficients do not
f2c04ccdad 2021-03-03 540: contain its second argument within a functional form, so that is the
f2c04ccdad 2021-03-03 541: reason we differentiated. The reason we first substituted the
f2c04ccdad 2021-03-03 542: indeterminate !*FOO for the second argument is that differentiation
f2c04ccdad 2021-03-03 543: does not work with respect to a functional form.
f2c04ccdad 2021-03-03 544:
f2c04ccdad 2021-03-03 545: The last exercise is to rewrite the last rule so that we can solve
f2c04ccdad 2021-03-03 546: equations which simplify to the form
f2c04ccdad 2021-03-03 547:
f2c04ccdad 2021-03-03 548: a*x^(m+2*l) + b*x^(m+l) + c*x^m = 0, where m >= 0 and l >= 1.
f2c04ccdad 2021-03-03 549:
f2c04ccdad 2021-03-03 550: The solutions are
f2c04ccdad 2021-03-03 551:
f2c04ccdad 2021-03-03 552: 0, with multiplicity m,
f2c04ccdad 2021-03-03 553: x1*E^(2*j*I*pi/l),
f2c04ccdad 2021-03-03 554: x2*E^(2*j*I*pi/l), with j = 0, 1, ..., l-1,
f2c04ccdad 2021-03-03 555:
f2c04ccdad 2021-03-03 556: where x1 and x2 are the solutions to the quadratic equation
f2c04ccdad 2021-03-03 557:
f2c04ccdad 2021-03-03 558: a*x^2 + b*x + c = 0.
f2c04ccdad 2021-03-03 559:
f2c04ccdad 2021-03-03 560: As a convenience to the user, you might also wish to have a global
f2c04ccdad 2021-03-03 561: switch named SOLVEPRINT, such that when it is nonzero, the solutions
f2c04ccdad 2021-03-03 562: are automatically printed.
f2c04ccdad 2021-03-03 563:
f2c04ccdad 2021-03-03 564: This is the end of lesson 4. When you are ready to run lesson 5,
f2c04ccdad 2021-03-03 565: start a new REDUCE session.
f2c04ccdad 2021-03-03 566:
f2c04ccdad 2021-03-03 567: ;end;