6
$\begingroup$

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[2][[4]][[1]], Tup[2][[4]][[2]], Tup[2][[4]][[3]], Tup[2][[4]][[4]], Tup[2][[4]][[5]], Tup[2][[4]][[6]]]

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$?

$\endgroup$
  • 1
    $\begingroup$ Try G @@@ Tup[10]; or G @@ Transpose[Tup[10]];. The latter should be faster but may not always work. $\endgroup$ – Henrik Schumacher Sep 16 '18 at 21:11
7
$\begingroup$

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

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


data = Tup[10];
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[10], 6]]]; // RepeatedTiming // First
a == b == c == d == e

4.012

0.068

7.30

0.0312

3.80

True

$\endgroup$
  • $\begingroup$ wow, the compilation really does rule! any insight on why a and b have such differing runtimes? $\endgroup$ – Ben Kalziqi Sep 16 '18 at 21:37
  • 1
    $\begingroup$ 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 $\endgroup$ – Henrik Schumacher Sep 16 '18 at 21:44
  • $\begingroup$ Beautiful! Thanks a lot. I appreciate the multiple solutions. $\endgroup$ – Benighted Sep 16 '18 at 23:11
  • $\begingroup$ You're welcome. $\endgroup$ – Henrik Schumacher Sep 17 '18 at 4:06
5
$\begingroup$
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[7] == tup2[7] == G @@@ Tup[7]

True

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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