4
$\begingroup$

I want to generalize the following table to a summation over $s[1], \ldots, s[N]$ and $t[1], \ldots t[N]$, where each variable sums over $\{-1, 1\}$.

Table[ expr , {s[1], {-1, 1}}, {s[2], {-1, 1}},  {s[3], {-1, 1}}, {t[1], {-1, 1}}, t[2], {-1, 1}}, {t[3], {-1, 1}} ]

The expression depends on both arrays $s$ and $t$ in some complicated way.

Basically, instead of writing out the sums over each of the array indices $s[1], s[2], s[3], t[1], t[2], t[3]$, how can I write this in a general way depending on a parameter N?

$\endgroup$

3 Answers 3

4
$\begingroup$

I think this gets at the core or your question:

Clear[s, t]
n = 3;
vars = Join[Array[Indexed[s, #] &, n], Array[Indexed[t, #] &, n]];
vals = Tuples[{-1, 1}, 2 n];  (* the possible configs *)
rules = Thread[Rule[vars, #]] & /@ vals;  (* rules linking vars to each config *)
vars /. rules  (* an expression in the vars, at each config *)
$\endgroup$
3
$\begingroup$

Here's an evaluation-leak free way: (i.e. it will work even if s[1] etc. have values outside the Table)

n = 3;
Replace[
  Join[s /@ Hold @@ Range@n, t /@ Hold @@ Range@n],
  v_ :> {v, {-1, 1}},
  1
  ] /.
 Hold[s___] :> Hold@Table[(*remove Hold to evaluate*)
    expr,
    s
    ]
(* Hold[
 Table[expr, {s[1], {-1, 1}}, {s[2], {-1, 1}}, {s[3], {-1, 1}}, {t[
    1], {-1, 1}}, {t[2], {-1, 1}}, {t[3], {-1, 1}}]] *)

As noted in the comment above, you'd need to remove the Hold to let the table evaluate. To see how this works, I show some of the individual steps of the above expression:

(* list of s "variables" *)
s /@ Hold @@ Range@n
(* Hold[s[1], s[2], s[3]] *)

(* combine with t "variables" *)   
Join[s /@ Hold @@ Range@n, t /@ Hold @@ Range@n]
(* Hold[s[1], s[2], s[3], t[1], t[2], t[3]] *)

(* insert the iterator specifications *)
Replace[
 Join[s /@ Hold @@ Range@n, t /@ Hold @@ Range@n],
 v_ :> {v, {-1, 1}},
 1
 ]
(* Hold[{s[1], {-1, 1}}, {s[2], {-1, 1}}, {s[3], {-1, 1}}, {t[
   1], {-1, 1}}, {t[2], {-1, 1}}, {t[3], {-1, 1}}] *)

If you don't care about evaluation leaks, this is enough:

n = 3;
Hold@Table[expr, ##] & @@ (
  {#, {-1, 1}} & /@ Join[s /@ Range@n, t /@ Range@n]
  )
(* Hold[
 Table[expr, {s[1], {-1, 1}}, {s[2], {-1, 1}}, {s[3], {-1, 1}}, {t[
    1], {-1, 1}}, {t[2], {-1, 1}}, {t[3], {-1, 1}}]] *)

Again, you'd need to remove the hold in your actual code.

You could also consider using Array if you can change in what way the variables are used:

n = 3;
Array[f[##] &, ConstantArray[2, n], {-1, 1}]
(* {{{f[-1, -1, -1], f[-1, -1, 1]}, {f[-1, 1, -1], 
   f[-1, 1, 1]}}, {{f[1, -1, -1], f[1, -1, 1]}, {f[1, 1, -1], 
   f[1, 1, 1]}}} *)

Here, the function f simply gets the values of the s[…] and t[…] in sequence.

$\endgroup$
2
$\begingroup$

@Alan have gave an elegant way to solve the problem.

Here we just mention that the original expression:

Table[expr[s1, s2, s3, t1, t2, t3], {s1, {-1, 1}}, {s2, {-1, 1}}, {s3, {-1, 1}}, {t1, {-1,1}}, {t2, {-1, 1}}, {t3, {-1, 1}}]

is equivalent to

Outer[expr, {-1, 1}, {-1, 1}, {-1, 1}, {-1, 1}, {-1, 1}, {-1, 1}]
$\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.