# Mapping multiple parameters of a function to specific values

I am a little bit confused by the documentation for Apply (@@).

I want to define a list of parameters, for instance:

parameters = {{1/2, 1/2}, {1, 1/3}, {2, 1/4}, {0.5, 1/5}};


Then I have a function:

(b/a)*((a/x)^(b+1))


Now I want to map the pair (a,b) to the values defined in parameters and generate a plot for each pair of parameters in the same graph.

Now the plot syntax would look something like this:

p = Plot[Evaluate[myfunction /@ parameters], {x, 0, 3},
AxesOrigin -> {0, 0}, AxesLabel -> {x, f}, PlotStyle -> styles]


What I struggle with, is getting the syntax right in the following part:

myfunction /@ parameters


How do I need to define this so I get a proper map of (a,b) to my list of parameters? To be honest, I am not very satisfied with the documentation for Map. Are there better tutorials?

-
Though old and extremely limited in scope , there's always the Flash tutorials. –  Brett Champion May 6 '12 at 4:33

There are two main ways of accomplishing this, both have their merits, but Map may be easier to understand initially. For instance, using (b/a)*((a/x)^(b+1)) I would do the following,

(#[[2]]/#[[1]])(#[[1]]/x)^(#[[2]]+1)& /@ parameters


where #[[1]] and #[[2]] are a and b, respectively. But, this makes it difficult to read, alternatively you can use With to improve the readability, as follows,

With[{a = #[[1]], b = #[[2]]}, (b/a)*((a/x)^(b+1))]& /@ parameters


It is longer, but it is more readable. I tend to use With in this way. The second method is to use Apply, as outlined by R.M. Here With can also be used,

With[{a = #1, b = #2}, (b/a)*((a/x)^(b+1))]& @@@ parameters


but it is less likely to be confusing when you come back to the code a month later.

-
Ok! Does the "#" in front designate it as a parameter? Does the number designate the order, so that the program knows which value from {number1, number2} to map? Why do we have 3 @'s. How does this "level" theory work? –  Chris May 6 '12 at 3:15
@Chris The # is a formal parameter known as a Slot. # is shorthand for #1. In my example using Map, #[[1]] refers to the first element of the first parameter. As noted by RM, Apply differs in that it replaces the Head of an expression, so Apply[f, {x,y}] (shorthand f@@{x,y}) becomes f[x,y]. The @@@ is shorthand for Apply[f, {{1,2},{3,4}}, {1}] which results in {f[1,2], f[3,4]}. Because the elements become arguments, #1 becomes a and #2 becomes b in your question. –  rcollyer May 6 '12 at 3:20
For the last approach (using @@@) you could use Function[{a, b}, (b/a)*((a/x)^(b + 1))] instead of With. –  Brett Champion May 6 '12 at 4:19

Here's another way:

parameters = {{1/2, 1/2}, {1, 1/3}, {2, 1/4}, {0.5, 1/5}};

myfunction[{a_, b_}] := (b/a)*((a/x)^(b + 1))

Plot[myfunction /@ parameters, {x, 0, 3}, Evaluated -> True]


Using plain x here is not local; you should consider using \[FormalX] instead. The example above is "safe" because x is localized by Plot (it would not be if you used Plot[ Evaluated @ ... ] instead of Evaluated -> True). On the other hand if you accidentally assign a value to x and then try something like myfunction[{1, 1/3}] /. x -> 5 it will not behave as expected. Formal Symbols are symbols that Mathematica will not let you assign a value to, protect you from yourself in a case like this. It is a good idea to use them if you are going to create a definition with a "floating" undefined symbol like x in the example above.

-
Can you expand upon \[FormalX] and why it is useful? Why does it work here, when x would not? –  rcollyer May 6 '12 at 3:14
@rcollyer well here it is not needed because Evaluated -> True rather than Evaluated @ localizes x anyway, but generally speaking it's a bad idea to float around a global variable that's not supposed to have a value, because at some point it might be assigned one accidentally. That's what the Formal Symbols are for. (I know you know this.) –  Mr.Wizard May 6 '12 at 3:23
I did know that, I just tend not to use them. I was trying to get you to expand your answer a little ... :P But, Evaluated is news to me; it does not show up in the docs, but is in Options[Plot]. –  rcollyer May 6 '12 at 3:28
Incidentally, the Evaluated trick is on Szabolcs' web page. It is about 1/3 the way down the page. –  rcollyer May 6 '12 at 14:02
@rcollyer outside of SE I can track it back to at least this. –  Mr.Wizard May 6 '12 at 18:33
show 7 more comments

You can define your function as an anonymous function and use Apply at level 1 or @@@:

myfunction[x_] := #2/#1 ((#1/x)^(#2 + 1)) &
Plot[Evaluate[myfunction[x] @@@ parameters], {x, 0, 3},
AxesOrigin -> {0, 0}, AxesLabel -> {x, f}]


Think of Apply as something that replaces the Head of an expression. For example, the head of g[a, b] is g. Now if you apply f to that expression, you get:

f @@ g[a, b]
(* Out= f[a, b] *)


You see that the head has been replaced with f. The long form of Apply also takes a third argument, where you can specify the Level that you want it to act on i.e., you can write Apply[f, expr, {level}].

Apply at level 1 is used very often, that it has its own shorthand, which is @@@ and is what I've used above. Here's an example showing the difference between @@ and @@@:

f @@ g[h[a, b], h[c, d]]
(* Out= f[h[a, b], h[c, d]] *)

f @@@ g[h[a, b], h[c, d]]
(* Out= g[f[a, b], f[c, d]] *)

-
I was working so hard to include both methods, but you stole my thunder, +1. :) –  rcollyer May 6 '12 at 3:09
Is that & at the end of the line where myfunction is defined necessary? Why can't I defined the function, put a ; at the end and then run the plot? –  Chris May 6 '12 at 3:25
@Chris he's being clever. As pointed out by Mr.Wizard, x is global, and within the bounds of Evaluate it would take on it's global value. What that construct does is localize x to the local form. –  rcollyer May 6 '12 at 3:29
@Chris Yes, it is necessary. The & is what completes the pure function definition and it won't work without it. My definition above is a mix of named patterns (x_) which localizes the variable x and slots (#) which take the parameter values when you apply at level 1. –  rm -rf May 6 '12 at 3:30

Here's another solution, which uses replacement rules, and is syntactically closest to your original code (and, unlike most other solutions, doesn't require you to rewrite either myfunction or parameters).

p = Plot[Evaluate[myfunction /. {a->#1, b->#2}& @@@ parameters], {x, 0, 3},
AxesOrigin -> {0,0}, AxesLabel -> {x,f}, PlotStyle -> styles]


However, in case you can rewrite myfunction, the simplest solution would be to make it a function of the parameters:

myfunction[a_, b_] := (b/a)*((a/x)^(b+1))
p = Plot[Evaluate[myfunction @@@ parameters], {x, 0, 3},
AxesOrigin -> {0,0}, AxesLabel -> {x,f}, PlotStyle -> styles]


Or maybe cleaner (but slightly more verbose):

myfunction[a_, b_, x_] := (b/a)*((a/x)^(b+1))
p = Plot[Evaluate[myfunction[##,x]& @@@ parameters], {x, 0, 3},
AxesOrigin -> {0,0}, AxesLabel -> {x,f}, PlotStyle -> styles]


On the other hand, if you cannot change myfunction, but can change how your parameters are written, you could directly write the latter as rules:

parameters = {{a->1/2, b->1/2}, {a->1, b->1/3}, {a->2, b->1/4}, {a->0.5, b->1/5}};


Then your plot call would just read

p = Plot[Evaluate[myfunction /. parameters], {x, 0, 3},
AxesOrigin -> {0,0}, AxesLabel -> {x,f}, PlotStyle -> styles]

-