Simplify an expression
This functionality does not run in MATLAB.
Simplify(f
) Simplify(f
,Steps = numberOfSteps
) Simplify(f
,options
)
Simplify(f)
applies termrewriting 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 bestfirst
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 bestfirst 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 nonmatching 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
).
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 highestrank task in the todo 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.
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)
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)
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)
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)
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:
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)
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)
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(%)
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
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):
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 x^{2}:
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 matcherbased 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:

Any object 

When you use the 

Option, specified as Specify the function 

Option, specified as Specify the function 

Option, specified as Specify the function 

Option, specified as If the 

With this option the simplifier applies the following rules to expressions:
With this option, the 

Option, specified as Specify the function 

Option, specified as Limit the effort invested in one simplification step. Here 

Option, specified as Specify the type of return value. The value Even if you specify the output type as If you set this option to Technically, proofs are objects of the same type as the output
of 

Option, specified as The 

Option, specified as A rule base 

Option, specified as When you use the 

Option, specified as When you use the You can define any rule base and use any kind the rules. The
only restriction is that 

Option, specified as When you use the 

Option, specified as When you use the 

Option, specified as When you use the By default, If a particular rule does not recognize the strategy If you use the If 

Option, specified as When you use the A good valuation is a compromise between contextfree and maximumtype concepts. For a contextfree valuation, both the operator of an expression and the valuations of the operands determine the valuation of the expression. For a maximumtype valuation, generally the valuation of an expression equals the maximum of valuations of its operands. A typical contextfree example is MuPAD offers a contextfree valuation 
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.
f