4
$\begingroup$

I am trying to do the summation shown below, $\sum_{i_1=0}^{imax_1} \sum_{i_2=0}^{imax_2} \dots \sum_{i_k=0}^{imax_k} f(i_1,\dots,i_k)$

$k$ is a variable. Therefore $i$ and $imax$ are defined as arrays of length $k$.

Array[i,k]
Array[imax,k]

Is there a way to accomplish this?

$\endgroup$
4
  • $\begingroup$ Did you try Sum[f,{i,imin,imax},{j,jmin,jmax}]? Maybe you can take a look at this and this. $\endgroup$
    – Rod
    Jun 14, 2013 at 23:03
  • $\begingroup$ will that work when i is an array? $\endgroup$
    – AIB
    Jun 14, 2013 at 23:04
  • $\begingroup$ Do you have any code which you've already tried to use? As far as I know you could also use {i,imin,imax,di},where di is the step size. $\endgroup$
    – Rod
    Jun 14, 2013 at 23:08
  • $\begingroup$ If the terms of your sum are all in an array, you can do this: Total[Array[f[#1, #2, ...] &, {imax1, imax2, ...}, {0, 0, ...}], -1]. $\endgroup$ Jun 15, 2013 at 1:12

3 Answers 3

5
$\begingroup$

Quite neat solution (if indices are from 0 to imax):

imax = RandomInteger[{1, 5}, k]
{1, 2, 1, 1}
Total[f @@@ Tuples[Range[0, #] & /@ imax]]
f[0, 0, 0, 0] + f[0, 0, 0, 1] + f[0, 0, 1, 0] + f[0, 0, 1, 1] + ...

Extension for case with imin different from 0.

Total[f @@@ Tuples[Range[##] & @@@ Transpose[{imin, imax}]]]

Edit: I am struggling with question if Array[i,k] is argument for f or set of indices to Array with values. Above solution is for the former. Latter can be easily achieved by following definition:

f[x__] := g @@ (a /@ {x})

if it is not clear one should evaluate this and then Total[...:

g[a[1], a[1], a[0], a[1]] + ....

Maybe this way for the last case is clearer:

Composition[
  Total,
  Apply[f, #, {1}] &, (* {1,2} -> f[1,2] *)
  Map[i, #, {2}] &, (* 1 -> i[1]*)
  Tuples,
  Map[Range[0, #] &, #] & (*creating sets of indices from 0 to imax_i*)
  ][imax]
f[i[0], i[0], i[0]] + f[i[0], i[0], i[1]] +...

So for more complicated cases I wolud choose halirutan's solution as shorter.

$\endgroup$
8
  • $\begingroup$ i and imax are defined as arrays... so it might be possible to i to be, for instance, greater than imax. In this case I believe the code wouldn't work... $\endgroup$
    – Rod
    Jun 15, 2013 at 0:38
  • $\begingroup$ @RodLm It seems I was thinkging about something else. If I understand well Your concern: don't worry, if Length@i > Max@imax it is going to works too. $\endgroup$
    – Kuba
    Jun 15, 2013 at 7:23
  • 2
    $\begingroup$ I'd rather use e.g. Total[f @@@ Tuples[Range[0, #] & /@ imax]] // Short for appropriate formatting instead of .... $\endgroup$
    – Artes
    Jun 15, 2013 at 8:58
  • $\begingroup$ @Artes Good point. I'll keep that in mind. I have just found Shallow, it suits well too. $\endgroup$
    – Kuba
    Jun 15, 2013 at 9:06
  • 1
    $\begingroup$ @AIB replace f@@@ on f/@: Total[f /@ Tuples[Range[0, #] & /@ imax]] $\endgroup$
    – Kuba
    Jun 16, 2013 at 14:17
3
$\begingroup$

Let's assume the following test data

k = 3;
vars = Array[i, k];
imax = RandomInteger[{1, 5}, k];
(*
  vars is {i[1], i[2], i[3]}
  imax is here {3, 5, 4}
*)

then the nested sum you try to achieve can be written as

Sum[f @@ vars, Evaluate[Sequence @@ ({#1, 0, #2} & @@@ Transpose[{vars, imax}])]]

Since I used a lot of operators which may not be easy to use by new Mathematica users, let me explain the approach in detail. What I want to create first is a list of your iterators. For this I first use Transpose[{vars, imax}] to create list which has the iteration variable and its upper bound side by side:

Transpose[{vars,imax}]
(* Out[5]= {{i[1],1},{i[2],3},{i[3],2}} *)

Now I need to transform this into the form {i[n],0,imaxn}. Therefore I use an anonymous function {#1, 0, #2}&. This function needs to be called like {#1, 0, #2}&[i[1],1] to work but we have sublist elements. They are in the form List[i[1],1]. If I would replace the List head with the anonymous function, everything would be fine. This is the reason why @@@ is used which replaces the heads of the elements inside the main list.

{#1,0,#2}&@@@Transpose[{vars,imax}]
(* Out[6]= {{i[1],0,1},{i[2],0,3},{i[3],0,2}} *)

In the above step we get a list of iteration bounds. This is not useful because we need to give them as Sequence to Sum. Therefore, we again replace a head but this time we replace the List head of the main iterator list by Sequence. Therefore @@ is used in contrast to @@@ which we used to replaced the heads of the elements of the list.

This very same trick is used to apply f to all iteration variables. We have them in a list vars and writing f@@vars creates f[i[1],i[2],...,i[k]].

In a last step we have to remember, that Sum has the attribute HoldAll. Therefore, it does not evaluate our iterator bounds we created so nicely. Instead it sees the whole expression

Sequence @@ ({#1, 0, #2} & @@@ Transpose[{vars, imax}])

which would lead to an error message because Sum expects appropriate bounds. The required evaluation of the above, before Sum sees it can be forced by Evaluate.

$\endgroup$
3
  • $\begingroup$ I didn't take a careful look at your code (I"m at work right now... a little bit short of time...), but I think it is important to put a constraint in the code (I don't know if it already has!) so that i[1] is smaller than imax[1], i[2] smaller than imax[2], etc... $\endgroup$
    – Rod
    Jun 14, 2013 at 23:44
  • $\begingroup$ @RodLm i[1] is the iteration variable. It has no value. Every nested sum runs from 0 to imax[n]. $\endgroup$
    – halirutan
    Jun 14, 2013 at 23:57
  • $\begingroup$ Oh, I see... +1 ! Initial iteration value is always zero! $\endgroup$
    – Rod
    Jun 15, 2013 at 0:13
0
$\begingroup$
k = 3;
Table[{x@i, 0, RandomInteger[{1, 5}]}, {i, k}] /.
  it_ :> {First /@ it, it} /.
 {{var__}, {it__}} :> Sum[f@var, it]
$\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.