6
$\begingroup$

This question is brought by this one.

Outer[Times, RandomReal[1., 1000000], {1., 2.}];

is much slower than

Outer[Times, RandomReal[1., 1000000], RandomReal[1., 2]];

because {1.,2.} is not packed array. The same problem also exists in Dot.

So a natural question is why so many built-in numerical function doesn't check its arguments to see if they are packed array or not? And transform all the unpacked to packed array? Because, PackedArrayQ and ToPackedArray don't take too much time.

Here is test

In[111]:= list = RandomReal[1., 1000000];
Developer`PackedArrayQ[list] // AbsoluteTiming

Out[112]= {1.81124*10^-6, True}

so PackedArrayQ is fast for list that are already packed.

In[113]:= list[[1]] = aaa;
Developer`PackedArrayQ[list] // AbsoluteTiming
Developer`ToPackedArray[list]; // AbsoluteTiming

Out[114]= {0.020944, False}

Out[115]= {3.62249*10^-6, Null}

if there is an element changed to symbol, PackedArrayQ is slower, but still pretty fast. And although perform ToPackedArray doesn't change anything, it does no harm, for it almost doesn't take time.

In[116]:= list[[1]] = 1.;
Developer`PackedArrayQ[list] // AbsoluteTiming
Developer`ToPackedArray[list]; // AbsoluteTiming

Out[117]= {1.81124*10^-6, False}

Out[118]= {0.0126244, Null}

If a list is all composed of machine number, PackedArrayQ is fast, while ToPackedArray is slower now, but again pretty fast for a list of 1000000 elements.

In conclusion, If built-in function first check all its argument's packedness and then convert all to packed array, this will not take too much time. For a 1000000 list, it takes at most 0.02 sec, and for {1.,2.} is the first example, negligible!. But the performance boost that packed array brings is huge. Then why mathematica doesn't do it?


PS. I'd also like to hear more comments why {1., 2.} + RandomReal[1., {2, 10000000}] doesn't suffer the problem of packedness?


update

I'd like to update a great illustration that showing how Packing and unpacking many times still brings performance boost. This shows add Packing will not harm the performance, welcome any counterexample

In[87]:= Outer[Times, RandomReal[1., 2], 
   Developer`FromPackedArray@
    RandomReal[1., 1000000]]; // AbsoluteTiming

Out[87]= {0.99861, Null}

and this one

In[86]:= Outer[Times, RandomReal[1., 2], 
   Developer`ToPackedArray@
    Developer`FromPackedArray@
     Developer`ToPackedArray@
      Developer`FromPackedArray@
       Developer`ToPackedArray@
        Developer`FromPackedArray@
         Developer`ToPackedArray@
          Developer`FromPackedArray@
           RandomReal[1., 1000000]]; // AbsoluteTiming

Out[86]= {0.536909, Null}
$\endgroup$

closed as off-topic by Daniel Lichtblau, m_goldberg, MarcoB, dr.blochwave, user9660 Nov 29 '15 at 18:48

  • The question does not concern the technical computing software Mathematica by Wolfram Research. Please see the help center to find out about the topics that can be asked here.
If this question can be reworded to fit the rules in the help center, please edit the question.

  • 1
    $\begingroup$ there is overhead in packing arrays so the list needs to be a minimum length to justify packing otherwise it is inefficient. The cut offs for many different functions are specified in system options which you will be able to find on this site but from memory lists under 200-250 in length will not be packed automatically because of the overhead involved. As always there are some exceptions to consider but getting back to your problem you should not expect to type {1.,2.} and have it automatically packed. $\endgroup$ – Mike Honeychurch Nov 29 '15 at 3:59
  • 1
    $\begingroup$ ** exception include functions like Range and RandomReal which will produce packed arrays even for lists of short lengths. $\endgroup$ – Mike Honeychurch Nov 29 '15 at 4:05
  • 1
    $\begingroup$ That's exactly my point. Say, someFunc[packed, unpacked] is faster without packing, but Do[someFunc[packed[i], unpacked], {i, 1000}] is faster if you prepack unpacked ONCE before invoking the loop, but slower if you pack it every time the loop loops. Now the analysis of whether to pack unpacked and whether it must be done inside the loop or once before the loop will itself be a huge hurdle. $\endgroup$ – LLlAMnYP Nov 29 '15 at 14:33
  • 1
    $\begingroup$ Try it with a symbolic g instead of a special case, optimized head like Times: With[{array2 = Developer`FromPackedArray@RandomReal[1., 1000000]}, Outer[g, {1., x}, Developer`ToPackedArray@array2]; // RepeatedTiming] -- 30% longer than without packing. $\endgroup$ – Michael E2 Nov 29 '15 at 16:31
  • 4
    $\begingroup$ I'm voting to close this question as off-topic because it appears to be a request for an enhancement to Mathematica and it thus not admissible to this site. $\endgroup$ – m_goldberg Nov 29 '15 at 17:21
1
$\begingroup$

More of an extended comment, but I have found a single counterexample, where it's longer to pack, than to just do it.

Edit: of course this needs <<Developer` first.

Do[Outer[Times, ToPackedArray[{3.}], ToPackedArray[{5.}]], {1000000}] // AbsoluteTiming
(* {1.62244, Null} *)

Do[Outer[Times, {3.}, {5.}], {1000000}] // AbsoluteTiming
(* {0.929396, Null} *)

Of course the silly case of an outer product of lists of length one will hardly be useful anywhere.

$\endgroup$
  • $\begingroup$ I have to say this is far from practical case... $\endgroup$ – matheorem Nov 30 '15 at 1:01

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