Skip to content

Commit 1b01e98

Browse files
committed
Reorganize the parse documentation
1 parent b0fbf97 commit 1b01e98

File tree

2 files changed

+185
-190
lines changed

2 files changed

+185
-190
lines changed

doc/reference/tensor/sparse/index.rst

Lines changed: 185 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,193 @@
33
Sparse
44
======
55

6+
In general, *sparse* matrices provide the same functionality as regular
7+
matrices. The difference lies in the way the elements of *sparse* matrices are
8+
represented and stored in memory. Only the non-zero elements of the latter are stored.
9+
This has some potential advantages: first, this
10+
may obviously lead to reduced memory usage and, second, clever
11+
storage methods may lead to reduced computation time through the use of
12+
sparse specific algorithms. We usually refer to the generically stored matrices
13+
as *dense* matrices.
14+
15+
Aesara's sparse package provides efficient algorithms, but its use is not recommended
16+
in all cases or for all matrices. As an obvious example, consider the case where
17+
the *sparsity proportion* is very low. The *sparsity proportion* refers to the
18+
ratio of the number of zero elements to the number of all elements in a matrix.
19+
A low sparsity proportion may result in the use of more space in memory
20+
since not only the actual data is stored, but also the position of nearly every
21+
element of the matrix. This would also require more computation
22+
time whereas a dense matrix representation along with regular optimized algorithms might do a
23+
better job. Other examples may be found at the nexus of the specific purpose and structure
24+
of the matrices. More documentation may be found in the
25+
`SciPy Sparse Reference <http://docs.scipy.org/doc/scipy/reference/sparse.html>`_.
26+
27+
Since sparse matrices are not stored in contiguous arrays, there are several
28+
ways to represent them in memory. This is usually designated by the so-called ``format``
29+
of the matrix. Since Aesara's sparse matrix package is based on the SciPy
30+
sparse package, complete information about sparse matrices can be found
31+
in the SciPy documentation. Like SciPy, Aesara does not implement sparse formats for
32+
arrays with a number of dimensions different from two.
33+
34+
So far, Aesara implements two ``formats`` of sparse matrix: ``csc`` and ``csr``.
35+
Those are almost identical except that ``csc`` is based on the *columns* of the
36+
matrix and ``csr`` is based on its *rows*. They both have the same purpose:
37+
to provide for the use of efficient algorithms performing linear algebra operations.
38+
A disadvantage is that they fail to give an efficient way to modify the sparsity structure
39+
of the underlying matrix, i.e. adding new elements. This means that if you are
40+
planning to add new elements in a sparse matrix very often in your computational graph,
41+
perhaps a tensor variable could be a better choice.
42+
43+
More documentation may be found in the :ref:`Sparse Library Reference <libdoc_sparse>`.
44+
45+
Before going further, here are the ``import`` statements that are assumed for the rest of the
46+
tutorial:
47+
48+
>>> import aesara
49+
>>> import numpy as np
50+
>>> import scipy.sparse as sp
51+
>>> from aesara import sparse
52+
53+
Compressed Sparse Format
54+
------------------------
55+
56+
.. Changes to this section should also result in changes to library/sparse/index.txt.
57+
58+
Aesara supports two *compressed sparse formats*: ``csc`` and ``csr``, respectively based on columns
59+
and rows. They have both the same attributes: ``data``, ``indices``, ``indptr`` and ``shape``.
60+
61+
* The ``data`` attribute is a one-dimensional ``ndarray`` which contains all the non-zero
62+
elements of the sparse matrix.
63+
64+
* The ``indices`` and ``indptr`` attributes are used to store the position of the data in the
65+
sparse matrix.
66+
67+
* The ``shape`` attribute is exactly the same as the ``shape`` attribute of a dense (i.e. generic)
68+
matrix. It can be explicitly specified at the creation of a sparse matrix if it cannot be inferred
69+
from the first three attributes.
70+
71+
Which format should I use?
72+
~~~~~~~~~~~~~~~~~~~~~~~~~~
73+
74+
At the end, the format does not affect the length of the ``data`` and ``indices`` attributes. They are both
75+
completely fixed by the number of elements you want to store. The only thing that changes with the format
76+
is ``indptr``. In ``csc`` format, the matrix is compressed along columns so a lower number of columns will
77+
result in less memory use. On the other hand, with the ``csr`` format, the matrix is compressed along
78+
the rows and with a matrix that have a lower number of rows, ``csr`` format is a better choice. So here is the rule:
79+
80+
.. note::
81+
82+
If shape[0] > shape[1], use ``csc`` format. Otherwise, use ``csr``.
83+
84+
Sometimes, since the sparse module is young, ops does not exist for both format. So here is
85+
what may be the most relevant rule:
86+
87+
.. note::
88+
89+
Use the format compatible with the ops in your computation graph.
90+
91+
The documentation about the ops and their supported format may be found in
92+
the :ref:`Sparse Library Reference <libdoc_sparse>`.
93+
94+
Handling Sparse in Aesara
95+
-------------------------
96+
97+
Most of the ops in Aesara depend on the ``format`` of the sparse matrix.
98+
That is why there are two kinds of constructors of sparse variables:
99+
``csc_matrix`` and ``csr_matrix``. These can be called with the usual
100+
``name`` and ``dtype`` parameters, but no ``broadcastable`` flags are
101+
allowed. This is forbidden since the sparse package, as the SciPy sparse module,
102+
does not provide any way to handle a number of dimensions different from two.
103+
The set of all accepted ``dtype`` for the sparse matrices can be found in
104+
``sparse.all_dtypes``.
105+
106+
>>> sparse.all_dtypes # doctest: +SKIP
107+
set(['int8', 'int16', 'int32', 'int64', 'uint8', 'uint16', 'uint32', 'uint64',
108+
'float32', 'float64', 'complex64', 'complex128'])
109+
110+
To and Fro
111+
~~~~~~~~~~
112+
113+
To move back and forth from a dense matrix to a sparse matrix representation, Aesara
114+
provides the ``dense_from_sparse``, ``csr_from_dense`` and
115+
``csc_from_dense`` functions. No additional detail must be provided. Here is
116+
an example that performs a full cycle from sparse to sparse:
117+
118+
>>> x = sparse.csc_matrix(name='x', dtype='float32')
119+
>>> y = sparse.dense_from_sparse(x)
120+
>>> z = sparse.csc_from_dense(y)
121+
122+
Properties and Construction
123+
~~~~~~~~~~~~~~~~~~~~~~~~~~~
124+
125+
Although sparse variables do not allow direct access to their properties,
126+
this can be accomplished using the ``csm_properties`` function. This will return
127+
a tuple of one-dimensional ``tensor`` variables that represents the internal characteristics
128+
of the sparse matrix.
129+
130+
In order to reconstruct a sparse matrix from some properties, the functions ``CSC``
131+
and ``CSR`` can be used. This will create the sparse matrix in the desired
132+
format. As an example, the following code reconstructs a ``csc`` matrix into
133+
a ``csr`` one.
134+
135+
>>> x = sparse.csc_matrix(name='x', dtype='int64')
136+
>>> data, indices, indptr, shape = sparse.csm_properties(x)
137+
>>> y = sparse.CSR(data, indices, indptr, shape)
138+
>>> f = aesara.function([x], y)
139+
>>> a = sp.csc_matrix(np.asarray([[0, 1, 1], [0, 0, 0], [1, 0, 0]]))
140+
>>> print(a.toarray())
141+
[[0 1 1]
142+
[0 0 0]
143+
[1 0 0]]
144+
>>> print(f(a).toarray())
145+
[[0 0 1]
146+
[1 0 0]
147+
[1 0 0]]
148+
149+
The last example shows that one format can be obtained from transposition of
150+
the other. Indeed, when calling the ``transpose`` function,
151+
the sparse characteristics of the resulting matrix cannot be the same as the one
152+
provided as input.
153+
154+
Structured Operation
155+
~~~~~~~~~~~~~~~~~~~~
156+
157+
Several ops are set to make use of the very peculiar structure of the sparse
158+
matrices. These ops are said to be *structured* and simply do not perform any
159+
computations on the zero elements of the sparse matrix. They can be thought as being
160+
applied only to the data attribute of the latter. Note that these structured ops
161+
provide a structured gradient. More explication below.
162+
163+
>>> x = sparse.csc_matrix(name='x', dtype='float32')
164+
>>> y = sparse.structured_add(x, 2)
165+
>>> f = aesara.function([x], y)
166+
>>> a = sp.csc_matrix(np.asarray([[0, 0, -1], [0, -2, 1], [3, 0, 0]], dtype='float32'))
167+
>>> print(a.toarray())
168+
[[ 0. 0. -1.]
169+
[ 0. -2. 1.]
170+
[ 3. 0. 0.]]
171+
>>> print(f(a).toarray())
172+
[[ 0. 0. 1.]
173+
[ 0. 0. 3.]
174+
[ 5. 0. 0.]]
175+
176+
.. _tutsparse_gradient:
177+
178+
Gradient
179+
~~~~~~~~
180+
181+
The gradients of the ops in the sparse module can also be structured. Some ops provide
182+
a *flag* to indicate if the gradient is to be structured or not. The documentation can
183+
be used to determine if the gradient of an op is regular or structured or if its
184+
implementation can be modified. Similarly to structured ops, when a structured gradient is calculated, the
185+
computation is done only for the non-zero elements of the sparse matrix.
186+
187+
More documentation regarding the gradients of specific ops can be found in the
188+
:ref:`Sparse Library Reference <libdoc_sparse>`.
189+
190+
6191
.. toctree::
7192
:maxdepth: 1
8193

9-
sparse
10194
sparse_api
11195
sandbox

doc/reference/tensor/sparse/sparse.rst

Lines changed: 0 additions & 189 deletions
This file was deleted.

0 commit comments

Comments
 (0)