Previous: Debugging Rewrites, Up: Rewrite Rules

Returning to the example of substituting the pattern
‘`sin(x)^2 + cos(x)^2`’ with 1, we saw that the rule
‘`opt(a) sin(x)^2 + opt(a) cos(x)^2 := a`’ does a good job of
finding suitable cases. Another solution would be to use the rule
‘`cos(x)^2 := 1 - sin(x)^2`’, followed by algebraic simplification
if necessary. This rule will be the most effective way to do the job,
but at the expense of making some changes that you might not desire.

Another algebraic rewrite rule is ‘`exp(x+y) := exp(x) exp(y)`’.
To make this work with the `j r` command so that it can be
easily targeted to a particular exponential in a large formula,
you might wish to write the rule as ‘`select(exp(x+y)) :=
select(exp(x) exp(y))`’. The ‘`select`’ markers will be
ignored by the regular `a r` command
(see Selections with Rewrite Rules).

A surprisingly useful rewrite rule is ‘`a/(b-c) := a*(b+c)/(b^2-c^2)`’.
This will simplify the formula whenever ‘`b`’ and/or ‘`c`’ can
be made simpler by squaring. For example, applying this rule to
‘`2 / (sqrt(2) + 3)`’ yields ‘`6:7 - 2:7 sqrt(2)`’ (assuming
Symbolic mode has been enabled to keep the square root from being
evaluated to a floating-point approximation). This rule is also
useful when working with symbolic complex numbers, e.g.,
‘`(a + b i) / (c + d i)`’.

As another example, we could define our own “triangular numbers” function
with the rules ‘`[tri(0) := 0, tri(n) := n + tri(n-1) :: n>0]`’. Enter
this vector and store it in a variable: `s t trirules`. Now, given
a suitable formula like ‘`tri(5)`’ on the stack, type ‘`a r trirules`’
to apply these rules repeatedly. After six applications, `a r` will
stop with 15 on the stack. Once these rules are debugged, it would probably
be most useful to add them to `EvalRules`

so that Calc will evaluate
the new `tri`

function automatically. We could then use `Z K` on
the keyboard macro `' tri($) <RET>` to make a command that applies
`tri`

to the value on the top of the stack. See Programming.

The following rule set, contributed by François
Pinard, implements quaternions, a generalization of the concept of
complex numbers. Quaternions have four components, and are here
represented by function calls ‘`quat( w, [x, y,
z])`’ with “real part”

`EvalRules`

,
or create a command based on [ quat(w, x, y, z) := quat(w, [x, y, z]), quat(w, [0, 0, 0]) := w, abs(quat(w, v)) := hypot(w, v), -quat(w, v) := quat(-w, -v), r + quat(w, v) := quat(r + w, v) :: real(r), r - quat(w, v) := quat(r - w, -v) :: real(r), quat(w1, v1) + quat(w2, v2) := quat(w1 + w2, v1 + v2), r * quat(w, v) := quat(r * w, r * v) :: real(r), plain(quat(w1, v1) * quat(w2, v2)) := quat(w1 * w2 - v1 * v2, w1 * v2 + w2 * v1 + cross(v1, v2)), quat(w1, v1) / r := quat(w1 / r, v1 / r) :: real(r), z / quat(w, v) := z * quatinv(quat(w, v)), quatinv(quat(w, v)) := quat(w, -v) / (w^2 + v^2), quatsqr(quat(w, v)) := quat(w^2 - v^2, 2 * w * v), quat(w, v)^k := quatsqr(quat(w, v)^(k / 2)) :: integer(k) :: k > 0 :: k % 2 = 0, quat(w, v)^k := quatsqr(quat(w, v)^((k - 1) / 2)) * quat(w, v) :: integer(k) :: k > 2, quat(w, v)^-k := quatinv(quat(w, v)^k) :: integer(k) :: k > 0 ]

Quaternions, like matrices, have non-commutative multiplication.
In other words, ‘`q1 * q2 = q2 * q1`’ is not necessarily true if
‘`q1`’ and ‘`q2`’ are `quat`

forms. The ‘`quat*quat`’
rule above uses `plain`

to prevent Calc from rearranging the
product. It may also be wise to add the line ‘`[quat(), matrix]`’
to the `Decls`

matrix, to ensure that Calc's other algebraic
operations will not rearrange a quaternion product. See Declarations.

These rules also accept a four-argument `quat`

form, converting
it to the preferred form in the first rule. If you would rather see
results in the four-argument form, just append the two items
‘`phase(2), quat(w, [x, y, z]) := quat(w, x, y, z)`’ to the end
of the rule set. (But remember that multi-phase rule sets don't work
in `EvalRules`

.)