level
-- evaluate an object with a
specified substitution depthlevel(
object, n)
evaluates
object
with substitution depth n
.
level(object)
level(object, n)
object |
- | any MuPAD object |
n |
- | a nonnegative integer less than 2^31 |
the evaluated object.
Chapter 5 of the MuPAD Tutorial.
context
, eval
, hold
, indexval
, LEVEL
, MAXLEVEL
, val
level
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.We 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:
We 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.
There 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
In 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 | +- -+ +- -+ +- -+ +- -+
The 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]
Polynomials
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
The 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
The 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.