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
  • 1
    $\begingroup$ Try G @@@ Tup[10]; or G @@ Transpose[Tup[10]];. The latter should be faster but may not always work. $\endgroup$ Commented Sep 16, 2018 at 21:11

2 Answers 2

8
$\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$
4
  • $\begingroup$ wow, the compilation really does rule! any insight on why a and b have such differing runtimes? $\endgroup$ Commented Sep 16, 2018 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$ Commented Sep 16, 2018 at 21:44
  • $\begingroup$ Beautiful! Thanks a lot. I appreciate the multiple solutions. $\endgroup$
    – Benighted
    Commented Sep 16, 2018 at 23:11
  • $\begingroup$ You're welcome. $\endgroup$ Commented Sep 17, 2018 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 and acknowledge you have read our privacy policy.

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