4

Today I witnessed the following strange behavior of Mathematica, when it comes to calculation time involving larger nested lists. The following is the short example that I setup, I am sure one can reproduce that behavior with other functions:

div[x_] := (RotateLeft[#, {1, 0}] - #) & @ x[[;; , ;; , 1]] + (RotateLeft[#, {0, 1}] - #) & @ x[[;; , ;; , 2]]

Which is some kind of discrete divergence operator, but this does not really matter here. And then I defined the corresponding lists to be evaluated by div:

testArray = Table[RandomReal[], {i, 1, 256}, {j, 1, 256}];
testArray2D = Table[{testArray[[i, j]], testArray[[j, i]]}, {i, Dimensions[testArray][[1]]}, {j, Dimensions[testArray][[2]]}];
testArray2Dnew = Table[{RandomReal[], RandomReal[]}, {i, 1, 256}, {j, 1, 256}];

It is obvious, that testArray2D and testArray2Dnew should be pretty much identical from a numerical standpoint (i.e. same dimensions, same kind of numbers and same precision). But when I apply div on both of them I get completely different calculation times:

Timing[div[testArray2D];]

delivers 0.035085 seconds and

Timing[div[testArray2Dnew];]

delivers 0.006100 seconds

Executing the above Timing commands over and over again does not change the results, so there is about a factor of 6 regarding calculation time.

Can somebody explain that behavior to me, because right now I am just confused.

mmal
  • 3,508
  • 2
  • 18
  • 38
Wizard
  • 2,720
  • 17
  • 28

1 Answers1

7

The reason for this difference in timing (and memory usage) is that testArray2Dnew is packed array:

Developer`PackedArrayQ[testArray]
Developer`PackedArrayQ[testArray2D]
Developer`PackedArrayQ[testArray2Dnew]
(*
True
False
True
*)

Packed arrays are an efficient way to store machine precision numerical data of the same type. In the documentation ToPackedArray is a starting point. If an internal function e.g. RotateLeft sees that it can make use of efficient code.