# Why is the variable inside the compiled code a tensor but not a scalar?

Consider the data data0, data1:

data0 = RandomReal[{0, 1}, {10^4, 3}];
(*Number of columns pairs*)
npairs = 12;
data1 = RandomReal[{0, 1}, {100, 2*npairs}];


and some function func1 that would use the values of data0, data1:

func1[x1_, y1_, x2_, y2_, X0_, Y0_] =
Exp[-x1^2 - y1^2 - x2^2 - y2^2]/(X0^2 + Y0^2);


I would like to sum some boolean conditions using func1 for the following combinations of pairs of columns of data1:

PairCombinations={{1,2},{1,8},{2,12},{3,9},{4,5},{4,8}};


This is my code:

compblock2 =
Hold@Compile[{{data0, _Real, 1}, {data1, _Real,
2}, {PairCombinations, _Real, 2}},
Module[{count, X0val, Y0val, xval1, yval1, xval2, yval2, Func1,
comb1, comb2}, count = 0.;
X0val = CompileGetElement[data0, 1];
Y0val = CompileGetElement[data0, 2];
(*This Do goes over all pair combinations in the table PairCombination*)
Do[
(*These are the identifiers of the pairs of columns used in the calculation*)
comb1 = PairCombinations[[m]][[1]];
comb2 = PairCombinations[[m]][[2]];
(*This Do goes over all rows of data1*)
Do[
(*Here I extract the values of the selected columns*)
xval1 = CompileGetElement[data1, i, 2*(comb1 - 1) + 1];
yval1 = CompileGetElement[data1, i, 2*(comb1 - 1) + 2];
xval2 = CompileGetElement[data1, i, 2*(comb2 - 1) + 1];
yval2 = CompileGetElement[data1, i, 2*(comb2 - 1) + 2];
Func1 = func1[xval1, yval1, xval2, yval2, X0val, Y0val];
(*This is the summation of boolean conditions*)
count += Boole[Func1 > 0.001], {i, 1, Length[data1], 1}], {m,
1, Length[PairCombinations], 1}];
{count}], CompilationTarget -> "C", RuntimeOptions -> "Speed",
RuntimeAttributes -> {Listable}, Parallelization -> True] /.
DownValues@func1 // ReleaseHold


When trying to compile the code, I get the error:

Compile::argcompten: The comparison, Greater, is invalid for tensor arguments.

This means that Func1 (and already xval1, etc.) is not the quantity of the desired type (scalar), but a tensor instead. I do not understand what is the origin of this problem.

How to fix this issue?

As often with Comiple, CompiledFunctionToolsCompilePrint is your friend: Since the function won't compile at all in its current state, I removed the problematic expression by trying count += Func1, and then I replaced count=0. with count={{0.}} to get rid of the error about tensor ranks in the addition. At this point, you can look at the compiled version of the function:

compblock2 =
Hold@Compile[{{data0, _Real, 1}, {data1, _Real,
2}, {PairCombinations, _Integer, 2}},
Module[{count, X0val, Y0val, xval1, yval1, xval2, yval2, Func1,
comb1, comb2}, count = {{0.}};
X0val = CompileGetElement[data0, 1];
Y0val = CompileGetElement[data0, 2];
(*This Do goes over all pair combinations in the table \
PairCombination*)
Do[(*These are the identifiers of the pairs of columns used in \
the calculation*)comb1 = PairCombinations[[m]][[1]];
comb2 = PairCombinations[[m]][[2]];
(*This Do goes over all rows of data1*)
Do[(*Here I extract the values of the selected columns*)
xval1 = CompileGetElement[data1, i, 2*(comb1 - 1) + 1];
yval1 = CompileGetElement[data1, i, 2*(comb1 - 1) + 2];
xval2 = CompileGetElement[data1, i, 2*(comb2 - 1) + 1];
yval2 = CompileGetElement[data1, i, 2*(comb2 - 1) + 2];
Func1 = func1[xval1, yval1, xval2, yval2, X0val, Y0val];
(*This is the summation of boolean conditions*)
count += Func1, {i, 1, Length[data1], 1}], {m, 1,
Length[PairCombinations], 1}];
{count}], CompilationTarget -> "C", RuntimeOptions -> "Speed",
RuntimeAttributes -> {Listable}, Parallelization -> True] /.
DownValues@func1 // ReleaseHold

<< CompiledFunctionTools

