4

In the sparse matrix, we have a list of properties: specified elements, dimension, default, and density. I am interested in getting this data without calculating them again. For an example, the following sparse matrix has four specified elements.

s = SparseArray[{{1, 1} -> 1, {2, 2} -> 2, {3, 3} -> 3, {1, 3} -> 4}]

I can calculate the number of specified elements of s by

Length@s["NonzeroValues"]

but I look for an option to get this information from s properties

Kiril Danilchenko
  • 2,019
  • 1
  • 9
  • 18
  • 2
    From the previous question, you know all the properties available. The length of "NonzeroValues" is not available, but you can calculate it, as you just did. Why is Length@s["NonzeroValues"] not an acceptable solution? I'm afraid it is not clear what fundamentally is the question you are asking. – rhermans Jul 29 '18 at 11:25
  • 3
    I'm voting to close this question as off-topic because the OP already gave the optimal solution. – Henrik Schumacher Jul 29 '18 at 13:24
  • 1
    At least if s well-formatted (e.g., ifSparseArraySparseArraySortedQ[s] returns True), s["RowPointers"][[-1]] is a second possibility. But Length[s["NonzeroValues"]] is much safer. – Henrik Schumacher Jul 29 '18 at 13:28
  • 2
    Also Length won't compute anything. s["NonzeroValues"] is a basic constitutent of a sparse array. Within the internal data type for sparse arrays (MSparseSparseArray), s["NonzeroValues"] is stored as a dense array (MTensor). The length (and dimensions) of a dense array are also stored in each MTensor object, so Length just reads off a value of a field of the MTensor. – Henrik Schumacher Jul 29 '18 at 13:39
  • @HenrikSchumacher Shouldn't that be a clear sign that OP should self-answer and wait to see if a better answer comes along, rather than a close vote? – eyorble Jul 29 '18 at 21:05

2 Answers2

7

You want a convenient accessor for the nonzero value count, which seems reasonable. You could define your own function, but you'd like to get it from properties instead.

I think this is a good use case for adding your own definition to a system function, which is allowed by the language. You just need to unprotect the symbol first,

Unprotect[SparseArray];
(s_SparseArray)["NonzeroValueCount"] := Length[s["NonzeroValues"]];
Protect[SparseArray];

It can be accessed like any other property now,

s["NonzeroValueCount"]
(* 4 *)
Jason B.
  • 68,381
  • 3
  • 139
  • 286
2

As an alternative to what you have already considered there is the property "Density":

slen = #["Density"] Times @@ Dimensions[#] &;

SparseArray[{{1, 1} -> 1, {2, 2} -> 2, {3, 3} -> 3, {1, 3} -> 4}] // slen
4.
Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
  • 1
    That seems a very convoluted way around Length@#["NonzeroValues"]&. – rhermans Jul 29 '18 at 13:53
  • @rhermans Perhaps, but it is faster should that be important. I'll add an example. EDIT No, I'm wrong. I thought I'd looked at this before; it's not. Well there's egg on my face. :^) – Mr.Wizard Jul 29 '18 at 13:54
  • SparseArray\SparseArrayDimensions` for speed then. – rhermans Jul 29 '18 at 13:55
  • @rhermans I don't believe I've ever used that function before; let me try it. Thanks! – Mr.Wizard Jul 29 '18 at 13:56
  • @rhermans Still not as fast as the direct way. :-/ – Mr.Wizard Jul 29 '18 at 13:58
  • I'd be surprise if there were a faster way then Length@s["NonzeroValues"]... – Henrik Schumacher Jul 29 '18 at 14:07
  • 1
    @Henrik I saw your comment after posting and it makes perfect sense now. I think what I was remembering that nonzero-Positions is a nontrival operation and would take measurable time, and confused that with values. I rarely if ever use "NonzeroValues" but "NonzeroPositions" was a very common tool for me in v7 before Pick was optimized. – Mr.Wizard Jul 29 '18 at 14:10