Accelerating the pace of engineering and science

• Trials

# Simplify

Simplify an expression

### Use only in the MuPAD Notebook Interface.

This functionality does not run in MATLAB.

## Syntax

```Simplify(f)
Simplify(f, Steps = numberOfSteps)
Simplify(f, options)
```

## Description

Simplify(f) applies term-rewriting rules to f and returns the simplest expression it can find.

The methods of searching for the simplest representation of an expression are different for Simplify and simplify. The simplify function performs a linear search trying to improve the result returned by the previous simplification step. The Simplify function uses the results returned by all previous simplification steps (the best-first search). The simplify function is faster. The Simplify function is slower, but more effective and more configurable.

The term "simplest" is defined as follows. One object is simpler than another if it has smaller valuation. If two objects have the same valuation, Simplify chooses the simpler object using internal heuristics. A valuation is a function that assigns a nonnegative real number to each MuPAD® object. To override the default valuation used by Simplify, use the Valuation option. Simplify uses the valuation for the best-first search as for determining the best result at the final step. However, you can define a separate method for the final simplification step by using the Criterion option.

The simplification process consists of steps. In each step, Simplify performs one of the following kinds of tasks for a := f or some (previously obtained) object a equivalent to f. In each step, Simplify can produce new objects equivalent to f (results) or new tasks to do or both:

• Initial step: Find all rules for a. The Simplify function performs the search for all rules for every new object a. This search produces no new result.

• Rewriting step: Apply one rule to a. This step can either fail or produce an equivalent object as result.

• Subexpression step: Perform one step in simplifying an operand of a. Replace the operand with the returned result (if there are any results). This step can produce a new equivalent object.

Each open task has a priority that determines what to do next. Simplification terminates in any of the following cases:

• There are no more open tasks.

• Simplify reached the time limit specified by Seconds.

• Simplify performed the maximal number of simplification steps specified by Steps.

• Simplify returned the object specified by Goal.

Simplify always returns the "simplest" equivalent object found in all simplification steps unless you specify another OutputType.

Rules form a particular domain Rule. They consist of a pattern (left side), an expression (right side), and options.

MuPAD organizes rules for Simplify in rule bases. You can change the default rule base by using the RuleBase option. You also can define your own rule selection mechanism by using the SelectRules option.

Typically, Simplify applies the selected rules to the given object a as a whole. The following case is an exception from this rule. If the pattern of the rule and the object a are both a sum or a product, then Simplify applies the rule to each subsum or subproduct of a that has the same number of operands as the pattern.

By using the ApplyRule option, you can specify your own function that applies a particular rule to a particular object. Otherwise, Simplify uses a default method.

The application of a rule to an object a fails if the pattern does not match (see match) the object a. The performance of Simplify strongly depends on the number of successful matches. Therefore, if you specify your own rule base, it must dispose of non-matching rules before rule selection.

A simplification step for an operand works like a simplification step on simplifying f. The exceptions are as follows. Performing a simplification step for an operand, MuPAD does not apply certain rules (see the details on SelectRules). Also, the system does not print any status information by default. If you want to display the status information, use the MaxInfoDepth option.

MuPAD determines priorities of open tasks as follows. The priority of doing the initial step for an expression depends on the valuation of the expression. The priority of doing a simplification step on an operand depends on the ratio between the overall valuation of the expression and the valuation of the operand and the priority of the highest-rank task in the to-do list of the operand. Finally, the priority of applying a rule to an expression equals to the priority of the rule multiplied by the valuation of the expression.

The strategy determines the priority of a rule. See the Strategy option for details.

Simplify never uses the symmetry of mathematical equivalence of expressions. Therefore, you can use Simplify as a general rewriting system.

Simplify maps to lists, sets, and tables.

For domain elements d, Simplify can be overloaded in two ways. First, Simplify uses the slot d::dom::Simplify. If that slot does not exist, Simplify uses d::dom::simplify. If the slot that Simplify uses is not a list, Simplify calls the slot and accepts the result as simple (even if the valuation does not agree). In this case, Simplify does not apply any other rules to d. However, Simplify uses the valuation to decide whether it must replace a domain element that occurs as an operand in another object with its "simplified" version. If the slot is a list, its entries must be rules, and Simplify applies them according to their priority.

