5
$\begingroup$

I am interested in updating the values of the sparse matrix. I have a list of matrix element which I am interested in updating and a list of new values. Currently, I do it in the following manner:

s = SparseArray[{{i_, i_} -> i}, {100, 100}];
newP = RandomInteger[{1, 100}, {5, 2}];
newV = RandomReal[1, {5}];
MapThread[(s[[#1[[1]], #1[[2]]]] = #2) &, {newP, newV}]

Any suggestions on how to do it more efficiently?

$\endgroup$
  • $\begingroup$ In you actual use case: Are the new positions among the nonzero positions of the old array? $\endgroup$ – Henrik Schumacher Aug 1 '18 at 9:15
  • $\begingroup$ No, I am updating sub-set of nonzero values of the matrix $\endgroup$ – Kiril Danilchenko Aug 1 '18 at 9:21
  • 2
    $\begingroup$ Module[{nzp = Join[newP, s["NonzeroPositions"]], nzv = Join[newV, s["NonzeroValues"]]}, SparseArray[nzp->nzv, Dimensions[s]]] seems to be faster. $\endgroup$ – kglr Aug 1 '18 at 9:23
  • 1
    $\begingroup$ Related, but not duplicate: (777) – that question deals with element-by-element updates, whereas this question permits bulk replacement. $\endgroup$ – Mr.Wizard Aug 1 '18 at 10:27
7
$\begingroup$
s = SparseArray[{{i_, i_} -> i}, {10000, 10000}];

newP = RandomInteger[{1, 10000}, {4000, 2}];
newV = RandomReal[1, {4000}];

s1 = s;
MapThread[(s1[[#1[[1]], #1[[2]]]] = #2) &, {newP, newV}] // 
  RepeatedTiming // First

1.93

(s2 = With[{nzp = Join[newP, s["NonzeroPositions"]],
      nzv = Join[newV, s["NonzeroValues"]]}, 
     SparseArray[nzp -> nzv, Dimensions[s]]]) // 
  RepeatedTiming  // First

0.0019

(s4 = With[{mask = SparseArray[newP -> 1, Dimensions[s]], 
      ns = SparseArray[newP -> newV, Dimensions[s]]}, (1 - mask) s + 
      mask ns]) // RepeatedTiming // First

0.0012

s1 == s2 == s4

True

Versus Mr.Wizard's method:

RepeatedTiming[
    s3 = s +  SparseArray[newP -> newV - Extract[s, newP], Dimensions[s]];
  ] // First

0.0016

$\endgroup$
  • $\begingroup$ Interesting; s4 is significantly slower than the others on my system, timing 0.00270. A variation of that was the first thing I tried. $\endgroup$ – Mr.Wizard Aug 1 '18 at 11:17
  • $\begingroup$ @Mr.Wizard, please note that i had changed 5000 to 4000 to avoid memory limits of free cloud plan. The timings i posted are obtained in Wolfram Cloud (v11.3). $\endgroup$ – kglr Aug 1 '18 at 11:35
  • $\begingroup$ @Mr.Wizard, in version 9 s4 is slower than both s2 and s3. $\endgroup$ – kglr Aug 1 '18 at 11:42
2
$\begingroup$

Compared to kglr's answer this is marginally faster on my system (version 10.1), and a little simpler. It may be acceptable in many cases, however it will not work if you are trying to update Real to Integer values for example, because by way of numeric operations the Integers will be cast to Real.

s + SparseArray[newP -> newV - Extract[s, newP], Dimensions[s]]

Timings:

(* example code from kglr's answer *)

s = SparseArray[{{i_, i_} -> i}, {10000, 10000}];
newP = RandomInteger[{1, 10000}, {5000, 2}];
newV = RandomReal[1, {5000}];

(* his method again for comparative timing *)

(s2 = 
    Module[{nzp = Join[newP, s["NonzeroPositions"]], 
      nzv = Join[newV, s["NonzeroValues"]]}, 
     SparseArray[nzp -> nzv, Dimensions[s]]]) // RepeatedTiming // First

(* my method *)

RepeatedTiming[
  s3 = s + SparseArray[newP -> newV - Extract[s, newP], Dimensions[s]];
] // First

(* confirm equivalence *)

s2 == s3
0.00162

0.00145

True
$\endgroup$

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.