8
$\begingroup$

Can anyone help explain why MapThread is so slow in this simple case?

p = 0.1;
t = Table[1, {10^6}];
SeedRandom[1000];
AbsoluteTiming[a = Map[# RandomChoice[{p, 1 - p} -> {1, 0}] &, t];]
SeedRandom[1000];
AbsoluteTiming[b = MapThread[# RandomChoice[{p, 1 - p} -> {1, 0}] &, {t}];]
Norm[a-b]

outputs

{0.555723, Null}
{3.696282, Null}
0
$\endgroup$
6
  • 2
    $\begingroup$ MapThread unpacks the array... and does more work under the covers (what would you expect re: latter?), and I'd venture compilation (auto) behaves differently. $\endgroup$
    – ciao
    Commented Jun 16, 2015 at 22:18
  • $\begingroup$ In V10.1 on OS X, I'm getting the same time, ~3.7 sec, with both Map and MapThread. Can anyone confirm this? PackArrayQ returns False for both a and b. $\endgroup$
    – m_goldberg
    Commented Jun 16, 2015 at 22:44
  • $\begingroup$ @m_goldberg I'm used 10.1 on OS X to write my answer. What happens if you run the code in Oleksandr's answer? $\endgroup$
    – C. E.
    Commented Jun 16, 2015 at 23:06
  • $\begingroup$ @Pickett. From the compiled function `f`` I get timings comparable to what he got. The returned array is packed. $\endgroup$
    – m_goldberg
    Commented Jun 16, 2015 at 23:16
  • $\begingroup$ @m_goldberg Strange. And your "MapCompileLength" is set to 100? This is confirmed? $\endgroup$
    – C. E.
    Commented Jun 16, 2015 at 23:33

2 Answers 2

14
$\begingroup$

This is because of the compilation that kicks in automatically if the list in Map exceeds a certain number of elements.

"MapCompileLength" /. ("CompileOptions" /. SystemOptions["CompileOptions"])
(* Out: 100 *)

shows that the default setting is that if the list contains more than 100 elements then Map will be compiled. MapThread on the other hand does not seem to use automatic compilation.

This piece of code will test our hypothesis. Don't forget to reset the setting or restart the kernel once you're done:

SetSystemOptions["CompileOptions" -> "MapCompileLength" -> Infinity]

p = 0.1;
t = Table[1, {10^6}];
SeedRandom[1000];
AbsoluteTiming[a = Map[# RandomChoice[{p, 1 - p} -> {1, 0}] &, t];]
SeedRandom[1000];
AbsoluteTiming[
 b = MapThread[# RandomChoice[{p, 1 - p} -> {1, 0}] &, {t}];]
Norm[a - b]

(* Out: {3.57806, Null}, {3.66936, Null}, 0 *)
$\endgroup$
1
  • $\begingroup$ Thx for verifying comment , +1 $\endgroup$
    – ciao
    Commented Jun 16, 2015 at 22:28
12
$\begingroup$

Map is automatically compiled. Yes, even with RandomChoice. Try it:

f = Compile[{{p, _Real, 0}, {t, _Integer, 1}}, 
  Map[# RandomChoice[{p, 1 - p} -> {1, 0}] &, t]
 ];
f // InputForm (* -> clean bytecode *)

Check its performance:

p = 0.1;
t = Table[1, {10^6}];
SeedRandom[1000];

AbsoluteTiming[a = Map[# RandomChoice[{p, 1 - p} -> {1, 0}] &,t];] (* -> 0.578125 seconds *)

AbsoluteTiming[c = f[0.1, t];] (* -> 0.593750 seconds *)

The timings are the same, so this is the solution. It's also the reason that Map doesn't unpack and MapThread does. (Compiled code only works with packed arrays.)

MapThread doesn't have this ability and uses the uncompiled code. Map will be the same if it is not allowed to compile, as Pickett shows in his answer.

$\endgroup$
2
  • $\begingroup$ Pickett already said this, but I was already typing the answer when he posted his, so I thought I might as well post it. Maybe I'll delete it later though since I don't think it adds much to the question. $\endgroup$ Commented Jun 16, 2015 at 22:30
  • 1
    $\begingroup$ I think it's a great complement to my answer. +1 $\endgroup$
    – C. E.
    Commented Jun 16, 2015 at 22:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.