## Examples

### Example 1

The easiest way to use Simplify is to accept all defaults, and then plug in the expression you want to simplify:

`Simplify(sin(x)^2 + cos(x)^2)`

### Example 2

By default, Simplify returns only one expression that the function considers as simplest. To return a list of all equivalent expressions, use the All option:

`Simplify(sin(x)^2 + cos(x)^2, All)`

### Example 3

The output of the previous example is short because as soon as the simplifier finds 1, it stops immediately. After that, the simplifier does not look for other equivalent expressions. In addition, the simplifier discards the equivalent expressions that are significantly more complicated than the best expression found earlier. You can switch off both mechanisms:

`Simplify(sin(x)^2 + cos(x)^2, All, Discard = FALSE, IsSimple = FALSE)`

### Example 4

By default, Simplify uses a valuation that favors expressions with fewer different irrational subexpressions. For example, Simplify assumes that an expression containing only sin(x) or cos(x) is simpler than an expression containing both:

`Simplify(cos(x)*sin(x))`

If you take the length as a complexity measure for expressions, Simplify returns another result:

`Simplify(cos(x)*sin(x), Valuation = length)`

### Example 5

The default number of steps is 100. To change the maximal number of possible simplification steps, use the Steps option. For example, decrease (resulting in a speedup) and increase (resulting in a probably better simplification) the number of simplification steps:

```f := ln(x) + ln(3) - ln(3*x) + (exp(x) - 1)/(exp(x/2) + 1):
Simplify(f, Steps = 8), Simplify(f, Steps = 120)```

`delete f:`

### Example 6

For many expressions, the default number of simplification steps does not allow the simplifier to find a good simplification:

`Simplify(e^(a* x *(a + 1) + b2* y *(y + b2* x* y)))`

Increasing this limit often helps:

`Simplify(e^(a* x *(a + 1) + b2* y *(y + b2* x* y)), Steps=125)`

### Example 7

By default, simplification functions do not combine logarithms:

`Simplify(ln(x^3 - 1) - ln(x - 1))`

Using the IgnoreAnalyticConstraints option, you often can get shorter results:

`Simplify(ln(x^3 - 1) - ln(x - 1), IgnoreAnalyticConstraints)`

### Example 8

You can write the same expression in different coordinate systems. For example, use Cartesian and polar coordinates:

```assume(x/r = cos(Symbol::theta)):
assumeAlso(y/r = sin(Symbol::theta)):
assumeAlso(r = sqrt(x^2+y^2)):
x/sqrt(x^2+y^2) + I*y/sqrt(x^2+y^2) = exp(I*Symbol::theta);
Simplify(%)```

### Example 9

The following expression is equivalent to exp(x):

```a := -1/(sin(1/2*I*x)^2 + 4*sin(1/4*I*x)^4 - 4*sin(1/4*I*x)^2 + 1)*
(sin(1/2*I*x)^2 - 4*I*sin(1/2*I*x)*sin(1/4*I*x)^2 + 2*I*sin(1/2*I*x) -
4*sin(1/4*I*x)^4 + 4*sin(1/4*I*x)^2 - 1)```

Simplify recognizes the equivalence of a and exp(x) within 100 steps. To show how the function proves the equivalence at each step, use the OutputType option. Note that the proof returned by Simplify is not a proof in a strict mathematical sense. Simplify uses the rules from the default rule base:

`Simplify(a, OutputType = "Proof")`
```Input was
-(sin((x*I)/2)^2 - 4*sin((x*I)/2)*sin((x*I)/4)^2*I + 2*sin((x*I)/2)*I - 4*sin((x*I)/4)^4 + 4*sin((x*I)/4)^2 - 1)/(sin\
((x*I)/2)^2 + 4*sin((x*I)/4)^4 - 4*sin((x*I)/4)^2 + 1)
Applying the rule
Simplify::combineSinCos
gives
cos(x*I) - sin(x*I)*I
Applying the rule
Simplify::expand
gives
cosh(x) + sinh(x)
Applying the rule
X -> rewrite(X, exp)
gives
exp(x)
END OF PROOF
```

### Example 10

