Documentation |
Apply a function to all operands of an object
This functionality does not run in MATLAB.
map(object, f, <p_{1}, p_{2}, , …>) map(object, f, <p_{1}, p_{2}, , …>, <Unsimplified>)
map(object, f) returns a copy of object where each operand x has been replaced by f(x). The object itself is not modified by map (see Example 2).
The second argument f may be a procedure generated via -> or proc (e.g., x -> x^2 + 1), a function environment (e.g., sin), or a functional expression (e.g., sin@exp + 2*id).
If optional arguments are present, then each operand x of object is replaced by f(x, p_{1}, p_{2}, ...) (see Example 1).
It is possible to apply an operator, such as + or *, to all operands of object, by using its functional equivalent, such as _plus or _mult. See Example 1.
In contrast to op, map does not decompose rational numbers and complex numbers further. Thus, if the argument is a rational number or a complex number, then f is applied to the number itself and not to the numerator and the denominator or the real part and the imaginary part, respectively (see Example 3).
If object is a string, then f is applied to the string as a whole and not to the individual characters (see Example 3).
If object is an expression, then f is applied to the operands of f as returned by op (see Example 1).
If object is an expression sequence, then this sequence is not flattened by map (see Example 4).
If object is a polynomial, then f is applied to the polynomial itself and not to all of its coefficients. Use mapcoeffs to achieve the latter (see Example 3).
If object is a list, a set, an array, or an hfarray, then the function f is applied to all elements of the corresponding data structure.
Note: If object is a table, the function f is applied to all entries of the table, not to the indices (see Example 9). The entries are the right sides of the operands of a table. |
If object is an element of a library domain, then the slot "map" of the domain is called and the result is returned. This can be used to extend the functionality of map to user-defined domains. If no "map" slot exists, then f is applied to the object itself (see Example 10).
map does not evaluate its result after the replacement; use eval to achieve this. Nevertheless, internal simplifications occur after the replacement, unless the option Unsimplified is given (see Example 8).
map does not descend recursively into an object; the function f is only applied to the operands at first level. Use misc::maprec for a recursive version of map (see Example 11).
The procedure f should be deterministic and should not have side effects (such as changing and using global variables). The user does not have any control over the ordering in which the function is applied to the operands of the object!
map works for expressions:
map(a + b + 3, sin)
The optional arguments of map are passed to the function being mapped:
map(a + b + 3, f, x, y)
In the following example, we add 10 to each element of a list:
map([1, x, 2, y, 3, z], _plus, 10)
Like most other MuPAD^{®} functions, map does not modify its first argument, but returns a modified copy:
a := [0, PI/2, PI, 3*PI/2]: map(a, sin)
The list a still has its original value:
a
map does not decompose rational and complex numbers:
map(3/4, _plus, 1), map(3 + 4*I, _plus, 1)
map does not decompose strings:
map("MuPAD", text2expr)
map does not decompose polynomials:
map(poly(x^2 + x + 1), _plus, 1)
Use mapcoeffs to apply a function to all coefficients of a polynomial:
mapcoeffs(poly(x^2 + x + 1), _plus, 1)
The first argument is not flattened:
map((1, 2, 3), _plus, 2)
Sometimes a MuPAD function returns a set or a list of big symbolic expressions containing mathematical constants etc. To get a better intuition about the result, you can map the function float to all elements, which often drastically reduces the size of the expressions:
solve(x^4 + x^2 + PI, x)
map(%, float)
In the following example, we delete the values of all global identifiers in the current MuPAD session. The command anames(All, User) returns a set with the names of all user-defined global identifiers having a value. Mapping the function _delete to this set deletes the values of all these identifiers. Since the return value of _delete is the empty sequence null(), the result of the call is the empty set:
x := 3: y := 5: x + y
map(anames(All, User), _delete)
x + y
It is possible to perform arbitrary actions with all elements of a data structure via a single map call. This works by passing an anonymous procedure as the second argument f. In the following example, we check that the fact "an integer n ≥ 2 is prime if and only if φ(n) = n - 1", where φ denotes Euler's totient function, holds for all integer 2 ≤ n < 10. We do this by comparing the result of isprime(n) with the truth value of the equation φ(n) = n - 1 for all elements n of a list containing the integers between 2 and 9:
map([2, 3, 4, 5, 6, 7, 8, 9], n -> bool(isprime(n) = bool(numlib::phi(n) = n - 1)))
The result of map is not evaluated further. If desired, you must request evaluation explicitly by eval:
map(sin(5), float); eval(%)
delete a: A := array(1..1, [a]); a := 0: map(A, sin); map(A, eval@sin); delete a:
Nevertheless, certain internal simplifications take place, such as the calculation of arithmetical operations with numerical arguments. The following call replaces sqrt(2) and PI by floating-point approximations, and the system automatically simplifies the resulting sum:
map(sin(5) + cos(5), float)
This internal simplification can be avoided by giving the option Unsimplified:
map(sin(5) + cos(5), float, Unsimplified)
map applied to a table changes only the right sides (the entries) of each operand of the table. Assume the entries stand for net prices and the sales tax (16 percent in this case) must be added:
T := table(1 = 65, 2 = 28, 3 = 42): map(T, _mult, 1.16)
map can be overloaded for elements of library domains, if a slot"map" is defined. In this example d is a domain, its elements contains two integer numbers: an index and an entry (like a table). For nice input and printing elements of this domain the slots"new" and "print" are defined:
d := newDomain("d"): d::new := () -> new(d, args()): d::print := object -> _equal(extop(object)): d(1, 65), d(2, 28), d(3, 42)
Without a slot "map" the function f will be applied to the domain element itself. Because the domain d has no slot "_mult", the result is the symbolic _mult call:
map(d(1, 65), _mult, 1.16), type(map(d(1, 65), _mult, 1.16))
The slot "map" of this domain should map the given function only onto the second operand of a domain element. The domain d gets a slot "map" and map works properly (in the authors sense) with elements of this domain:
d::map := proc(obj, f) begin if args(0) > 2 then d(extop(obj, 1), f(extop(obj, 2), args(3..args(0)))) else d(extop(obj, 1), f(extop(obj, 2))) end_if end_proc: map(d(1, 65), _mult, 1.16), map(d(2, 28), _mult, 1.16), map(d(3, 42), _mult, 1.16)
map does not work recursively. Suppose that we want to de-nest a nested list. We use map to apply the function op, which replaces a list by the sequence of its operands, to all entries of the list l. However, this only affects the entries at the first level:
l := [1, [2, [3]], [4, [5]]]: map(l, op)
Use misc::maprec to achieve the desired behavior:
[misc::maprec(l, {DOM_LIST} = op)]
object |
An arbitrary MuPAD object |
f |
A function |
p_{1}, p_{2}, … |
Any MuPAD objects accepted by f as additional parameters |