level -- evaluate an object with a
specified substitution depth
Introductionlevel(object, n) evaluates
object with substitution depth n.
Call(s)level(object)
level(object, n)
Parametersobject |
- | any MuPAD object |
n |
- | a nonnegative integer less than 2^31 |
Returnsthe evaluated object.
Further
DocumentationChapter 5 of the MuPAD Tutorial.
Related
Functionscontext, eval, hold, indexval, LEVEL, MAXLEVEL, val
Detailslevel serves to evaluate an object with a specified
recursion depth for this substitution process.level(object, 0),
object is evaluated without replacing any identifier occurring in it by its value. In most
cases, but not always, this equivalent to hold(object), and object
is returned unevaluated. See example 3.level(object, 1), all identifiers occurring in object are
replaced by their values, but not recursively, and then all function
calls in the result of the substitution are executed. This is how
objects are evaluated within a procedure by
default.level(object) is equivalent to
level(object, MAXLEVEL), i.e., identifiers
occurring in object are recursively replaced by their
values up to substitution depth MAXLEVEL - 1, and an error
occurs if the substitution depth MAXLEVEL is reached. Usually, this
leads to a complete evaluation of object. See
example 1.level without a second argument to request
the complete evaluation of an object not containing local variables or
formal parameters within a procedure. This
may be necessary since by default, objects are evaluated with
substitution depth 1 within procedures. See
example 2.
Otherwise, it should never be necessary to use
level.
level does not affect the evaluation of
local variables and formal parameters, of type DOM_VAR, in procedures. When such a local variable occurs in
object, then it is always replaced by its value,
independent of the value of n, and the value is not
further recursively evaluated. See example 2.
level works by temporarily setting the value of
LEVEL to n,
or to 2^31 - 1 if n is not given. However, the
value of MAXLEVEL
remains unchanged. If the substitution depth MAXLEVEL is reached, then an error
message is returned. See LEVEL and MAXLEVEL for more information on
these environment variables.level does not flatten its first argument if it is an expression sequence. See example 5.level does not recursively descend into arrays, tables, matrices or polynomials. Use the call map(object, eval) to evaluate the
entries of an array, a table, a matrix or mapcoeffs(object, eval) to
evaluate the coefficients of a polynomial. Cf. example 4 and example 6.
Further information concerning the evaluation of arrays, tables,
matrices or polynomials can be found on the eval help page.
level depends on the
environment variable MAXLEVEL, while the maximum
evaluation depth of the function eval depends on the environment
variable LEVEL. See
example 7.eval evaluates the result again there is a
difference between evaluating an expression with depth n by
level in comparison with eval. See
example 7.level does not affect the evaluation of
local variables and formal parameters, of type DOM_VAR, in procedures. Here eval behaves
different. See example 7 and the
eval help page for more
information.level(hold(x)) is always
x, because a full evaluation of hold(x) leads
to x. The same does not hold for
eval(hold(x)), because eval first evaluates
its argument and then evaluates the result again.domain depends on the implementation of the
domain. Usually domain elements remain unevaluated by
level. If the domain has a slot "evaluate",
the corresponding slot routine is called with the domain element as
argument at each evaluation, and hence it is called once when
level is invoked. Cf. example 8.level is a function of the system kernel.
Example
1We demonstrate the effect of level for
various values of the second parameter:
>> delete a0, a1, a2, a3, a4, b: b := b + 1: a0 := a1: a1 := a2 + 2: a2 := a3 + a4: a3 := a4^2: a4 := 5:
>> hold(a0), hold(a0 + a2), hold(b); level(a0, 0), level(a0 + a2, 0), level(b, 0); level(a0, 1), level(a0 + a2, 1), level(b, 1); level(a0, 2), level(a0 + a2, 2), level(b, 2); level(a0, 3), level(a0 + a2, 3), level(b, 3); level(a0, 4), level(a0 + a2, 4), level(b, 4); level(a0, 5), level(a0 + a2, 5), level(b, 5); level(a0, 6), level(a0 + a2, 6), level(b, 6);
a0, a0 + a2, b
a0, a0 + a2, b
a1, a1 + a3 + a4, b + 1
2
a2 + 2, a2 + a4 + 7, b + 2
a3 + a4 + 2, a3 + a4 + 32, b + 3
2 2
a4 + 7, a4 + 37, b + 4
32, 62, b + 5
32, 62, b + 6
Evaluating object by just typing
object at the command prompt is equivalent to
level(object, LEVEL):
>> LEVEL := 2: MAXLEVEL := 4: a0, a2, b; level(a0, LEVEL), level(a2, LEVEL), level(b, LEVEL)
2
a2 + 2, a4 + 5, b + 2
2
a2 + 2, a4 + 5, b + 2
If the second argument is omitted, then this corresponds
to a complete evaluation up to substitution depth MAXLEVEL -
1:
>> level(a0)
Error: Recursive definition [See ?MAXLEVEL]
>> level(a2)
30
>> level(b)
Error: Recursive definition [See ?MAXLEVEL]
>> delete LEVEL, MAXLEVEL:
Example
2We demonstrate the behavior of level in
procedures:
>> delete a, b, c: a := b: b := c: c := 42:
p := proc()
local x;
begin
x := a:
print(level(x, 0), x, level(x, 2), level(x)):
print(level(a, 0), a, level(a, 2), level(a)):
end_proc:
p()
b, b, b, b
a, b, c, 42
Since a is evaluated with the default
substitution depth 1, the assignment x:=a
sets the value of the local variable x to the unevaluated
identifier b. You can see that any evaluation of
x, whether level is used or not, simply
replaces x by its value b, but no further
recursive evaluation happens. In contrast, evaluation of the identifier
a takes place with the default substitution depth
1, and level(a, 2) evaluates it
with substitution depth 2.
Thus level without a second argument can be used to
request the complete evaluation of an object not containing any local
variables or formal parameters.
Example
3There are some rare cases where
level(object, 0) and
hold(object) behaves different. This is the case if
object is not an identifier, e.g., a nameless function,
because level influences only the evaluation of
identifiers:
>> level((x -> x^2)(2),0), hold((x -> x^2)(2))
4, (x -> x^2)(2)
For the same reason level(object,
0) and hold(object) behave differently if
object is a local variable of a procedure:
>> f:=proc() local x; begin
x := 42;
hold(x), level(x, 0);
end_proc:
f();
delete f:
DOM_VAR(0,2), 42
Example
4In contrast to lists and sets, evaluation of an array does not evaluate its entries. Thus
level has no effect for arrays either. The same holds for
tables and matrices. Use map to evaluate all entries of an array.
On the eval help page
further examples can be found:
>> delete a, b: L := [a, b]: A := array(1..2, L): a := 1: b := 2: L, A, level(A), map(A, level), map(A, eval)
+- -+ +- -+ +- -+ +- -+
[1, 2], | a, b |, | a, b |, | a, b |, | 1, 2 |
+- -+ +- -+ +- -+ +- -+
Example
5The first argument of level may be an
expression sequence, which is not flattened. However, it must be
enclosed in parentheses:
>> delete a, b: a := b: b := 3: level((a, b), 1); level(a, b, 1)
b, 3
Error: Wrong number of arguments [level]
Example
6Polynomials are
inert when evaluated, and so level has no effect:
>> delete a, x: p := poly(a*x, [x]): a := 2: x := 3: p, level(p)
poly(a x, [x]), poly(a x, [x])
Use mapcoeffs and the function
eval to evaluate all
coefficients:
>> mapcoeffs(p, eval)
poly(2 x, [x])
If you want to substitute a value for the indeterminate
x, use evalp:
>> delete x: evalp(p, x = 3)
3 a
As you can see, the result of an evalp call may contain unevaluated
identifiers, and you can evaluate them by an application of eval. It is necessary to use
eval instead of level because
level does not evaluate its result:
>> eval(evalp(p, x = 3))
6
Example
7The subtle difference between level and
eval is shown. The
evaluation depth of eval is limited by the environment
variable LEVEL.
level pays no attention to LEVEL, but rather
continues evaluating its argument either as many times as the second
argument implies or until it has been evaluated completely:
>> delete a0, a1, a2, a3: a0 := a1 + a2: a1 := a2 + a3: a2 := a3^2 - 1: a3 := 5: LEVEL := 1: eval(a0), level(a0);
2
a2 + a3 + a3 - 1, 53
If the evaluation depth exceeds the value of MAXLEVEL, an error is raised
in both cases:
>> delete LEVEL: MAXLEVEL := 3: level(a0);
Error: Recursive definition [See ?MAXLEVEL]
>> delete LEVEL: MAXLEVEL := 3: eval(a0); delete MAXLEVEL:
Error: Recursive definition [See ?MAXLEVEL]
It is not the same evaluating an expression
ex with eval and an evaluation depth
n and by level((ex, n)), because
eval evaluates its result:
>> LEVEL := 2: eval(a0), level(a0, 2); delete LEVEL:
2
53, a2 + a3 + a3 - 1
level does not affect the evaluation of
local variables of type DOM_VAR while eval
evaluates them with evaluation depth LEVEL, which is one
in a procedure:
>> p := proc()
local x;
begin
x := a0:
print(eval(x), level(x)):
end_proc:
p()
2
a2 + a3 + a3 - 1, a1 + a2
Example
8The evaluation of an element of a user-defined domain depends on the implementation of the domain. Usually it is not further evaluated:
>> delete a: T := newDomain("T"):
e := new(T, a): a := 1:
e, level(e), map(e, level), val(e)
new(T, a), new(T, a), new(T, a), new(T, a)
If the slot "evaluate" exists, the
corresponding slot routine is called for a domain element each time it
is evaluated. We implement the routine T::evaluate, which
simply evaluates all internal operands of its argument, for our domain
T. The unevaluated domain element can still be accessed
via val:
>> T::evaluate := x -> new(T, eval(extop(x))): e, level(e), map(e, level), val(e);
new(T, 1), new(T, 1), new(T, 1), new(T, a)
>> delete e, T:
level no longer affects the evaluation of a local
variable or a formal parameter, for which a new data type DOM_VAR was introduced. See
sections ``The
LEVEL-Problem'' and ``Symbols and Variables'' of the
document ``From MuPAD 1.4 to
MuPAD 2.0'' for details.