You also can use Simplify for experiments with formal grammars given by only a few rules. In this case, the better approach is not to use rule bases, but to use a SelectRules method that returns a list of all rules. The following example presents a general associative operator ?. The example computes the number of all possible placements of parentheses. First, define the operator, and then attach it to a function that controls its output (see funcenv). Specify that the only applicable rule is the associative law. In the call to Simplify, set the number of steps to a very large value to perform a complete search. Note that most grammars produce infinitely many words and spend infinite time to finish a complete search:

```_f := funcenv(() -> procname(args())):
operator("?", _f, Binary, 1000):
R := Rule((X ? Y) ? Z, X ? (Y ? Z)):
selectProc := () -> [R]:
S := Simplify(u ? v ? x ? y ? z, Steps = 10^10,
SelectRules = selectProc, All):```
```PRETTYPRINT := FALSE:
print(Plain, S):
PRETTYPRINT := TRUE:```
```[u ? (v ? (x ? (y ? z))), u ? (v ? ((x ? y) ? z)), u ? ((v ? (x ? y)) ? z), u ? (((v ? x) ? y) ? z), u ? ((v ? x) ? (y \
? z)), (u ? (v ? x)) ? (y ? z), ((u ? v) ? x) ? (y ? z), (u ? v) ? (x ? (y ? z)), (u ? v) ? ((x ? y) ? z), (u ? (v ? (x\
? y))) ? z, (u ? ((v ? x) ? y)) ? z, ((u ? (v ? x)) ? y) ? z, (((u ? v) ? x) ? y) ? z, ((u ? v) ? (x ? y)) ? z]
```

There are 14 possible ways of placing parentheses:

```nops(S);
delete fout, _f, R, S, selectProc:
operator("?", Delete):```

### Example 11

If you want to specify a larger set of rules, the best approach is to use your own rule base. A classic example is differentiation. Although a heuristic search must be slower than a simple recursive algorithm, this example is suitable for demonstrating some efficiency considerations. Start by defining a function environment mydiff that does not do anything:

```mydiff := funcenv(mydiff):
mydiff::type := "mydiff"```

The goal of this definition is to show that MuPAD sorts rules in rule bases by the types of expressions to which MuPAD applies those rules. Therefore, mydiff gets its own type. Now, define a rule base Myrules with the usual differentiation rules. Do not use any additional rules:

```Myrules := newDomain("Myrules"):
Myrules::mydiff := [Rule(mydiff(f, x), 0, {(f, x) -> not has(f, x)}),
Rule(mydiff(x, x), 1),
Rule(mydiff(x^n, x), n*x^(n-1)),
Rule(mydiff(f*g, x), f*mydiff(g, x) + g*mydiff(f, x)),
Rule(mydiff(f+g, x), mydiff(f,x)+mydiff(g,x))]:```

This rule base works for the expression x2:

`Simplify(mydiff(x^2, x), RuleBase=Myrules)`

However, the rule base does not work for the following expression:

`Simplify(mydiff(x + 3, x), RuleBase=Myrules)`

Try to improve that rule base. As a first step, increase the number of simplification steps. Increasing the number of steps does not help in this case:

`Simplify(mydiff(x + 3, x), RuleBase=Myrules, Steps = 200)`

As a second step, take a closer look on the equivalent expressions returned by Simplify. Sometimes, Simplify finds the expected result, but does not return it because the valuation of the expected result is higher than the valuation of some other equivalent expression. For the expression x + 3, the Simplify function does not find the expected result:

`l := Simplify(mydiff(x + 3, x), RuleBase=Myrules, All)`

Note that the derivative of 1 appears in the result. Use the OutputType option, to check how Simplify manipulates the third term l[3] and how it proves the equivalence of input and output at each step:

```Simplify(mydiff(x + 3, x), RuleBase=Myrules,
Goal = l[3], OutputType = "Proof")```
```Input was
mydiff(x + 3, x)
Applying the rule
mydiff(f*g, x) -> f*mydiff(g, x) + g*mydiff(f, x)
gives
(x + 3)*mydiff(1, x) + mydiff(x + 3, x)
END OF PROOF
```

Now you can see that for each expression f, you must specify the rule for diffentiating products because f = 1 f. Modify that rule:

```(Myrules::mydiff)[4] := Rule(mydiff(f*g, x),
f*mydiff(g, x) + g*mydiff(f, x),
{(f, g) -> f<>1 and g<>1}):```

