# Rule

Defining equivalence rules for mathematical expressions

### Use only in the MuPAD Notebook Interface.

This functionality does not run in MATLAB.

## Syntax

```Rule(`pattern`, `replacement`, <`conditions`>)
Rule(`procedure`, <`condProc`>)
```

## Description

`Rule` is a data type. Each object of `Rule` – a rule – describes the equivalence between mathematical expressions. The arguments of a rule are two pattern expressions, that are equivalent, and optional some conditions for the validity of the equivalence.

Rule can be applied to any expression, and returns an expression equivalent to the input, or `FAIL`.

Additionally, a rule can consist of a procedure that returns an equivalent expression to a given expression or `FAIL` without using the pattern matcher.

Rules created with `Rule` are mainly used to build a rule base for the new `Simplify`. See the documentation of `Simplify` and Example 8 for a real application of `Rule`. Example 3 shows, how to implement rewriting rules via `Rule`.

All other examples are only given to explain the behavior of rules. In practice, single rules and their manual application is unusual.

There are two kinds of rules: Use the library pattern matcher to determine whether the rule is suitable, or use a user defined procedure to analyze a given expression and return an equivalent expression.

`Rule(pattern, replacement, conditions)` defines a rule that describes the equivalence of the expressions `pattern` and `replacement`.

When this rule is applied to a given expression `ex`, the pattern matcher is called with the arguments

`match(ex, pattern, Cond = conditions)`

and returns a set of replacements ```S:={var = ex_var, ...}``` for each variable `var` of `pattern`, and `ex_var` is the corresponding subexpression of `ex` (see `match` for detailed description).

In this case the result of the substitution ```subs(replacement, S)``` is returned as equivalent expression to `ex`.

The call to `match` can also return `FAIL`, when `ex` doesn't have the same structure as `pattern`. Then the return value of the rule application is `FAIL`, too.

See Example 1 and Example 2.

See `match` for the description of valid conditions.

Alternatively, a rule can consist of a procedure that is called with a given expression, and must return an equivalent expression or `FAIL`. The "pattern matcher" is not called.

`Rule(procedure, condProc)` defines such a rule that returns an equivalent expression to any given input as return value of `procedure` or `FAIL`.

The optional condition `condProc` must be a procedure, too. This procedure is called before the procedure that produces equivalent expressions, with a given expression `ex`. When the call `condProc(ex)` returns `TRUE`, then the return value of the call `procedure(ex)` is returned as the result of the application of the rule, otherwise `FAIL`.

With a rule that consists of a procedure, several relations ```pattern <=> result``` can be expressed. This is mostly more efficient, than using `match` for each equivalence.

See Example 6 and Example 7.

 Note:   Rules with expressions as arguments must use identifiers that are protected from any assignment. Those identifiers must be of the form `#X`, where `X` can be any valid variable name. All variables that start with `#` in their names are protected by the kernel from any assignment.

## Examples

### Example 1

The first rule represents the simplification ```sin(X)^2 + cos(X)^2 = 1```. The first argument of the rule is the expression ```sin(X)^2 + cos(X)^2```. Each expression, which has the same structure, is found by `match`, and the second argument of the rule `1` is returned as result. There are no conditions for the validity of this equivalence. The identifiers used for defining the rule are write protected, because they have names beginning with `#`:

```r := Rule(sin(`#X`)^2 + cos(`#X`)^2, 1): Rule::apply(r, sin(2*x - 1)^2 + cos(2*x - 1)^2)```

The next expression doesn't have the right form, the application of the rule fails:

`Rule::apply(r, sin(2*x - 1)^2 + cos(2*x + 1)^2)`

### Example 2

The next rule represents the addition theorem ```sin(X + Y) = sin(X)*cos(Y) + sin(Y)*cos(X)```. The first argument of the rule is the expression `sin(X + Y)`. Each expression that is a call to `sin` with a sum as argument, is identified by `match`, and the sum ```sin(X)*cos(Y) + sin(Y)*cos(X)``` is returned, where `X` and `Y` are replaced by the corresponding parts of the given expression. There are no conditions for the validity of this equivalence. The second part of the rule is prevented from evaluation with `hold`. The identifiers used for defining the rule are write protected, because they have names beginning with `#`:

```r := Rule(sin(`#X` + `#Y`), hold(sin(`#X`)*cos(`#Y`) + sin(`#Y`)*cos(`#X`))): Rule::apply(r, sin(tan(x) + tan(y)))```

The matcher identifies the difference of two expressions `a` and `b` as the sum `a + -b`, therefore also the following example works:

`Rule::apply(r, sin(tan(x) - tan(y)))`

### Example 3

We define two rules based on the trigonometric identies sin(x)2 = 1 - cos(x)2 and :

```myrules := [Rule(sin(`#X`)^`#n`, (1 - cos(`#X`)^2)^(`#n`/2), {`#n` -> is(`#n`, Type::Even)}), Rule(tan(`#X`)^`#n`, (1/cos(`#X`)^2 - 1)^(`#n`/2), {`#n` -> is(`#n`, Type::Even)}) ]:```

We wish to apply these rules as rewriting rules to various expressions. We forward `Rule::apply` to all subexpressions of an expression via `misc::maprec`. For convenience, an interface function `myrewrite` is implemented that calls `misc::maprec`:

