Documentation |
Evaluate an object with a specified substitution depth
This functionality does not run in MATLAB.
level(object) level(object, n)
level(object, n) evaluates object with substitution depth n.
When a MuPAD^{®} object is evaluated, identifiers occurring in it are replaced by their values. This happens recursively, i.e., if the values themselves contain identifiers, then these are replaced as well. level serves to evaluate an object with a specified recursion depth for this substitution process.
With 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.
With 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.
The call 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.
You can use 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.
Note: 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.
In contrast to most other functions, 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. See Example 4 and Example 6.
Further information concerning the evaluation of arrays, tables, matrices or polynomials can be found on the eval help page.
The maximal substitution depth of 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.
Because 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.
As mentioned 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.
The result of 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.
The evaluation of elements of a user-defined 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.
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);
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)
If the second argument is omitted, then this corresponds to a complete evaluation up to substitution depth MAXLEVEL - 1:
level(a0)
Error: Recursive definition, the maximal evaluation level is reached.
level(a2)
level(b)
Error: Recursive definition, the maximal evaluation level is reached.
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()
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))
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:
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)
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)
Error: The number of arguments is incorrect. [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)
Use mapcoeffs and the function eval to evaluate all coefficients:
mapcoeffs(p, eval)
If you want to substitute a value for the indeterminate x, use evalp:
delete x: evalp(p, x = 3)
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))
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);
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, the maximal evaluation level is reached.
delete LEVEL: MAXLEVEL := 3: eval(a0); delete MAXLEVEL:
Error: Recursive definition, the maximal evaluation level is reached.
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:
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()
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)
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);
delete e, T: