4
$\begingroup$

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

$\endgroup$
  • 2
    $\begingroup$ 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. $\endgroup$ – rhermans Jul 29 '18 at 11:25
  • 3
    $\begingroup$ I'm voting to close this question as off-topic because the OP already gave the optimal solution. $\endgroup$ – Henrik Schumacher Jul 29 '18 at 13:24
  • 1
    $\begingroup$ At least if s well-formatted (e.g., if SparseArraySparseArraySortedQ[s] returns True), s["RowPointers"][[-1]] is a second possibility. But Length[s["NonzeroValues"]] is much safer. $\endgroup$ – Henrik Schumacher Jul 29 '18 at 13:28
  • 2
    $\begingroup$ 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. $\endgroup$ – Henrik Schumacher Jul 29 '18 at 13:39
  • $\begingroup$ @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? $\endgroup$ – eyorble Jul 29 '18 at 21:05
7
$\begingroup$

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 *)
$\endgroup$
2
$\begingroup$

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.
$\endgroup$
  • 1
    $\begingroup$ That seems a very convoluted way around Length@#["NonzeroValues"]&. $\endgroup$ – rhermans Jul 29 '18 at 13:53
  • $\begingroup$ @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. :^) $\endgroup$ – Mr.Wizard Jul 29 '18 at 13:54
  • $\begingroup$ SparseArray`SparseArrayDimensions for speed then. $\endgroup$ – rhermans Jul 29 '18 at 13:55
  • $\begingroup$ @rhermans I don't believe I've ever used that function before; let me try it. Thanks! $\endgroup$ – Mr.Wizard Jul 29 '18 at 13:56
  • 1
    $\begingroup$ @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. $\endgroup$ – Mr.Wizard Jul 29 '18 at 14:10

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.