Is there a "Mathematica Way", like Map or Apply to compute the following double sum?

$\sum_{i=1}^{N_1}\sum_{j=1}^{N_2} m_i n_j \, f(\tau_{i} \gamma_{j})$

I have already stored the lists $m,n,\tau,\gamma$.

$m$ and $\tau$ are of length $N_1$ and $n$ and $\gamma$ of length $N_2$. So my approach was to use something like

Outer[f, τ, γ]

for the function map, and then

Total[Total[Outer[f, τ, γ]]]

but how do Ι multiply mand n into the sum?

EDIT: Undo Edit, figured out the bug in my code

  • $\begingroup$ I guess the time to beat is Sum[m[[i]] n[[j]] f[tau[[i]], gamma[[j]]], {i, 1, n1}, {j, 1, n2}] $\endgroup$ – ssch Feb 5 '13 at 16:34
  • $\begingroup$ If f is simple enough then Compile will likely give the best possible performance. But it's not "Mathematica-like". $\endgroup$ – Szabolcs Feb 5 '13 at 16:41
  • $\begingroup$ You could likewise do an Outer[Times,m,n] and then Dot that with your first Outer result. I don't know how that will be speedwise though. $\endgroup$ – Daniel Lichtblau Feb 5 '13 at 16:45
  • $\begingroup$ Does Table/ParallelTable count as Mathematica-like? $\endgroup$ – RunnyKine Feb 5 '13 at 16:50
  • 1
    $\begingroup$ Actually I missed the need for Flatten. This variant works. AbsoluteTiming[Flatten[Outer[Times, m, n]].Flatten[ Outer[f, t, gamma]]] $\endgroup$ – Daniel Lichtblau Feb 5 '13 at 20:36

If your elements are in lists the fastest way is to use array operations. In the present case of an outer product one index, let's say "i", will not be expanded, on the other you want to thread.

To operate on a list the function needs the attribute Listable. The Times function, as many other internal ones, is already listable, that is

Times[{1,2,3},x] = {x, 2x, 3x}

You want to do the same with your function "f", e.g.

SetAttributes[f, Listable]

f[{1,2,3},x] = {f[1, x], f[2, x], f[3, x]}

For the threading part you can use MapThread to "slide" through the list, e.g.

MapThread[#1 f[#2] &, {{a,b,c},{1,2,3}}] = {a f[1], b f[2], c f[3]}

Finally your code will look like this

SetAttributes[f, Listable]
f[x_, y_] := x y
{m, n, t, g} = RandomReal[1, {4, 1000}];

Total@Total@MapThread[m #1 f[t #2] &, {n, g}]

A note about speed: usually threaded operation are much faster than element ones

Total@Total@MapThread[m #1 f[t, #2] &, {n, g}] // AbsoluteTiming
Total@Total[Outer[Times, m, n] Outer[f[#1, #2] &, t, g]] // AbsoluteTiming
Sum[m[[i]] n[[j]] f[t[[i]], g[[j]]], {i, 1, 1000}, {j, 1, 1000}] // AbsoluteTiming
ParallelSum[m[[i]] n[[j]] f[t[[i]], g[[j]]], {i, 1, 1000}, {j, 1, 1000}] // AbsoluteTiming

Out[27]= {0.797645, 62806.3}

Out[28]= {1.554886, 62806.3}

Out[29]= {2.933898, 62806.3}

Out[30]= {0.828527, 62806.3}

Thus always try to use them when possible.

| improve this answer | |
  • $\begingroup$ I think it should be Total@Total@MapThread[m #1 f[t, #2] &, {n, g}], otherwise it didn't work for me $\endgroup$ – rainer Feb 6 '13 at 11:33
  • 1
    $\begingroup$ You are aware of the second argument of Total[], I presume? Total[(* stuff *), 2] works nicely in particular... $\endgroup$ – J. M.'s discontentment Feb 7 '13 at 3:29

How about using Table or ParallelTable like this:

Total[ParallelTable[m[[i]] n[[j]] f[τ[[i]] γ[[j]]], {i, 1, N1}, {j, 1, N2}]]
| improve this answer | |

You almost had it.You were right to use Outer[]; what you missed was to interpret the sum as an appropriate matrix multiplication. Observe:

Table[Subscript[m, i], {i, 5}].Outer[f, Table[Subscript[τ, i], {i, 5}],
                                        Table[Subscript[γ, j], {j, 4}]].
                               Table[Subscript[n, j], {j, 4}] == 
Sum[f[Subscript[τ, i], Subscript[γ, j]] Subscript[m, i] Subscript[n, j],
    {i, 5}, {j, 4}] // FullSimplify

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.