```myrewrite:= proc(f, rules) local _rewrite; begin _rewrite:= proc(x) local r, tmp; begin for r in rules do tmp:= Rule::apply(r, x); if tmp <> FAIL then x:= tmp; end; end; return(x) end; misc::maprec(f, TRUE = _rewrite); end:```

Now we can call `myrewrite(f, myrules)` to apply the rewriting rules to an expression `f`:

```f:= tan(x) + sin(2*x) - tan(y)^2*sin(x + 3)^6 + sin(x)^2 * tan(23)^4: myrewrite(f, myrules);```

`delete myrules, myrewrite, f:`

### Example 4

Another rule represents the simplification ```sin(X) = 0```, which is only true, when `X` is an integer multiple of `PI`:

```r := Rule(sin(`#X`), 0, {`#X` -> is(`#X`/PI, Type::Integer)}): Rule::apply(r, sin(2*x*PI))```

In the last call, the argument of `sin` doesn't have the necessary property, so the application of the rule fails.

After an assumption to `x`, the expression has the right form:

```assume(x, Type::Integer): Rule::apply(r, sin(2*x*PI))```

The next application of the rule checks a constant expression:

`Rule::apply(r, sin(2*PI))`

Why `FAIL`? The problem is, `sin` simplifies the constant input `2*PI` to `0` itself, so the rule gets `0` as input. However, `0` doesn't have the necessary form, so `FAIL` is returned.

### Example 5

Another rule represents the simplification ```ln(neg^even*r) = even*ln(-neg) + ln(r)```, which is only true, when `neg` is negative and `even` is an even number:

```r := Rule(ln(`#Neg`^`#Even`*`#X`), `#Even`*ln(-`#Neg`) + ln(`#X`), {`#Neg` -> is(`#Neg`, Type::Negative) = TRUE, `#Even` -> is(`#Even`, Type::Even) = TRUE}): delete e, n, x: Rule::apply(r, ln(n^e*x))```

The rule application fails, because the variables doesn't have the necessary properties.

With an assumption `n` should be a negative variable and `e` should be even:

```assume(n < 0): assume(e, Type::Even): Rule::apply(r, ln(n^e*x))```

### Example 6

This rule represents the application of `rewrite` to an expression with the target `exp`, when the expression has subexpressions of type `"sin"` or `"cos"`. The first argument of the rule is a procedure that calls `rewrite` with any expression and target `exp` and returns an expression equivalent to the input (because `rewrite` does it). The second argument is a procedure that checks, whether `sin` or `cos` is contained in the input expression:

```r := Rule(X -> rewrite(X, exp), X -> has(X, sin) or has(X, cos)): Rule::apply(r, sin(2*x - 1)^2 + cos(2*x - 1)^2)```

The next expression doesn't have `sin` or `cos`, so the application of the rule fails:

`Rule::apply(r, tan(2*I*x))`

### Example 7

This rule represents the application of `rewrite` to an expression with several targets. The first argument of the rule is a procedure that applies `rewrite` to the given expression, with a target depending on the input. This rule doesn't have a condition procedure:

```rewProc := proc(ex) begin rewrite(ex, (if has(ex, exp) then tan elif has(ex, sin) or has(ex, cos) then cot elif has(ex, tan) or has(ex, cot) then sincos else exp end_if)) end_proc: r := Rule(rewProc): Rule::apply(r, exp(2*x))```

The rule is applied again to the last result:

`Rule::apply(r, %)`

The last result should be simplified back to the first expression:

`Simplify(%)`

### Example 8

The new `Simplify` uses a rule base for applying a lot of rewriting rules for finding the simplest form of any given expression.

We want to rewrite only some powers and assume that all used variables are real (without using properties).

The list `PowerRules` consists of several rules. The procedure `powerRules` returns all this rules in a list.

Because of better readability, the names of the used identifiers are short and not protected names:

```PowerRules := [Rule(A^m*A^n, hold(A^(m + n))), Rule(A^m/A^n, hold(A^(m - n))), Rule(A^n*B^n, hold((A*B)^n)), Rule(A^n/B^n, hold((A/B)^n)), Rule(A^n/B^n, hold((B/A)^-n)), Rule((A^m)^n, hold(A^(m*n)))]: powerRules := proc() begin PowerRules end_proc:```

`Simplify` is called with the option `SelectRules`, and expects a procedure that returns a list of rules, applicable to a given expression. In this case, all of the rules are returned in every case.

`Simplify` applies all rules to a given expression and also to rewritten results, and tries to find the easiest form of the expression with respect to the default valuation procedure `Simplify::complexity`.

Because of the argument `SelectRules = powerRules`, only the given rules are used by `Simplify`:

`Simplify(T^(1/2)*(R*T)^(-1/2), SelectRules = powerRules)`

Other expressions cannot be simplified with the same rule base:

`Simplify(sin(x)^2 + cos(x)^2, SelectRules = powerRules)`

`delete r, x, powerRules, PowerRules:`

## Parameters

 `pattern` A MuPAD® expression; all identifiers are used as pattern variables for the pattern matcher `replacement` A MuPAD expression with the same identifiers, as `pattern`; the replacement expression should be protected from evaluation with the function `hold` `conditions` A set (of type `DOM_SET`) of procedures and expressions in the pattern variables, or the empty set (see `match` and option `Cond`) `procedure` A MuPAD procedure that is called with an expression and must return an equivalent expression or `FAIL` `condProc` A procedure that is called with an expression before `procedure`, and must return `TRUE`, when `procedure` should be called with the expression, otherwise `FAIL` is returned immediately