6
$\begingroup$

I have the following:

matrix1 = {{a, b, c, d}, {e, f, g, h}, {i, j, k, l}, {m, n, o, p}}

(Note that it's the data that matters, not the fact it's defined as a matrix. Could be a table, could be a list.)

I want to create a cumulative sum, so that each entry is the sum of all data in that row up to and including column n, which is the column where the sum is to be placed. In other words, I want

matrix2 = {{a, a + b, a + b + c, a + b + c + d}, {e, e + f, e + f + g, e + f + g + h}, {i, i + j, i + j + k, i + j + k + l}, {m, m + n, 
m + n + o, m + n + o + p}}

I assume there must be a way to do this using Total[matrix1 ,{2}] combined with some way to specify the number of columns to sum - maybe Range...? Or should I be using Part and Span? If so, how?

Can anyone help with this? Thanks in advance.

$\endgroup$

5 Answers 5

5
$\begingroup$

I first came up with:

FoldList[Plus, #[[1]], Rest[#]] & /@ matrix

Then read the documentation for Accumulate, which says it is equivalent to:

Rest[FoldList[Plus, 0, #]] & /@ matrix1

One nice thing about these approaches is they generalize beyond sums:

FoldList[Times, #[[1]], Rest[#]] & /@ matrix1
Rest[FoldList[Times, 1, #]] & /@ matrix1
$\endgroup$
1
  • 1
    $\begingroup$ In more recent versions of Mathematica, FoldList[Times, #] & is equivalent to FoldList[Times, #[[1]], Rest[#]] &. (I forget exactly when they added that syntactic sugar.) $\endgroup$
    – Michael E2
    Commented Dec 22, 2020 at 23:55
6
$\begingroup$
Accumulate /@ matrix1

produces

{{a, a + b, a + b + c, a + b + c + d}, {e, e + f, e + f + g, 
  e + f + g + h}, {i, i + j, i + j + k, i + j + k + l}, {m, m + n, 
  m + n + o, m + n + o + p}}
$\endgroup$
6
$\begingroup$

Just for fun, another approach using matrix-matrix multiplication:

acc = matrix1.UpperTriangularize[ConstantArray[1, {1, 1} Dimensions[matrix1][[2]]]];
acc // MatrixForm

$\left( \begin{array}{cccc} a & a+b & a+b+c & a+b+c+d \\ e & e+f & e+f+g & e+f+g+h \\ i & i+j & i+j+k & i+j+k+l \\ m & m+n & m+n+o & m+n+o+p \\ \end{array} \right)$

As alternative to Accumulate[matrix1], you could use

acc = LowerTriangularize[ConstantArray[1, {1, 1} Dimensions[matrix1[[1]]]].matrix1;
acc // MatrixForm

$\left( \begin{array}{cccc} a & b & c & d \\ a+e & b+f & c+g & d+h \\ a+e+i & b+f+j & c+g+k & d+h+l \\ a+e+i+m & b+f+j+n & c+g+k+o & d+h+l+p \\ \end{array} \right)$

I would not advise to use these in practice as they have computational complexity $O(n^3)$ while the methods involving Accumulate have only complexity $O(n^2)$.

$\endgroup$
2
  • $\begingroup$ Dear @Richard, you can only mark a single answer as the answer to your question (although you can upvote as many as you like). In this case, I would recommend to mark kglr's post as answer as it is (i) more concise and (ii) more efficient than mine. $\endgroup$ Commented Aug 31, 2018 at 9:53
  • 3
    $\begingroup$ Clever. Accumulate is probably the standard way, but I do prefer/like Linear Algebra solutions. $\endgroup$ Commented Aug 31, 2018 at 12:43
2
$\begingroup$
mx = {{a, b, c, d}, {e, f, g, h}, {i, j, k, l}, {m, n, o, p}};

mx // TableForm

enter image description here

Using ArrayReduce (new in 12.2)

Accumulate rows

ArrayReduce[Accumulate, mx, 2] // TableForm

enter image description here

Accumulate columns

ArrayReduce[Accumulate, mx, 1] // TableForm

enter image description here

$\endgroup$
1
$\begingroup$
mx = {{a, b, c, d}, {e, f, g, h}, {i, j, k, l}, {m, n, o, p}};

mx2 = {{a, a + b, a + b + c, a + b + c + d}, {e, e + f, e + f + g, e + f + g + h}, 
      {i, i + j, i + j + k, i + j + k + l}, {m, m + n, m + n + o, m + n + o + p}};

A variation using FoldList:

FoldList[Apply[Plus]@*Flatten@*List, Nothing, #] & /@ mx === mx2

(*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.