The updated rule base works:

`Simplify(mydiff(x + 3, x), RuleBase=Myrules, Remember=FALSE)`

Use a few options to optimize the call to Simplify. As a first step, measure how many steps a typical example takes before returning the expected output:

```Simplify(mydiff(5*x^4 + x^3 + x^2 + x + 1, x),
RuleBase = Myrules,
Steps = 2000,
Goal = 20*x^3 + 3*x^2 + 2*x + 1,
OutputType = "NumberOfSteps")```

Avoid the application of the equality f = f + 0. Switch off the remember mechanism. When the remember mechanism works, Simplify ignores changes in the rule base:

```Myrules::mydiff[5] := Rule(mydiff(f+g, x),
mydiff(f, x) + mydiff(g, x),
{(f, g) -> f<>0 and g<>0}):
Simplify(mydiff(5*x^4 + x^3 + x^2 + x + 1, x),
RuleBase = Myrules,
Steps = 2000,
Goal = 20*x^3 + 3*x^2 + 2*x + 1,
OutputType = "NumberOfSteps",
Remember = FALSE)```

Next, try to change the valuation criteria. For example, use length:

```Simplify(mydiff(5*x^4 + x^3 + x^2 + x + 1, x),
RuleBase = Myrules,
Steps = 2000,
Goal = 20*x^3 + 3*x^2 + 2*x + 1,
OutputType = "NumberOfSteps",
Valuation = length)```

To optimize the call to Simplify, you also can specify your own simplification strategy. For example, the first rule seems to provide a very useful simplification whenever it applies. Therefore, assign a high priority to this rule by assuming that on average this rule simplifies its input to 0.03 of the original complexity:

```Myrules::mydiff[1] := subsop(Myrules::mydiff[1],
4 = table("MyStrategy" = 0.03)):
Simplify(mydiff(5*x^4 + x^3 + x^2 + x + 1, x),
RuleBase = Myrules,
Steps = 3000,
Goal = 20*x^3 + 3*x^2 + 2*x + 1,
OutputType = "NumberOfSteps",
Strategy = "MyStrategy")```

When using the valuation length, you get the following result:

```Simplify(mydiff(5*x^4 + x^3 + x^2 + x + 1, x),
RuleBase = Myrules,
Steps = 3000,
Goal = 20*x^3 + 3*x^2 + 2*x + 1,
OutputType = "NumberOfSteps",
Strategy = "MyStrategy",
Valuation = length)```

When you use a matcher-based simplification, most of the rules do not match to most objects. Trying to match all rules to all objects produces many failing rewriting steps. The recommended approach is to discard these failing rules during the initial step. Discarding failling rules decreases the number of steps. It also increases the running time per step by a small amount. Defining a procedure instead of a list of rules can help you to discard the failing rules during an initial step. You can define the rules by using a pattern or a procedure as their first argument:

```Myrules::mydiff :=
proc(df)
begin
[if not has(op(df, 1), op(df, 2)) then
Rule(X -> 0)
else
case type(op(df, 1))
of "_plus" do
Rule(X -> map(op(X, 1), mydiff, op(X, 2)));
break
of "_mult" do
Rule(mydiff(f*g, x), f*mydiff(g, x) + g*mydiff(f, x));
break
of "_power" do
Rule(X -> op(X, [1, 2])*op(X, [1, 1])^(op(X, [1, 2])-1));
break
of DOM_IDENT do
assert(op(df, 1) = op(df, 2));
Rule(X -> 1);
break
otherwise
null()
end_case
end_if]
end_proc:
Simplify(mydiff(5*x^4 + x^3 + x^2 + x + 1, x),
RuleBase = Myrules,
Steps = 200,
Goal = 20*x^3 + 3*x^2 + 2*x + 1,
OutputType = "NumberOfSteps")```

`delete Myrules, mydiff:`

## Parameters

 f Any object

## Return Values

Simplify returns an object mathematically equivalent to the input. With the option OutputType = "All", the Simplify function returns a list of all equivalent objects found during the simplification. With the option OutputType = "NumberOfSteps", the function returns a positive integer. With the option OutputType = "Proof", the function returns a string containing a proof of the equivalence of the input and the result.