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$
  • 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 Jun 16 '15 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 Jun 16 '15 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. Jun 16 '15 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 Jun 16 '15 at 23:16
  • $\begingroup$ @m_goldberg Strange. And your "MapCompileLength" is set to 100? This is confirmed? $\endgroup$ – C. E. Jun 16 '15 at 23:33
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$
  • $\begingroup$ Thx for verifying comment , +1 $\endgroup$ – ciao Jun 16 '15 at 22:28
13
$\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$
  • $\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$ – Oleksandr R. Jun 16 '15 at 22:30
  • 1
    $\begingroup$ I think it's a great complement to my answer. +1 $\endgroup$ – C. E. Jun 16 '15 at 22:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.