The role and meaning of Listable
The Listable attribute serves to impose automatic threading over lists for symbols for which it is set (or present from the start, for some built-in functions).
Conceptually, Listable attribute is more or less equivalent to
ClearAll[setListable];
setListable[f_]:=
call:f[left___,l_List,right___]:=
Module[{myHold},
SetAttributes[myHold,HoldAll];
With[
{
heldres=
Hold[Evaluate[Quiet[Check[myHold[left,l,right]//.
m_myHold:>Thread[m],$Failed]]]]/.
myHold->f
},
If[heldres===Hold[$Failed],
Message[Thread::tdlenMessageName,call]
];
ReleaseHold[heldres]/;heldres=!=Hold[$Failed]&&heldres=!=Hold[call]
]
];
so that e.g.
ClearAll[f];
setListable[f];
f[{1, 2, 3}, 1]
f[{{1, 2, 3}}, {{4, 5, 6}}, 1]
give
(* {f[1, 1], f[2, 1], f[3, 1]} *)
(* {{f[1, 4, 1], f[2, 5, 1], f[3, 6, 1]}} *)
but when there are more than one lists passed, and of different lengths, it is then an error:
f[{1, 2, 3}, {4, 5}]
During evaluation of In[666]:= Thread::tdlen: Objects of unequal length in f[{1,2,3},{4,5}] cannot be combined. >>
During evaluation of In[666]:= Thread::tdlen: Objects of unequal length in f[{1,2,3},{4,5}] cannot be combined. >>
(* f[{1, 2, 3}, {4, 5}] *)
what is important is that threading over lists happens before any user-defined DownValues fire for f, or UpValues fire for the arguments of f. So, this threading happens at a pretty early stage in the evaluation.
Built-in Listable functions
There are two types of listability - the one in built-in functions, which pushes threading into the kernel and is fast, and the top-level one (setting Listable for some functions by the user).
You can not achieve built-in listability by simply setting a Listable attribute. The reason is that, while the end result is the same - automatic threading over lists, the underlying mechanisms to achieve it are different for built-ins vs user-defined. When a built-in Listable function (particularly numerical) is passed lists as arguments, it dispatches to the special branch which internally runs the loop, and returns a list of results. So, for a built-in function, Listable is rather a signal to pick the internal branch which deals with lists automatically.
Listable vs. Map or Thread
Imagine that you have a function f, for example
ClearAll[f]
f[x_]:=Sow[x]
You may want to sow all elements of a nested list, in which case you can either
write
f[x_List]:=Map[f,x]
or set the Listable attribute:
ClearAll[f];
SetAttributes[f,Listable]
f[x_]:=Sow[x]
What is important to understand here:
The two forms are more or less speed-equivalent for top-level functions (but see the next point)
If you set the Listable attribute for a top-level function, then your definition based on Map has no chance to apply, even if present, because Listable - based threading happens much earlier in the evaluation sequence.
Both methods can give inferior speed as compared to explicit mapping, since you can use pure functions or other compilable functions in explicit mapping, and Map auto-compiles.
Worst-case scenario: spoiling built-in Listability via intermediate top-level Listable function
The worst thing you can do in terms of speed is e.g. the following:
ClearAll[f]
SetAttributes[f,Listable];
f[x_]:=x^2
Why? Because the Power function is internally Listable, so that you can simply define:
ClearAll[ff];
ff[x_]:=x^2
and apply this to a list without using explicit Map. But when you set f as Listable, you force the top-level (slow) threading before the more efficient internal threading has a chance to apply.
Here are some examples:
(res1 = ff[test]); // AbsoluteTiming
(res2 = Map[#^2 &, test]); // AbsoluteTiming
(res3 = f[test]); // AbsoluteTiming
(* {0.016720, Null} *)
(* {0.056495, Null} *)
(* {0.815428, Null} *)
You can see that the direct application is leveraging built-in Listable attribute of Power and is very fast. The Map is slower, but still quite fast since it auto-compiles. But the top-level Listable attribute makes it two orders of magnitude slower.
Summary
So, in summary, here are some recommendations related to performance-tuning and Listable attribute:
When you can use built-in Listable functions, just use them by passing entire lists to them and forget about the explicit Listable attribute.
Explicit mapping with Map can often be quite efficient too.
Do not use Listable attribute for speed, use it only for convenience / more compact and elegant code. In fact, the rule of thumb is that for numerical large arrays, chances are that top-level Listable is a wrong tool, while for certain symbolic manipulations can be a good option
This does not apply to the Listable attribute you can set in your compiled functions when using Compile - by all means do this when you can, because this one acts similarly to the built-in Listable attribute.
SqrtorSin(...) with attributeListabledirectly supplying lists as argument will be usually faster than usingMap(at least for numeric input). – Yves Klett Oct 31 '13 at 12:38Listablefor top-level functions (meaning, set by the user) does not provide much of a speed advantage overMap, if at all. But it can make things worse, becauseMapauto-compiles, when it can -Listablewill prevent that. I would say that the advantages of user-setListableare mostly not in speed but elsewhere - e.g. sometimes it can lead to very concise code. As @YvesKlett noted, it is different for numeric functions, and other built-inListablefunctions - thereListablebasically means that you push more work to the kernel, and this will always be faster. – Leonid Shifrin Oct 31 '13 at 12:48Listable's full behaviour cannot be replaced byMap– Rojo Oct 31 '13 at 14:10Listableis almost impossible, AFAIK. You can do e.g. this:ClearAll[f];SetAttributes[f, Listable]; f[x_] := x^2;f /; MemberQ[Stack[_], HoldForm[f[_?Developer`PackedArrayQ]]] := (#^2 &), but to my mind, this is hardly worth the effort in most cases. This will also make the function seriously slower on non-numeric lists, because it will have to inspect theStackat every invocation. Much simpler is to emulate Listability with an explicit rule likef[x_List/;!Developer`PackedArrayQ[x]]:=Map[f,x];f[x_]:=x^2. – Leonid Shifrin Oct 31 '13 at 15:15ListableQ" function, there should be some discussion of it here on SE. – Leonid Shifrin Oct 31 '13 at 15:16Listablefor some functions by the user). You can not achieve built-in listability by simply setting a Listable attribute, so for most cases, it will not speed things up. The reason is that, while the end result is the same - automatic threading over lists, the underlying mechanisms to achieve it are different for built-ins vs user-defined. – Leonid Shifrin Oct 31 '13 at 15:22