Modify Subexpressions

Find and Replace Subexpressions

Operations on symbolic expressions often involve finding subexpressions and replacing them with values or with other subexpressions. MuPAD® provides the following functions for this task:

evalAt replaces specified objects in the expression tree with the specified values or subexpressions, and then evaluates the expression. This function replaces only entire branches of expression trees. It cannot replace a part of the branch, for example, two terms in the sum of three terms:

a*(b + c) | b = d,
a*(b + c) | b + c = d,
a*(b + c + 1) | b + c = d

evalAt replaces only free identifiers:

int(f(x), x = 0..1) + f(x) | x = 100

subs replaces specified objects in the expression tree with the specified values or subexpressions. This function cannot replace a part of the branch in the expression tree:

subs(a*(b + c), b + c = d),
subs(a*(b + c + 1), b + c = d)

After substitution, subs does not evaluate the resulting expression (although it can simplify the expression). You can enforce evaluation of the modified subexpressions by using the EvalChanges option:

subs(ln(x), x = E),
subs(ln(x), x = E, EvalChanges)

subs replaces both free and dependent identifiers. In some cases, replacing dependent identifiers can cause invalid results:

subs(int(f(x), x = 0..1) + f(x), x = 100)

subsex analyzes associative system operators and can replace part of the branch in the expression tree:

subsex(a*(b + c), b + c = d),
subsex(a*(b + c + 1), b + c = d)

subsex does not evaluate the resulting expression:

subsex(ln(x + a + 1),  x + a = E - 1)

Use eval to evaluate results returned by subsex:

eval(%)

subsop replaces only entire branches in the expression tree of an expression, the same way as subs. When using subsop, you must know the position (index) of the branch inside the expression in internal order that might differ from the output order used to represent the expression on screen. To find the internal index of a particular subexpression, use the op function:

ex := sin(a*x + b)  + cos(a*x + b):
op(ex);

op(ex, 2);

op(ex, [2, 1]);

op(ex, [2, 1, 2]);

op(ex, [2, 1, 2, 1])

Now you can use subsop to replace the parameter a with some value. For example, replace it with the value 3:

subsop(ex, [2, 1, 2, 1] = 3)

prog::find helps you find all occurrences of a specific value in the expression. For example, find all sums in this expression:

ex := (x + 1)/(x^2 + 2*x - 2) - 1/x + 1/(x + 1):
pos := [prog::find(ex, hold(_plus))];
map(pos, p -> op(ex, p));
map(pos, p -> op(ex, p[1..-2]))

Recursive Substitution

You also can find all subexpressions of a particular type (for example, all Bessel functions or all branches not containing x), execute some code for these subexressions and replace them with the return value of that code. For this task, use the misc::maprec function.

Suppose you want to rewrite all terms that contain the sine and tangent functions in terms of cosine functions. (In this example, do not use sin(x)2 = 1 - cos(x)2 and similar identities.) First, create the functions sin2cos and tan2cos that rewrite expressions in terms of the cosine function. These functions access the operands of the sine and tangent functions using op(ex):

sin2cos := ex -> cos(op(ex) - PI/2):
tan2cos := ex -> cos(op(ex) - PI/2)/cos(op(ex)):

Now you can use these functions when replacing all occurrences of sine and tangent functions in an expression. To replace subexpressions of the original expression, use misc::maprec. The misc::maprec function uses the syntax misc::maprec(expression, selector = replacement), where:

  • expression is the original expression (subexpressions of which you want to replace).

  • selector is the selection criterion (for example, a set of types of subexpressions that you want to replace).

  • replacement is the procedure that you want to use to replace subexpressions of the original expression.

MuPAD applies misc::maprec recursively to all subexpressions of the original expression. For example, in this call misc::maprec replaces all occurrences of sin and tan, including the sine function in tan(sin(x)):

misc::maprec(sin(x) + tan(x^2) - tan(sin(x)),
  {"sin"} = sin2cos,
  {"tan"} = tan2cos)

Besides data types or types of expressions, such as "sin" or "tan", you can use procedures to represent selection criteria in misc::maprec. In this example, the selection criterion of misc::maprec is the procedure ex -> bool(freeIndets(ex) = {}) that excludes free identifiers and selects all constants of an expression. Using the procedure f as a replacement, misc::maprec replaces all nonrational constants of an expression with new identifiers:

f :=
proc(x)
  option remember;
begin
  if testtype(x, Type::Rational) then x
  else genident();
  end_if;
end:
misc::maprec(a = 5*b + PI*sqrt(2)*c + PI,
  (ex -> bool(freeIndets(ex) = {})) = f)

option remember in f ensures that constants appearing multiple times always get the same identifier. Moreover, you can access the remember table of the procedure f and select which substitutions you want to make:

select([op(op(f,5))], _not@bool)

Was this topic helpful?