compiled function does not extract elements from a matrix, proceed with uncompiled evaluation

I have written a small piece of code for a function that extracts certain elements from a matrix and then sum them and return the result. Although the uncompiled version works, when I try to switch to a compilable function something goes wrong:

microstep = Compile [{{matrix, _Integer, 2}, {arraydim, _Integer}},
Module[{

tempmatrix = matrix,
randomtuple = {x , y } = RandomInteger[{1, arraydim}, 2], (*select a random element of  the matrix*)

down = {Mod[x + 1, arraydim, 1], y},  (*find the nearest neighbours  and *)
up = {Mod[x - 1, arraydim, 1], y},    (*impose periodic boundary conditions*)
left = {x, Mod[ y - 1, arraydim, 1]},
right = {x, Mod[y + 1, arraydim, 1]}, spindiff},

spindiff = Total[Extract[tempmatrix, #] & /@ {up, down, left, right}]

],
CompilationTarget -> "C", RuntimeOptions -> "Speed"]

microstep[confiniziale, 5]


where confiniziale is a 5x5 matrix whose elements are randomly chosen between -1 and 1.

confiniziale = RandomChoice[{-1, 1}, {lato, lato}];


The plan was to further develop her and implement a Metropolis algorithm. The errors i get are :

1) Extract: "Position specification {4.,2.} in Extract[*mymatrix,,{4.,2.}] is not applicable

and

2) CompiledFunction : " compiled expression Extract[*mymatrix,{4.,2.}] should be a rank 2 tensor of machine-size real numbers

and then the function continues using the uncompiled version giving the right result. what am I missing? any tips?

• Does spindiff = Total[CompileGetElement[tempmatrix, ##] & @@@ {up, down, left, right}] work? – kglr May 12 '18 at 5:39
• @kglr it says " Compilation of COmpileGetElement(tempmatrix,##1) &)@@CompileGetElement(SystemPrivateCompileSymbol(0),SystemPrivateCompileSymbol(1)) is not supported for the function argument CompileGetElement(tempmatrix,##1)&. The only function arguments supported are Times,Plus,or List. Evaluation will use the uncompiled function" – Alucard May 12 '18 at 5:47
• It's worth pointing out that randomtuple = {x , y } = RandomInteger[{1, arraydim}, 2] is also causing trouble here. x and y isn't localized. – xzczd May 12 '18 at 6:46
• @xzczd ah yes , thank you – Alucard May 12 '18 at 6:52

This is how I would write your CompiledFunction:

microstep = Compile[{{matrix, _Integer, 2}},
Module[{x, y, dimx, dimy},
dimx = CompileGetElement[Dimensions[matrix], 1];
dimy = CompileGetElement[Dimensions[matrix], 2];
x = RandomInteger[{1, dimx}];
y = RandomInteger[{1, dimy}];
Plus[
CompileGetElement[matrix, Mod[x + 1, dimx, 1], y],
CompileGetElement[matrix, Mod[x - 1, dimx, 1], y],
CompileGetElement[matrix, x, Mod[y - 1, dimy, 1]],
CompileGetElement[matrix, x, Mod[y + 1, dimy, 1]]
]
],
CompilationTarget -> "C",
RuntimeOptions -> "Speed"
]


The major issue was that Extract is not compilable and Compile seems to be unable to build a reasonable call to the main evaluator. Anyway, you wouldn't have fun with a compiled function that has to call the main evaluator (slow).

Another mild issue:

You use quite a lot of tensor operations like left = {x, Mod[ y - 1, arraydim, 1]}, for vectors of length 2. That's very inefficient within Compile since each of these calls will involve a CopyTensor which is notoriously slow. And in the end, you have to retrieve the elements of these vectors again, undoing the whole costly process of putting things into vectors.

• thanks ! where can i find the documentation for GetElement ? i couldn't find it on the wolfram center. – Alucard May 12 '18 at 6:43
• There is not documentation for it, but it gets frequently used on this site. In a nutshell, it is a read-only variant of Part with the difference that does not check every time whether the indices are within the bounds of the array. That makes it considerably faster than Part but the programmer has to do the bound checks. Otherwise the kernel will quit when the function is called. – Henrik Schumacher May 12 '18 at 6:49
• one last question : do you know if Mathematica speed up by a noteworthy amount if i switch to helical boundary conditions? or the Mod function is pretty much irrelevant for the absolute time? – Alucard May 12 '18 at 6:50
• Mod is very quick. No need to take pain for optimizing it away. – Henrik Schumacher May 12 '18 at 6:51
• sorry to bother you again henrik but when i try to check whether the sum (spinsum= Plus[...]) is lesser than 0 i get a warning message that tells me that spinsum should be a machine-size real number. Do you know hw to solve this problem? – Alucard May 12 '18 at 7:23