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