map -- apply a function to all
operands of an object
Introductionmap(object, f) applies the function
f to all operands of object.
Call(s)map(object, f <, p1, p2, ...>)
Parametersobject |
- | an arbitrary MuPAD object |
f |
- | a function |
p1, p2, ... |
- | any MuPAD objects accepted by f as
additional parameters |
Returnsa copy of object with f applied to all
operands.
object
Related
Functionseval, mapcoeffs, misc::maprec, op, select, split, subs, subsex, subsop, zip
Detailsmap(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).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).x of object is replaced
by f(x, p1, p2, ...) (see example 1).+ or *, to all operands of object,
by using its functional equivalent, such as _plus or _mult. See example 1.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).object is a string,
then f is applied to the string as a whole and not to the
individual characters (see example 3).object is an expression,
then f is applied to the operands of f as
returned by op (see example
1).object is an expression
sequence, then this sequence is not flattened by map (see example 4).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).object is a list, a set, or an array,
then the function f is applied to all elements of the
corresponding data structure.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.
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 (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).map is a function of the system kernel.
Example
1map works for expressions:
>> map(a + b + 3, sin)
sin(a) + sin(b) + sin(3)
The optional arguments of map are passed to
the function being mapped:
>> map(a + b + 3, f, x, y)
f(a, x, y) + f(b, x, y) + f(3, x, y)
In the following example, we add 10 to each
element of a list:
>> map([1, x, 2, y, 3, z], _plus, 10)
[11, x + 10, 12, y + 10, 13, z + 10]
Example
2Like 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)
[0, 1, 0, -1]
The list a still has its original
value:
>> a
-- PI 3 PI --
| 0, --, PI, ---- |
-- 2 2 --
Example
3map does not decompose rational and complex
numbers:
>> map(3/4, _plus, 1), map(3 + 4*I, _plus, 1)
7/4, 4 + 4 I
map does not decompose strings:
>> map("MuPAD", text2expr)
MuPAD
map does not decompose polynomials:
>> map(poly(x^2 + x + 1), _plus, 1)
2
poly(x + x + 1, [x]) + 1
Use mapcoeffs to apply a function to
all coefficients of a polynomial:
>> mapcoeffs(poly(x^2 + x + 1), _plus, 1)
2
poly(2 x + 2 x + 2, [x])
Example
4The first argument is not flattened:
>> map((1, 2, 3), _plus, 2)
3, 4, 5
Example
5Sometimes 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)
{ 1/2 1/2 1/2 1/2 1/2 1/2
{ 2 ((1 - 4 PI) - 1) 2 ((1 - 4 PI) - 1)
{ - ---------------------------, ---------------------------,
{ 2 2
1/2 1/2 1/2
2 (- (1 - 4 PI) - 1)
- -----------------------------,
2
1/2 1/2 1/2 }
2 (- (1 - 4 PI) - 1) }
----------------------------- }
2 }
>> map(%, float)
{- 0.7976383425 - 1.065939457 I,
- 0.7976383425 + 1.065939457 I,
0.7976383425 - 1.065939457 I, 0.7976383425 + 1.065939457 I}
Example
6In 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
8
>> map(anames(All, User), _delete)
{}
>> x + y
x + y
Example
7It 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
phi(n) = n - 1'', where phi 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 phi(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)))
[TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE]
Example
8The result of map is not evaluated further.
If desired, you must request evaluation explicitly by eval:
>> map(sin(5), float); eval(%)
sin(5.0)
-0.9589242747
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)
-0.6752620892
Example
9map 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)
table(
3 = 48.72,
2 = 32.48,
1 = 75.4
)
Example
10map 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)
1 = 65, 2 = 28, 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))
1.16 (1 = 65), "_mult"
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)
1 = 75.4, 2 = 32.48, 3 = 48.72
Example
11map 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)
[1, 2, [3], 4, [5]]
Use misc::maprec to achieve the desired
behavior:
>> [misc::maprec(l, {DOM_LIST} = op)]
[1, 2, 3, 4, 5]