Origin for each line in Lesson_4.red from check-in f2c04ccdad:

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;

iCAS Bundled REDUCE Scripts
Homepage | GitHub Mirror | SourceHut Mirror | NotABug Mirror | Chisel Mirror | Chisel RSS ]