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

f2c04ccdad 2021-03-03 trnsz@pobox.c: COMMENT
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c:                   REDUCE INTERACTIVE LESSON NUMBER 3
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c:                          David R. Stoutemyer
f2c04ccdad 2021-03-03 trnsz@pobox.c:                          University of Hawaii
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c:                         Update for REDUCE 3.4
f2c04ccdad 2021-03-03 trnsz@pobox.c:                             Herbert Melenk
f2c04ccdad 2021-03-03 trnsz@pobox.c:                       Konrad-Zuse-Zentrum Berlin
f2c04ccdad 2021-03-03 trnsz@pobox.c:                                    
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: COMMENT This is lesson 3 of 7 REDUCE lessons.  Please refrain from
f2c04ccdad 2021-03-03 trnsz@pobox.c: using variables beginning with the letters F through H during the
f2c04ccdad 2021-03-03 trnsz@pobox.c: lesson.
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: Mathematics is replete with many named elementary and not-so-
f2c04ccdad 2021-03-03 trnsz@pobox.c: elementary functions besides the set built into REDUCE such as SIN,
f2c04ccdad 2021-03-03 trnsz@pobox.c: COS, and LOG, and it is often convenient to utilize expressions
f2c04ccdad 2021-03-03 trnsz@pobox.c: containing a functional form such as F(X) to denote an unknown
f2c04ccdad 2021-03-03 trnsz@pobox.c: function or a class of functions.  Functions are called operators in
f2c04ccdad 2021-03-03 trnsz@pobox.c: REDUCE, and by merely declaring their names as such, we are free to
f2c04ccdad 2021-03-03 trnsz@pobox.c: use them for functional forms.  For example:;
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: operator f;
f2c04ccdad 2021-03-03 trnsz@pobox.c: g1 := f(f(cot(f)), f());
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: COMMENT Note that
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c:    1.  We can use the same name for both a variable and an operator.
f2c04ccdad 2021-03-03 trnsz@pobox.c:        (However, this practice often leads to confusion.)
f2c04ccdad 2021-03-03 trnsz@pobox.c:    2.  We can use the same operator for any number of arguments --
f2c04ccdad 2021-03-03 trnsz@pobox.c:        including zero arguments such as for F().
f2c04ccdad 2021-03-03 trnsz@pobox.c:    3.  We can assign values to specific instances of functional
f2c04ccdad 2021-03-03 trnsz@pobox.c:        forms.;
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: pause;
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: COMMENT COT is one of the functions already defined in REDUCE together
f2c04ccdad 2021-03-03 trnsz@pobox.c: with a few of its properties.  However, you can augment or even
f2c04ccdad 2021-03-03 trnsz@pobox.c: override these definitions depending on the needs of a given problem.
f2c04ccdad 2021-03-03 trnsz@pobox.c: For example, if you wished to write COT(F) in terms of TAN, you could
f2c04ccdad 2021-03-03 trnsz@pobox.c: say:;
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: cot(f) := 1/tan(f);
f2c04ccdad 2021-03-03 trnsz@pobox.c: g1 := g1 + cot(h+1);
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: pause;
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: COMMENT Naturally, our assignment for COT(F) did not affect COT(H+1)
f2c04ccdad 2021-03-03 trnsz@pobox.c: in our example above.  However, we can use a LET rule to make all
f2c04ccdad 2021-03-03 trnsz@pobox.c: cotangents automatically be replaced by the reciprocal of the
f2c04ccdad 2021-03-03 trnsz@pobox.c: corresponding tangents:;
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: let cot(~f) => 1/tan(f);
f2c04ccdad 2021-03-03 trnsz@pobox.c: g1;
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: COMMENT Any variable preceded by a tilde is a dummy variable which is
f2c04ccdad 2021-03-03 trnsz@pobox.c: distinct from any other previously or subsequently introduced
f2c04ccdad 2021-03-03 trnsz@pobox.c: indeterminate, variable, or dummy variable having the same name
f2c04ccdad 2021-03-03 trnsz@pobox.c: outside the rule.  The leftmost occurrence of a dummy variable in a
f2c04ccdad 2021-03-03 trnsz@pobox.c: rule must be marked with a tilde.
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: The arguments to LET are either single rules or lists (explicitly
f2c04ccdad 2021-03-03 trnsz@pobox.c: enclosed in {..} or as variables with list values).  All elements of a
f2c04ccdad 2021-03-03 trnsz@pobox.c: list have to be rules (i.e., expressions written in terms of the
f2c04ccdad 2021-03-03 trnsz@pobox.c: operator "=>") or names of other rule lists.  So we could have written
f2c04ccdad 2021-03-03 trnsz@pobox.c: the above command either as
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c:       LET COT(~F) => 1/TAN(F)
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: or as the command sequence
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c:       RS := {COT(~F) => 1/TAN(F)}
f2c04ccdad 2021-03-03 trnsz@pobox.c:       LET RS
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: The CLEARRULES command clears one or more rules.  They have to be
f2c04ccdad 2021-03-03 trnsz@pobox.c: entered in the same form as for LET -- otherwise REDUCE is unable to
f2c04ccdad 2021-03-03 trnsz@pobox.c: identify them.;
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: clearrules cot(~f) => 1/tan(f);
f2c04ccdad 2021-03-03 trnsz@pobox.c: cot(g+5);
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: COMMENT Alternative forms would have been
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c:      CLEARRULES {COT(~F) => 1/TAN(F)}
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c:    or with the above value of RS
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c:      CLEARRULES RS
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: Note that CLEAR RS would not remove the rule(s) from the system -- it
f2c04ccdad 2021-03-03 trnsz@pobox.c: would only remove the list value from the variable RS.;
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: pause;
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: COMMENT The arguments of a functional form on the left-hand side of a
f2c04ccdad 2021-03-03 trnsz@pobox.c: rule can be more complicated than mere indeterminates.  For example,
f2c04ccdad 2021-03-03 trnsz@pobox.c: we may wish to inform REDUCE how to differentiate expressions
f2c04ccdad 2021-03-03 trnsz@pobox.c: involving a symbolic function P, whose derivative is expressed in
f2c04ccdad 2021-03-03 trnsz@pobox.c: terms of another function Q.;
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: operator p, q;
f2c04ccdad 2021-03-03 trnsz@pobox.c: let df(p(~x), x) => q(x)^2;
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: df(3*p(f*g), g);
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: COMMENT Also, REDUCE obviously knows the chain rule.;
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: pause;
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: COMMENT As another example, suppose that we wish to employ the
f2c04ccdad 2021-03-03 trnsz@pobox.c: angle-sum identities for SIN and COS:;
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: let {sin(~x+~y) => sin(x)*cos(y) + sin(y)*cos(x),
f2c04ccdad 2021-03-03 trnsz@pobox.c:      cos(~x+~y) => cos(x)*cos(y) - sin(x)*sin(y)};
f2c04ccdad 2021-03-03 trnsz@pobox.c: cos(5 + f - g);
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: COMMENT Note that:
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c:    1.  LET can have any number of replacement rules written as a list.
f2c04ccdad 2021-03-03 trnsz@pobox.c:    2.  There was no need for rules with 3 or more addends, because the
f2c04ccdad 2021-03-03 trnsz@pobox.c:        above rules were automatically employed recursively, with two
f2c04ccdad 2021-03-03 trnsz@pobox.c:        of the three addends 5, F, and -G grouped together as one of
f2c04ccdad 2021-03-03 trnsz@pobox.c:        the dummy variables the first time through.
f2c04ccdad 2021-03-03 trnsz@pobox.c:    3.  Despite the sub-expression F-G in our example, there was no
f2c04ccdad 2021-03-03 trnsz@pobox.c:        need to make rules for the difference of two angles, because
f2c04ccdad 2021-03-03 trnsz@pobox.c:        sub-expressions of the form X-Y are treated as X+(-Y).
f2c04ccdad 2021-03-03 trnsz@pobox.c:    4.  Built-in rules were employed to convert expressions of the form
f2c04ccdad 2021-03-03 trnsz@pobox.c:        SIN(-X) or COS(-X) to -SIN(X) or COS(X) respectively.
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: As an exercise, try to implement rules which transform the logarithms
f2c04ccdad 2021-03-03 trnsz@pobox.c: of products and quotients respectively to sums and differences of
f2c04ccdad 2021-03-03 trnsz@pobox.c: logarithms, while converting the logarithm of a power of a quantity to
f2c04ccdad 2021-03-03 trnsz@pobox.c: the power times the logarithm of the quantity.;
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: pause;
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: COMMENT Actually, the left-hand side of a rule also can be somewhat
f2c04ccdad 2021-03-03 trnsz@pobox.c: more general than a functional form.  The left-hand side can be a
f2c04ccdad 2021-03-03 trnsz@pobox.c: power of an indeterminate or of a functional form, or a product of
f2c04ccdad 2021-03-03 trnsz@pobox.c: such powers and/or indeterminates or functional forms.  For example,
f2c04ccdad 2021-03-03 trnsz@pobox.c: we can have the rule
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c:        SIN(~X)^2 => 1 - COS(~X)^2
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: or we can have the rule:;
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: let cos(~x)^2 => 1 - sin(~x)^2;
f2c04ccdad 2021-03-03 trnsz@pobox.c: g1 := cos(f)^3 + cos(g);
f2c04ccdad 2021-03-03 trnsz@pobox.c: pause;
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: COMMENT Note that a replacement takes place wherever the left-hand
f2c04ccdad 2021-03-03 trnsz@pobox.c: side of a rule divides a term.  With a rule replacing SIN(X)^2 and a
f2c04ccdad 2021-03-03 trnsz@pobox.c: rule replacing COS(X)^2 simultaneously in effect, an expression which
f2c04ccdad 2021-03-03 trnsz@pobox.c: uses either one will lead to an infinite recursion that eventually
f2c04ccdad 2021-03-03 trnsz@pobox.c: exhausts the available storage.  (Try it if you wish -- after the
f2c04ccdad 2021-03-03 trnsz@pobox.c: lesson).  We are also permitted to employ a more symmetric rule using
f2c04ccdad 2021-03-03 trnsz@pobox.c: a top level "+" provided that no free variables appear in the rule.
f2c04ccdad 2021-03-03 trnsz@pobox.c: However, a rule such as "SIN(~X)^2 + COS(X)^2 => 1" is not permitted.
f2c04ccdad 2021-03-03 trnsz@pobox.c: We can get around the restriction against a top-level "+" on the
f2c04ccdad 2021-03-03 trnsz@pobox.c: left-hand side though, at the minor nuisance of having to employ an
f2c04ccdad 2021-03-03 trnsz@pobox.c: operator whenever we want the rule applied to an expression:;
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: clearrules cos(~x)^2 => 1 - sin(~x)^2;
f2c04ccdad 2021-03-03 trnsz@pobox.c: operator trigsimp;
f2c04ccdad 2021-03-03 trnsz@pobox.c: trigsimp_rules := {
f2c04ccdad 2021-03-03 trnsz@pobox.c:    trigsimp(~a*sin(~x)^2 + a*cos(x)^2 + ~c) => a + trigsimp(c),
f2c04ccdad 2021-03-03 trnsz@pobox.c:    trigsimp(~a*sin(~x)^2 + a*cos(x)^2) => a,
f2c04ccdad 2021-03-03 trnsz@pobox.c:    trigsimp(sin(~x)^2 + cos(x)^2 + ~c) => 1 + trigsimp(c),
f2c04ccdad 2021-03-03 trnsz@pobox.c:    trigsimp(sin(~x)^2 + cos(x)^2) => 1,
f2c04ccdad 2021-03-03 trnsz@pobox.c:    trigsimp(~x) => x }$
f2c04ccdad 2021-03-03 trnsz@pobox.c: g1 := f*cos(g)^2 + f*sin(g)^2 + g*sin(g)^2 + g*cos(g)^2 + 5;
f2c04ccdad 2021-03-03 trnsz@pobox.c: g1 := trigsimp(g1) where trigsimp_rules;
f2c04ccdad 2021-03-03 trnsz@pobox.c: pause;
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: COMMENT Here we use another syntactical paradigm: the rule list is
f2c04ccdad 2021-03-03 trnsz@pobox.c: assigned to a name (here TRIGSIMP_RULES) and it is activated only
f2c04ccdad 2021-03-03 trnsz@pobox.c: locally for one evaluation, using the WHERE clause.
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: Why doesn't our rule TRIGSIMP(~X) => X defeat the other more specific
f2c04ccdad 2021-03-03 trnsz@pobox.c: ones?  The reason is that rules inside a list are applied in the order
f2c04ccdad 2021-03-03 trnsz@pobox.c: they are written, with the whole process immediately restarted
f2c04ccdad 2021-03-03 trnsz@pobox.c: whenever any rule succeeds.  Thus the rule TRIGSIMP(X) = X, intended
f2c04ccdad 2021-03-03 trnsz@pobox.c: to make the operator TRIGSIMP eventually evaporate, is tried only
f2c04ccdad 2021-03-03 trnsz@pobox.c: after all of the genuine simplification rules have done all they can.
f2c04ccdad 2021-03-03 trnsz@pobox.c: For such reasons we usually write rules for an operator in an order
f2c04ccdad 2021-03-03 trnsz@pobox.c: which proceeds from the most specific to the most general cases.
f2c04ccdad 2021-03-03 trnsz@pobox.c: Experimentation will reveal that TRIGSIMP will not simplify higher
f2c04ccdad 2021-03-03 trnsz@pobox.c: powers of sine and cosine, such as COS(X)^4 + 2*COS(X)^2*SIN(X)^2 +
f2c04ccdad 2021-03-03 trnsz@pobox.c: SIN(X)^4, and that TRIGSIMP will not necessarily work when there are
f2c04ccdad 2021-03-03 trnsz@pobox.c: more than 6 terms.  This latter restriction is not fundamental but is
f2c04ccdad 2021-03-03 trnsz@pobox.c: a practical one imposed to keep the combinatorial searching associated
f2c04ccdad 2021-03-03 trnsz@pobox.c: with the current algorithm under reasonable control.  As an exercise,
f2c04ccdad 2021-03-03 trnsz@pobox.c: see if you can generalize the rules sufficiently so that 5*COS(H)^2 +
f2c04ccdad 2021-03-03 trnsz@pobox.c: 6*SIN(H)^2 simplifies to 5 + SIN(H)^2 or to 6 - COS(H)^2.;
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: pause;
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: COMMENT Rules do not need to have free variables.  For example, we
f2c04ccdad 2021-03-03 trnsz@pobox.c: could introduce the simplification rule to replace all subsequent
f2c04ccdad 2021-03-03 trnsz@pobox.c: instances of M*C^2 by ENERGY:;
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: clear m, c, energy;
f2c04ccdad 2021-03-03 trnsz@pobox.c: g1 := (3*m^2*c^2 + m*c^3 + c^2 + m + m*c + m1*c1^2)
f2c04ccdad 2021-03-03 trnsz@pobox.c:               where m*c^2 => energy;
f2c04ccdad 2021-03-03 trnsz@pobox.c: pause;
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: COMMENT Suppose that instead we wish to replace M by ENERGY/C^2:;
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: g1 where m => energy/c^2;
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: COMMENT You may wonder how a rule of the trivial form 
f2c04ccdad 2021-03-03 trnsz@pobox.c: "indeterminate => ..." differs from the corresponding assignment 
f2c04ccdad 2021-03-03 trnsz@pobox.c: "indeterminate := ...".  The difference is this:
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c:    1.  The LET rule does not replace any contained bound
f2c04ccdad 2021-03-03 trnsz@pobox.c:        variables with their values until the rule is actually used for
f2c04ccdad 2021-03-03 trnsz@pobox.c:        a replacement.
f2c04ccdad 2021-03-03 trnsz@pobox.c:    2.  The LET rule performs the evaluation of any contained bound
f2c04ccdad 2021-03-03 trnsz@pobox.c:        variables every time the rule is used.
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: Thus, the rule "X => X + 1" would cause infinite recursion at the
f2c04ccdad 2021-03-03 trnsz@pobox.c: first subsequent occurrence of X, as would the pair of rules "{X => Y,
f2c04ccdad 2021-03-03 trnsz@pobox.c: Y => X}".  (Try it! -- After the lesson.)  To illustrate point 1
f2c04ccdad 2021-03-03 trnsz@pobox.c: above, compare the following command sequence with the analogous
f2c04ccdad 2021-03-03 trnsz@pobox.c: earlier one in lesson 2, which used assignments throughout:;
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: clear e1, f;
f2c04ccdad 2021-03-03 trnsz@pobox.c: e2 := f;
f2c04ccdad 2021-03-03 trnsz@pobox.c: let f1 => e1 + e2;
f2c04ccdad 2021-03-03 trnsz@pobox.c: f1;
f2c04ccdad 2021-03-03 trnsz@pobox.c: e2 := g;
f2c04ccdad 2021-03-03 trnsz@pobox.c: f1;
f2c04ccdad 2021-03-03 trnsz@pobox.c: pause;
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: COMMENT For a subsequent example, we need to replace E^(I*X) by
f2c04ccdad 2021-03-03 trnsz@pobox.c: COS(X)^2 + I*SIN(X)^2 for all X.  See if you can successfully
f2c04ccdad 2021-03-03 trnsz@pobox.c: introduce this rule.  (Without it, the following code will not work
f2c04ccdad 2021-03-03 trnsz@pobox.c: correctly!);
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: pause;
f2c04ccdad 2021-03-03 trnsz@pobox.c: e^i;
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: COMMENT REDUCE does not match I as an instance of the pattern I*X with
f2c04ccdad 2021-03-03 trnsz@pobox.c: X = 1, so if you neglected to include a rule for this degenerate case,
f2c04ccdad 2021-03-03 trnsz@pobox.c: do so now.;
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: pause;
f2c04ccdad 2021-03-03 trnsz@pobox.c: clear x, n, nminusone;
f2c04ccdad 2021-03-03 trnsz@pobox.c: zero := e^(n*i*x) - e^(nminusone*i*x)*e^(i*x);
f2c04ccdad 2021-03-03 trnsz@pobox.c: realzero := sub(i=0, zero);
f2c04ccdad 2021-03-03 trnsz@pobox.c: imagzero := sub(i=0, -i*zero);
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: COMMENT Regarding the last two assignments as equations, we can solve
f2c04ccdad 2021-03-03 trnsz@pobox.c: them to get recurrence relations defining SIN(N*X) and COS(N*X) in
f2c04ccdad 2021-03-03 trnsz@pobox.c: terms of angles having lower multiplicity.
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: Can you figure out why I didn't use N-1 rather than NMINUSONE above?
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: Can you devise a similar technique to derive the angle-sum identities
f2c04ccdad 2021-03-03 trnsz@pobox.c: that we previously implemented?;
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: pause;
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: COMMENT To implement a set of trigonometric multiple-angle expansion
f2c04ccdad 2021-03-03 trnsz@pobox.c: rules, we need to match the patterns SIN(N*X) and COS(N*X) only when N
f2c04ccdad 2021-03-03 trnsz@pobox.c: is an integer exceeding 1.  We can implement one of the necessary
f2c04ccdad 2021-03-03 trnsz@pobox.c: rules as follows:;
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c:    cos(~n*~x) => cos(x)*cos((n-1)*x) - sin(x)*sin((n-1)*x)
f2c04ccdad 2021-03-03 trnsz@pobox.c:              when fixp n and n>1;
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: COMMENT Note:
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c:    1.  In a conditional rule, any dummy variables should appear in the
f2c04ccdad 2021-03-03 trnsz@pobox.c:        left-hand side of the replacement with a tilde.
f2c04ccdad 2021-03-03 trnsz@pobox.c:    2.  FIXP, standing for FIX Predicate, is a built-in function which
f2c04ccdad 2021-03-03 trnsz@pobox.c:        yields true if and only if its argument is an integer.  Other
f2c04ccdad 2021-03-03 trnsz@pobox.c:        useful predicates are NUMBERP, which is true if its argument
f2c04ccdad 2021-03-03 trnsz@pobox.c:        represents a numeric value, that is an integer, a rational
f2c04ccdad 2021-03-03 trnsz@pobox.c:        number or a rounded (floating point) number, and EVENP, which
f2c04ccdad 2021-03-03 trnsz@pobox.c:        is true if its argument is an integer multiple of 2.
f2c04ccdad 2021-03-03 trnsz@pobox.c:    3.  Arbitrarily-complicated true-false conditions can be composed
f2c04ccdad 2021-03-03 trnsz@pobox.c:        using the relational operators =, NEQ, <, >, <=, >=, together
f2c04ccdad 2021-03-03 trnsz@pobox.c:        with the logical operators "AND", "OR", "NOT".
f2c04ccdad 2021-03-03 trnsz@pobox.c:    4.  The operators < , >, <=, and >= work only when both sides are
f2c04ccdad 2021-03-03 trnsz@pobox.c:        numbers.
f2c04ccdad 2021-03-03 trnsz@pobox.c:    5.  The relational operators have higher precedence than "NOT",
f2c04ccdad 2021-03-03 trnsz@pobox.c:        which has higher precedence than "AND", which has higher
f2c04ccdad 2021-03-03 trnsz@pobox.c:        precedence than "OR".
f2c04ccdad 2021-03-03 trnsz@pobox.c:    6.  In a sequence of expressions joined by "AND" operators, testing
f2c04ccdad 2021-03-03 trnsz@pobox.c:        is done left to right, and testing is discontinued after the
f2c04ccdad 2021-03-03 trnsz@pobox.c:        first item which is false.
f2c04ccdad 2021-03-03 trnsz@pobox.c:    7.  In a sequence of expressions joined by "OR" operators, testing
f2c04ccdad 2021-03-03 trnsz@pobox.c:        is done left to right, and testing is discontinued after the
f2c04ccdad 2021-03-03 trnsz@pobox.c:        first item which is true.
f2c04ccdad 2021-03-03 trnsz@pobox.c:    8.  We didn't actually need the "AND N>1" part in the above rule.
f2c04ccdad 2021-03-03 trnsz@pobox.c:        Can you guess why?
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: Your mission is to complete the set of multiple-angle rules and to
f2c04ccdad 2021-03-03 trnsz@pobox.c: test them on the example COS(4*X) + COS(X/3) + COS(F*X).;
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: pause;
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: COMMENT Now suppose that we wish to write a set of rules for doing
f2c04ccdad 2021-03-03 trnsz@pobox.c: symbolic integration, such that expressions of the form
f2c04ccdad 2021-03-03 trnsz@pobox.c: INTEGRATE(X^P, X) are replaced by X^(P+1)/(P+1) for arbitrary X and P,
f2c04ccdad 2021-03-03 trnsz@pobox.c: provided P is independent of X.  This will of course be less complete
f2c04ccdad 2021-03-03 trnsz@pobox.c: that the analytic integration package available with REDUCE, but for
f2c04ccdad 2021-03-03 trnsz@pobox.c: specific classes of integrals it is often a reasonable way to do such
f2c04ccdad 2021-03-03 trnsz@pobox.c: integration.  Noting that DF(P,X) is 0 if P is independent of X, we
f2c04ccdad 2021-03-03 trnsz@pobox.c: can accomplish this as follows:;
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: operator integrate;
f2c04ccdad 2021-03-03 trnsz@pobox.c: let integrate(~x^~p, x) => x^(p+1)/(p+1) when df(p, x) = 0;
f2c04ccdad 2021-03-03 trnsz@pobox.c: integrate(f^5, f);
f2c04ccdad 2021-03-03 trnsz@pobox.c: integrate(g^g, g);
f2c04ccdad 2021-03-03 trnsz@pobox.c: integrate(f^g, f);
f2c04ccdad 2021-03-03 trnsz@pobox.c: pause;
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: g1 := integrate(g*f^5, f) + integrate(f^5+f^g, f);
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: COMMENT The last example indicates that we must incorporate rules
f2c04ccdad 2021-03-03 trnsz@pobox.c: which distribute integrals over sums and extract factors which are
f2c04ccdad 2021-03-03 trnsz@pobox.c: independent of the second argument of INTEGRATE.  Can you think of
f2c04ccdad 2021-03-03 trnsz@pobox.c: rules which accomplish this?  It is a good exercise, but this
f2c04ccdad 2021-03-03 trnsz@pobox.c: particular pair of properties of INTEGRATE is so prevalent in
f2c04ccdad 2021-03-03 trnsz@pobox.c: mathematics that operators with these properties are called linear,
f2c04ccdad 2021-03-03 trnsz@pobox.c: and a corresponding declaration is built into REDUCE:;
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: linear integrate;
f2c04ccdad 2021-03-03 trnsz@pobox.c: g1;
f2c04ccdad 2021-03-03 trnsz@pobox.c: g1 := integrate(f+1, f) + integrate(1/f^5, f);
f2c04ccdad 2021-03-03 trnsz@pobox.c: pause;
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: COMMENT We overcame one difficulty and uncovered 3 others.  Clearly
f2c04ccdad 2021-03-03 trnsz@pobox.c: REDUCE does not consider F to match the pattern F^P as F^1, or 1 to
f2c04ccdad 2021-03-03 trnsz@pobox.c: match the pattern as F^0, or 1/F^5 to match the pattern as F^(-1), but
f2c04ccdad 2021-03-03 trnsz@pobox.c: we can add additional rules for such cases:;
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: let {
f2c04ccdad 2021-03-03 trnsz@pobox.c:    integrate(1/~x^~p, x) => x^(1-p)/(1-p) when df(p, x) = 0,
f2c04ccdad 2021-03-03 trnsz@pobox.c:    integrate(~x, x) => x^2/2,
f2c04ccdad 2021-03-03 trnsz@pobox.c:    integrate(1, ~x) => x }$
f2c04ccdad 2021-03-03 trnsz@pobox.c: g1;
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: COMMENT A remaining problem is that INTEGRATE(X^-1, X) will lead to
f2c04ccdad 2021-03-03 trnsz@pobox.c: X^0/(-1+1), which simplifies to 1/0, which will cause a zero-divide
f2c04ccdad 2021-03-03 trnsz@pobox.c: error message.  Consequently, we should also include the correct rule
f2c04ccdad 2021-03-03 trnsz@pobox.c: for this special case:;
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: let integrate(~x^-1, x) => log(x);
f2c04ccdad 2021-03-03 trnsz@pobox.c: integrate(1/x, x);
f2c04ccdad 2021-03-03 trnsz@pobox.c: pause;
f2c04ccdad 2021-03-03 trnsz@pobox.c:  
f2c04ccdad 2021-03-03 trnsz@pobox.c: COMMENT We now collect the integration rules so far into one list
f2c04ccdad 2021-03-03 trnsz@pobox.c: according to the law that within a rule set a more specific rule
f2c04ccdad 2021-03-03 trnsz@pobox.c: should precede the more general one:;
f2c04ccdad 2021-03-03 trnsz@pobox.c:  
f2c04ccdad 2021-03-03 trnsz@pobox.c: integrate_rules := {
f2c04ccdad 2021-03-03 trnsz@pobox.c:   integrate(1, ~x) => x,
f2c04ccdad 2021-03-03 trnsz@pobox.c:   integrate(~x, x) => x^2/2,
f2c04ccdad 2021-03-03 trnsz@pobox.c:   integrate(~x^-1, x) => log(x),
f2c04ccdad 2021-03-03 trnsz@pobox.c:   integrate(1/~x^~p, x) => x^(1-p)/(1-p) when df(p, x) = 0,
f2c04ccdad 2021-03-03 trnsz@pobox.c:   integrate(~x^~p, x) => x^(p+1)/(p+1) when df(p, x) = 0 }$
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: COMMENT Note that there are more elegant ways to match special cases
f2c04ccdad 2021-03-03 trnsz@pobox.c: in which variables have the values 0 or 1 by using "double tilde
f2c04ccdad 2021-03-03 trnsz@pobox.c: variables" -- see "Advanced use of rule lists" in section 11.3 of the
f2c04ccdad 2021-03-03 trnsz@pobox.c: REDUCE User's Manual.
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: This is the end of lesson 3.  We leave it as an intriguing exercise to
f2c04ccdad 2021-03-03 trnsz@pobox.c: extend this integrator.
f2c04ccdad 2021-03-03 trnsz@pobox.c: 
f2c04ccdad 2021-03-03 trnsz@pobox.c: ;end;

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