Substitution depth of identifiers
The environment variable LEVEL determines the maximal substitution depth of identifiers.
Possible values: a positive integer smaller than 231.
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 determines the maximal recursion depth of this process.
Technically, evaluation of a MuPAD object works as follows. For a compound object, usually first the operands are evaluated recursively, and then the object itself is evaluated. E.g., if the object is a function call with arguments,the arguments are evaluated first, and then the function is executed with the evaluated arguments.
With respect to the evaluation of identifiers, the current substitution depth is recorded internally. Initially, this value is zero. If an identifier is encountered during the recursive evaluation process as described above and the current substitution depth is smaller than LEVEL, then the identifier is replaced by its value, the current substitution depth is increased by one, and evaluation proceeds recursively with the value of the identifier. After the identifier has been evaluated, the current substitution depth is reset to its previous value. If the current substitution depth equals LEVEL, however, then the recursion stops and the identifier remains unevaluated.
Note: The default value of LEVEL at interactive level is 100. However, the default value of LEVEL within a procedure is 1. Then an identifier is only replaced by its value, which is not evaluated recursively.
The value of LEVEL may be changed within a procedure, but it is reset to 1 each time a new procedure is entered. After the procedure returns, LEVEL is reset to its previous value. See Example 3.
Note: The evaluation of local variables and formal parameters of procedures, of type DOM_VAR, is not affected by LEVEL: they are always evaluated with substitution depth 1. This means that a local variable or a formal parameter is replaced by its value when evaluated, but the value is not evaluated further.
See Example 3.
See Example 4.
The function eval evaluates its argument with substitution depth given by LEVEL, and then evaluates the result again with the same substitution depth.
The call level(object, n) evaluates its argument with substitution depth n, independent of the value of LEVEL.
If, during evaluation, the substitution depth MAXLEVEL, is reached, then the evaluation is terminated with an error. This is a heuristic for recognizing recursive definitions, as in the example delete a; a := a + 1; a. Here, a would be replaced by a + 1 infinitely often. Note that this has no effect if MAXLEVEL is greater than LEVEL. The default value of MAXLEVEL is 100, i.e., it is equal to the default value of LEVEL at interactive level. However, unlike LEVEL, MAXLEVEL is not changed within a procedure, and hence recursive definitions are usually not recognized within procedures. See the help page of MAXLEVEL for examples.
The default value of LEVEL is 100 at interactive level; LEVEL has this value after starting or resetting the system via reset. Within a procedure, the default value is 1. The command delete LEVEL restores the default value.
We demonstrate the effect of various values of LEVEL at interactive level:
delete a0, a1, a2, a3, a4, b: b := b + 1: a0 := a1: a1 := a2 + 2: a2 := a3 + a4: a3 := a4^2: a4 := 5:
LEVEL := 1: a0, a0 + a2, b; LEVEL := 2: a0, a0 + a2, b; LEVEL := 3: a0, a0 + a2, b; LEVEL := 4: a0, a0 + a2, b; LEVEL := 5: a0, a0 + a2, b; LEVEL := 6: a0, a0 + a2, b; delete LEVEL:
In the following calls, the identifier a is fully evaluated:
delete a, b, c: a := b: b := c: c := 7: a
After assigning the value 2 to LEVEL, a is evaluated only with depth two:
LEVEL := 2: a; delete LEVEL:
If we set MAXLEVEL to 2 as well, evaluation of a produces an error, although there is no recursive definition involved:
LEVEL := 2: MAXLEVEL := 2: a
Error: Recursive definition. [See ?MAXLEVEL]
delete LEVEL, MAXLEVEL:
This example shows the difference between the evaluation of identifiers and local variables. By default, the value of LEVEL is 1 within a procedure, i.e., a global identifier is replaced by its value when evaluated, but there is no further recursive evaluation. This changes when LEVEL is assigned a bigger value inside the procedure:
delete a0, a1, a2, a3: a0 := a1 + a2: a1 := a2 + a3: a2 := a3^2 - 1: a3 := 5: p := proc() save LEVEL; begin print(a0, eval(a0)): LEVEL := 2: print(a0, eval(a0)): end_proc:
In contrast, evaluation of a local variable replaces it by its value, without further evaluation. When eval is applied to an object containing a local variable, then the effect is an evaluation of the value of the local variable with substitution depth LEVEL:
q := proc() save LEVEL; local x; begin x := a0: print(x, eval(x)): LEVEL := 2: print(x, eval(x)): end_proc: q()
The command x:=a0 assigns the value of the identifier a0, namely the unevaluated expression a1+a2, to the local variable x, and x is replaced by this value every time it is evaluated, independent of the value of LEVEL.
LEVEL does not affect on evaluation of polynomials:
delete a, x: p := poly(a*x, [x]): a := 2: x := 3: p, eval(p); LEVEL := 1: p, eval(p); delete LEVEL:
delete a, b: A := array(1..2, [a, b]): T := table(a = b): a := 1: b := 2: A, eval(A), T, eval(T); LEVEL := 1: A, eval(A), T, eval(T); delete LEVEL: