# Efficiently Evaluate a Multivariable Function on a List of Tuples

I have a function G[x,y,z,r,s,t] in the code below. Quite simply, I want to generate a list of all possible tuples $(x,y,z,r,s,t)$ such that all six entries are taken from the set $\{0,1,2,...,N-1\}$ where $N$ will be an integer parameter of the problem. I then want to evaluate $G$ on each of these tuples and as efficiently as I can, count the number of the tuples which evaluate to 0 modulo $N$. I at least have the following:

G[x_, y_, z_, r_, s_, t_] := x*y*z*(r^3 + s^3 + t^3) - r*s*t*(x^3 + y^3 + z^3); F[N_] := Range[0, N - 1]; Tup[N_] := Tuples[F[N], 6];

So Tup[N] is a list of all my tuples of interest. I was about to do a "for loop" ranging over the number of tuples and evaluate something like

G[Tup[][], Tup[][], Tup[][], Tup[][], Tup[][], Tup[][]]

for example, but this seems to be extremely inefficient. I'm sure there must be a smarter way! So given my G[x,y,z,r,s,t] as well as Tup[N] how can I construct a function P[N] which will output the number of tuples which evaluate to 0 modulo $N$?

• Try G @@@ Tup; or G @@ Transpose[Tup];. The latter should be faster but may not always work. Sep 16 '18 at 21:11

Here are several ways to perform the computations along with timings:

G2[X_] := X[] X[] X[] (X[]^3 + X[]^3 + X[]^3) -
X[] X[] X[] (X[]^3 + X[]^3 + X[]^3);
cG2 = With[{code = G2[Array[CompileGetElement[X, #] &, {6}]]},
Compile[{{X, _Integer, 1}},
code,
CompilationTarget -> "C",
RuntimeAttributes -> {Listable},
Parallelization -> True,
RuntimeOptions -> "Speed"
]
];

data = Tup;
a = G @@@ data; // RepeatedTiming // First
b = G @@ Transpose[data]; // RepeatedTiming // First
c = G2 /@ data; // RepeatedTiming // First
d = cG2[data]; // RepeatedTiming // First
e = Flatten[Outer[G, ## & @@ ConstantArray[F, 6]]]; // RepeatedTiming // First
a == b == c == d == e


4.012

0.068

7.30

0.0312

3.80

True

• wow, the compilation really does rule! any insight on why a and b have such differing runtimes? Sep 16 '18 at 21:37
• Well, b heavily uses vectorization and d is compiled. So, a and c have to struggle with the fact that Mathematica is an interpreted language, not a compiled one. They are also not parallelized. I am a bit surprised that c is so much slower than a Sep 16 '18 at 21:44
• Beautiful! Thanks a lot. I appreciate the multiple solutions. Sep 16 '18 at 23:11
• You're welcome. Sep 17 '18 at 4:06
tup1[N_] := Tuples[G @@ F[N], 6]


or

tup2[N_] := Flatten[Outer[G, ## & @@ ConstantArray[F[N], 6]]]


They both give the same result as G @@@ Tup[N] suggested by Henrik:

tup1 == tup2 == G @@@ Tup
`

True