CompilePrint@compblock2
(* "    3 arguments
10 Integer registers
7 Real registers
15 Tensor registers
Underflow checking off
Overflow checking off
Integer overflow checking off
RuntimeAttributes -> {Listable}

T(R1)0 = A1
T(R2)1 = A2
T(R2)2 = A3
I4 = 0
I1 = 2
I9 = -1
I0 = 1
T(R2)3 = {{0.}}
Result = T(R3)8

1   T(R2)9 = CopyTensor[ T(R2)3]]
2   R3 = GetElement[ T(R1)0, I0]
3   R2 = GetElement[ T(R1)0, I1]
4   I3 = Length[ T(R2)2]
5   I5 = I4
6   goto 84
7   T(R1)7 = Part[ T(R2)2, I5]
8   R1 = Part[ T(R1)7, I0]
9   T(R1)7 = Part[ T(R2)2, I5]
10  R0 = Part[ T(R1)7, I1]
11  I7 = Length[ T(R2)1]
12  I8 = I4
13  goto 83
14  R5 = I9
15  R4 = R1 + R5
16  R5 = I1
17  R5 = R5 * R4
18  R4 = I0
19  R5 = R5 + R4
20  R4 = I9
21  R6 = R1 + R4
22  R4 = I1
23  R4 = R4 * R6
24  R6 = I0
25  R4 = R4 + R6
26  T(R2)7 = MainEvaluate[ Hold[CompileGetElement][ T(R2)1, I8, R4]]
27  R5 = I9
28  R4 = R1 + R5
29  R5 = I1
30  R5 = R5 * R4
31  R4 = I1
32  R5 = R5 + R4
33  R4 = I9
34  R6 = R1 + R4
35  R4 = I1
36  R4 = R4 * R6
37  R6 = I1
38  R4 = R4 + R6
39  T(R2)6 = MainEvaluate[ Hold[CompileGetElement][ T(R2)1, I8, R4]]
40  R5 = I9
41  R4 = R0 + R5
42  R5 = I1
43  R5 = R5 * R4
44  R4 = I0
45  R5 = R5 + R4
46  R4 = I9
47  R6 = R0 + R4
48  R4 = I1
49  R4 = R4 * R6
50  R6 = I0
51  R4 = R4 + R6
52  T(R2)5 = MainEvaluate[ Hold[CompileGetElement][ T(R2)1, I8, R4]]
53  R5 = I9
54  R4 = R0 + R5
55  R5 = I1
56  R5 = R5 * R4
57  R4 = I1
58  R5 = R5 + R4
59  R4 = I9
60  R6 = R0 + R4
61  R4 = I1
62  R4 = R4 * R6
63  R6 = I1
64  R4 = R4 + R6
65  T(R2)4 = MainEvaluate[ Hold[CompileGetElement][ T(R2)1, I8, R4]]
66  T(R2)11 = Square[ T(R2)7]
67  T(R2)12 = - T(R2)11
68  T(R2)11 = Square[ T(R2)5]
69  T(R2)8 = - T(R2)11
70  T(R2)11 = Square[ T(R2)6]
71  T(R2)13 = - T(R2)11
72  T(R2)11 = Square[ T(R2)4]
73  T(R2)14 = - T(R2)11
74  T(R2)12 = T(R2)12 + T(R2)8 + T(R2)13 + T(R2)14
75  T(R2)8 = Exp[ T(R2)12]
76  R5 = Square[ R3]
77  R4 = Square[ R2]
78  R5 = R5 + R4
79  R4 = Reciprocal[ R5]
80  T(R2)12 = R4 * T(R2)8
81  T(R2)8 = T(R2)9 + T(R2)12
82  T(R2)9 = CopyTensor[ T(R2)8]]
83  if[ ++ I8 <= I7] goto 14
84  if[ ++ I5 <= I3] goto 7
85  T(R3)8 = {T(R2)9}
86  Return " *)


Immediately problematic is any line with MainEvaluate, because that is usually an indication that Compile didn't understand something as expected. Let's look at the first of them:

26  T(R2)7 = MainEvaluate[ Hold[CompileGetElement][ T(R2)1, I8, R4]]


The T(Rx)y is to be read as "tensor of rank x, number y. Similarly, Ix is the xth integer register, and Ry the yth real register. So what is happening is that compile thinks you are doing something of the form

CompileGetElement[{{...},...}, 123, 2.4]


which is obviously wrong. Tracking down where R4 comes from, you'll see that it ultimately comes from

7   T(R1)7 = Part[ T(R2)2, I5]
8   R1 = Part[ T(R1)7, I0]


which in turn come from

T(R2)2 = A3


This means that because A3 (the third argument) is declared as a rank 2 tensor of reals, Compile decided that your CompileGetElement call gets a real number as index, making it invalid. Knowing this, the fix is easy: Simply replace {PairCombinations, _Real, 2} with {PairCombinations, _Integer, 2}:

compblock2 =
Hold@Compile[{{data0, _Real, 1}, {data1, _Real,
2}, {PairCombinations, _Integer, 2}},
Module[{count, X0val, Y0val, xval1, yval1, xval2, yval2, Func1,
comb1, comb2}, count = 0.;
X0val = CompileGetElement[data0, 1];
Y0val = CompileGetElement[data0, 2];
(*This Do goes over all pair combinations in the table \
PairCombination*)
Do[(*These are the identifiers of the pairs of columns used in \
the calculation*)comb1 = PairCombinations[[m]][[1]];
comb2 = PairCombinations[[m]][[2]];
(*This Do goes over all rows of data1*)
Do[(*Here I extract the values of the selected columns*)
xval1 = CompileGetElement[data1, i, 2*(comb1 - 1) + 1];
yval1 = CompileGetElement[data1, i, 2*(comb1 - 1) + 2];
xval2 = CompileGetElement[data1, i, 2*(comb2 - 1) + 1];
yval2 = CompileGetElement[data1, i, 2*(comb2 - 1) + 2];
Func1 = func1[xval1, yval1, xval2, yval2, X0val, Y0val];
(*This is the summation of boolean conditions*)
count += Boole[Func1 > 0.001], {i, 1, Length[data1], 1}], {m,
1, Length[PairCombinations], 1}];
{count}], CompilationTarget -> "C", RuntimeOptions -> "Speed",
RuntimeAttributes -> {Listable}, Parallelization -> True] /.
DownValues@func1 // ReleaseHold
`