2
$\begingroup$

Often I need to use same matrix several times and for that I save them in an external file. Converting the matrix into SparseArray can save a lot of space in this process.

For example consider this SparseArray.

spdat = Join[RandomInteger[{1, 10}, 2], {RandomReal[]}] & /@ Range[20];
spmat = SparseArray[(#[[1 ;; 2]] -> #[[3]]) & /@ spdat, {10, 10}]

Lets consider this spdat

{{9, 10, 0.11555}, {5, 8, 0.0436915}, {6, 2, 0.376473}, {7, 10, 0.893704}, {6, 3, 0.114267}, {2, 1, 0.860136}, {10, 7, 0.462883}, {5, 5, 0.126532}, {9, 8, 0.327185}, {10, 3, 0.36935}, {1, 8, 0.98363}, {3, 3, 0.864916}, {1, 1, 0.523974}, {1, 8, 0.752075}, {7, 1, 0.0122767}, {10, 4, 0.872767}, {4, 7, 0.555469}, {1, 4, 0.395135}, {7, 8, 0.842624}, {7, 4, 0.943731}}

If I can Export this as a data file, I can create my SparseArray from that. A simple Export will export the whole matrix in dense form which will create a huge file.

If I check the InputForm of spmat, it returns,

InputForm[spmat]

SparseArray[Automatic, {10, 10}, 0, {1, {{0, 3, 4, 5, 6, 8, 10, 14, 14, 16, 19}, {{1}, {4}, {8}, {1}, {3}, {7}, {5}, {8}, {2}, {3}, {1}, {4}, {8}, {10}, {8}, {10}, {3}, {4}, {7}}}, {0.5239738483968632, 0.3951345317083965, 0.9836297206953681, 0.8601364789360151, 0.8649158619094384, 0.5554690352192444, 0.12653163124345568, 0.04369153890486932, 0.3764726821240931, 0.11426712799092975, 0.012276677822715243, 0.9437312355928948, 0.8426237324241401, 0.8937036888680452, 0.32718527756860794, 0.11555023823345034, 0.36934965959862076, 0.872767483243448, 0.4628830528072616}}]

How can I retrieve spdat from this? Definitely the third argument contains the information about the position of nonzero elements, but I can't recognise them!

$\endgroup$
6
  • 6
    $\begingroup$ The easiest thing to do is probably to Export the sparse array as .m or .mx file, then you can simply Import it back without thinking what its pieces mean. The .mx file has an additional advantage that it will keep packed arrays packed. If you do want to understand the anatomy of sparse arrays, you can read e.g. this discussion. $\endgroup$ Commented Sep 11, 2015 at 13:37
  • 1
    $\begingroup$ @LeonidShifrin is almost certainly right, but if really want spdat back you can do something like MapThread[Append, {#["NonzeroPositions"], #["NonzeroValues"]}] &@spmat $\endgroup$
    – chuy
    Commented Sep 11, 2015 at 13:45
  • $\begingroup$ The only thing I'll add to @LeonidShifrin's comment is that while the .mx format is great, it is not portable across different OS's or across different versions of MMA. I use it all the time, but this is important to keep in mind. $\endgroup$
    – march
    Commented Sep 11, 2015 at 15:24
  • $\begingroup$ @march Since V10, .mx is portable across OS - but not architectures, and perhaps may not also be across different versions of Mathematica. $\endgroup$ Commented Sep 11, 2015 at 15:28
  • $\begingroup$ @LeonidShifrin. Apparently the documentation hasn't been updated, then! Both online and in my version of V10, the help files say that .mx was updated last at V6 and gives the caveats I gave above. $\endgroup$
    – march
    Commented Sep 11, 2015 at 15:58

3 Answers 3

2
$\begingroup$

Here are two different ways of getting spdat from spmat:

Join[#[[1]], {#[[2]]}] & /@ (ArrayRules[spmat])

or (this is chuy's suggestion)

MapThread[Append, {#["NonzeroPositions"], #["NonzeroValues"]}] &@spmat
$\endgroup$
4
$\begingroup$

Using Export directly "just works":

In[23]:= mat = SparseArray[DiagonalMatrix[2^Range[0, 10]]];

In[24]:= file = Export[CreateTemporary[], mat, "Package"];

In[25]:= FilePrint[file]

During evaluation of In[25]:=
(* Created with the Wolfram Language : www.wolfram.com *)
SparseArray[Automatic, {11, 11}, 0, 
 {1, {{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, {{1}, {2}, {3}, {4}, {5}, {6}, 
   {7}, {8}, {9}, {10}, {11}}}, {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 
  1024}}]

In[26]:= DeleteFile[file]
$\endgroup$
2
$\begingroup$

Your sample spdat generated from random numbers is of course likely to be just an example for this question, but nonetheless in the interest of thoroughness I would like to point that in the literal case you cannot be sure to recover your spdat from spmat, because your spdat may contain duplicate directives, only one of which is retained when you generate the SparseArray.

In the example spdat you post, for instance, there are two conflicting directives for position {1, 8} in the resulting matrix:

spdat = {{9, 10, 0.11555}, {5, 8, 0.0436915}, {6, 2, 0.376473}, {7, 10, 0.893704},
  {6, 3, 0.114267}, {2, 1, 0.860136}, {10, 7, 0.462883}, {5, 5, 0.126532},
  {9, 8, 0.327185}, {10, 3, 0.36935}, 

  {1, 8, 0.98363}, (*duplicated directive*)

  {3, 3, 0.864916}, {1, 1, 0.523974}, 

  {1, 8, 0.752075}, (*duplicated directive*)

  {7, 1, 0.0122767}, {10, 4, 0.872767}, {4, 7, 0.555469}, {1, 4, 0.395135},
  {7, 8, 0.842624}, {7, 4, 0.943731}}

Of course, the value corresponding to one of those two directives is lost in the generation of the SparseArray:

spmat = SparseArray[(#[[1 ;; 2]] -> #[[3]]) & /@ spdat, {10, 10}];
Join[#[[1]], {#[[2]]}] & /@ (ArrayRules[spmat]);

% == spdat
(*False*)

spmat[[1, 8]]
(* 0.98363, i.e. the first value encountered in your list of rules *)
$\endgroup$
2
  • $\begingroup$ Thanks @MarcoB. You are right. I just want to give an example. Right way to do that would be create the positions first with Union and then assign the values. I am just too lazy for that :) $\endgroup$
    – Sumit
    Commented Sep 12, 2015 at 12:06
  • $\begingroup$ @Sumit Hehe, yes of course it was just an example, but I just wanted the caveat on the record for future readers :-) $\endgroup$
    – MarcoB
    Commented Sep 12, 2015 at 15:30

Not the answer you're looking for? Browse other questions tagged or ask your own question.