pyspla

Python wrapper for spla library

Cross-platform generalized sparse linear algebra framework for efficient mathematical computations over sparse matrices and vectors with vendor-agnostic GPUs acceleration to speed-up processing of large and complex data. Library underling core witten using C++ with optional C-compatible interface.

Links:

We are welcome for contributions. Join project development on GitHub!

Installation

Install the release version of the package from PyPI repository for Windows, Linux and MacOS:

$ pip install pyspla

Install the latest test version of the package from Test PyPI repository for Windows, Linux and MacOS:

$ pip install -i https://test.pypi.org/simple/ pyspla

Delete package if no more required:

$ pip uninstall pyspla

Summary

Generalized sparse liner algebra python package with GPUs accelerated computations. Library provides a set of linear algebra primitives such as matrix, vector and scalar for mathematical computations parametrized using one of built-in type. It allows to define sequence of execution tasks using schedule API. Desired behavior of math operations can be customized using pre-defined or custom user-defined element operations in op module.

Library optionally uses GPUs acceleration through OpenCL or CUDA API. It automatically attempts to initialize accelerator and trys to use it to speed-up some operations. All GPU communication, data transformations and transfers done internally automatically without any efforts from user perspective.

Example of usage

This example demonstrates basic library primitives usage and shows how to implement simple breadth-first search algorithm using spla primitives in a few lines of code and run it on your GPU using OpenCL backend for acceleration.

Import spla package to your python script.

>>> from pyspla import *

Create an adjacency matrix of graph using lists of row-column indices and values.

>>> I = [0, 1, 2, 2, 3]
>>> J = [1, 2, 0, 3, 2]
>>> V = [1, 1, 1, 1, 1]
>>> A = Matrix.from_lists(I, J, V, shape=(4, 4), dtype=INT)
>>> print(A)
'
    0 1 2 3
 0| . 1 . .|  0
 1| . . 1 .|  1
 2| 1 . . 1|  2
 3| . . 1 .|  3
    0 1 2 3
'

The following function implements single-source breadth-first search algoritm through masked matrix-vector product. The algorithm accepts starting vertex and an adjacency matrix of a graph. It traverces graph using vxm and assigns depths to reached vertices. Mask is used to update only unvisited vertices reducing number of required computations.

>>> def bfs(s: int, A: Matrix):
>>>     v = Vector(A.n_rows, INT)  # to store depths
>>>
>>>     front = Vector.from_lists([s], [1], A.n_rows, INT)  # front of new vertices to study
>>>     front_size = 1              # current front size
>>>     depth = Scalar(INT, 0)      # depth of search
>>>     count = 0                   # num of reached vertices
>>>
>>>     while front_size > 0:       # while have something to study
>>>         depth += 1
>>>         count += front_size
>>>         v.assign(front, depth, op_assign=INT.SECOND, op_select=INT.NQZERO)              # assign depths
>>>         front = front.vxm(v, A, op_mult=INT.LAND, op_add=INT.LOR, op_select=INT.EQZERO) # do traversal
>>>         front_size = front.reduce(op_reduce=INT.PLUS).get()                             # update front count to end algorithm
>>>
>>>     return v, count, depth.get()

Run bfs algorithm starting from 0-vertex with the graph adjacency matrix created earlier. None, that spla will automatically select GPU-based acceleration backed for computations.

>>> v, c, d = bfs(0, A)

Output the result vector with distances of reached vertices.

>>> print(v)
'
 0| 1
 1| 2
 2| 3
 3| 4
'

Total number of reached vertices.

>>> print(c)
'
 4
'

Maximum depth of a discovered vertex.

>>> print(d)
'
 4
'

Performance

Spla shows greate performance comparing to Nvidia CUDA based optimized GraphBLAST library, processing large graphs in extreme cases counting 1 BILLION edges with speed and without memory issues. Also, spla shows outstanding performance in Page-Rank algorithms, outperforming low-level Nvidia CUDA highly-optimized Gunrock library. Spla shows scalability on GPUs on Intel, Nvidia and AMD with acceptable performance. Spla can be run even on integrated GPUs. Here you can get good speedup, what is much faster than scipy or networkx.

More details with performance study given down bellow.

Comparison on a Nvidia GPU

stats Description: Relative speedup of GraphBLAST, Gunrock and Spla compared to a LaGraph (SuiteSparse) used a baseline. Logarithmic scale is used.

Configuration: Ubuntu 20.04, 3.40Hz Intel Core i7-6700 4-core CPU, DDR4 64Gb RAM, Nvidia GeForce GTX 1070 dedicated GPU with 8Gb on-board VRAM.

Scalability on Intel, Amd and Nvidia GPUs

stats Description: Throughput of Spla library shown as a number of processed edges/s per single GPU core. Logarithmic scale is used.

Configuration: Nvidia GeForce GTX 1070 dedicated GPU with 8Gb on-board VRAM, Intel Arc A770 flux dedicated GPU with 8GB on-board VRAM and or AMD Radeon Vega Frontier Edition dedicated GPU with 16GB on-board VRAM.

Comparison running on integrated Intel and Amd GPUs

stats Description: Relative speedup of Spla compared to a LaGraph (SuiteSparse) used a baseline running on a single CPU device with integrated GPU.

Configuration: Ubuntu 20.04, 3.40Hz Intel Core i7-6700 4-core CPU, DDR4 64Gb RAM, Intel HD Graphics 530 integrated GPU and Ubuntu 22.04, 4.70Hz AMD Ryzen 9 7900x 12-core CPU, DDR4 128 GB RAM, AMD GFX1036 integrated GPU.

Dataset

Name Vertices Edges Avg Deg Sd Deg Max Deg Link
coAuthorsCiteseer 227.3K 1.6M 7.2 10.6 1372.0 link
coPapersDBLP 540.5K 30.5M 56.4 66.2 3299.0 link
amazon-2008 735.3K 7.0M 9.6 7.6 1077.0 link
hollywood-2009 1.1M 112.8M 98.9 271.9 11467.0 link
belgium_osm 1.4M 3.1M 2.2 0.5 10.0 link
roadNet-CA 2.0M 5.5M 2.8 1.0 12.0 link
com-Orkut 3.1M 234.4M 76.3 154.8 33313.0 link
cit-Patents 3.8M 33.0M 8.8 10.5 793.0 link
rgg_n_2_22_s0 4.2M 60.7M 14.5 3.8 36.0 link
soc-LiveJournal 4.8M 85.7M 17.7 52.0 20333.0 link
indochina-2004 7.4M 302.0M 40.7 329.6 256425.0 link
rgg_n_2_23_s0 8.4M 127.0M 15.1 3.9 40.0 link
road_central 14.1M 33.9M 2.4 0.9 8.0 link

Containers

Library provides fundamental generalized linear algebra containers for data storage and mathematical computations. These containers are generalized, so any of built-in types may be used to parametrize type of data. Containers have sparse formats by default, so it is possible to create large-dimension but low data containers. Containers are storage-invariant, so the best format for the storage is automatically managed by container internally. All required format conversion done in the context of particular primitive usage.

Types

Library provides a set of standard and common built-in data types. Library value types differ a bit from a classic type definition. In spla library type is essentially is a storage characteristic, which defines count and layout of bytes per element. User can interpret stored data as her/she wants. Spla types set is limited due to the nature of GPUs accelerations, where arbitrary layout of data causes significant performance penalties. Types such as int float uint bool are supported. More types can be added on demand.

Ops

Library provides a set of unary, binary and select ops for values data manipulation inside matrix and vector containers. Unary operations commonly used for apply and transformation operations, binary operations used for reductions and products, select operations used for filtration and mask application.

Math operations

Library provides a set of high-level linera algebra operations over matrices and vectors with parametrization by binary, unary and select ops. There is avalable implementations for general mxm matrix-matrix, masked mxmT matrix-matrix, masked mxv matrix-vector, masked vxm vector-matrix products, matrix and vector reductions, assignment, matrix and vector element-wise eadd and emult oprations, and so on. Most operations have both CPU and GPU implementation. Thus, you will have GPU performance in computations out of the box.

Details

Spla C/C++ backend compiled library is automatically loaded and initialized on package import. State of the library managed by internal bridge module. All resources are unloaded automatically on package exit. Library state finalized automatically.

  1"""
  2Python wrapper for spla library
  3===============================
  4
  5Cross-platform generalized sparse linear algebra framework for efficient mathematical
  6computations over sparse matrices and vectors with vendor-agnostic GPUs
  7acceleration to speed-up processing of large and complex data.
  8Library underling core witten using C++ with optional C-compatible interface.
  9
 10Links:
 11
 12- **Package page**:
 13  [https://pypi.org/project/pyspla](https://pypi.org/project/pyspla/)
 14- **Package page (test)**:
 15  [https://test.pypi.org/project/pyspla](https://test.pypi.org/project/pyspla/)
 16- **Source code**:
 17  [https://github.com/SparseLinearAlgebra/spla](https://github.com/SparseLinearAlgebra/spla)
 18- **Contributing**:
 19  [https://github.com/SparseLinearAlgebra/spla/CONTRIBUTING.md](https://github.com/SparseLinearAlgebra/spla/blob/main/CONTRIBUTING.md)
 20- **Development**:
 21  [https://github.com/SparseLinearAlgebra/spla/DEVELOPMENT.md](https://github.com/SparseLinearAlgebra/spla/blob/main/DEVELOPMENT.md)
 22- **Examples**:
 23  [https://github.com/SparseLinearAlgebra/spla/EXAMPLES.md](https://github.com/SparseLinearAlgebra/spla/blob/main/EXAMPLES.md)
 24- **C/C++ API Reference**:
 25  [https://SparseLinearAlgebra.github.io/spla/docs-cpp](https://SparseLinearAlgebra.github.io/spla/docs-cpp/)
 26- **Bug report**:
 27  [https://github.com/SparseLinearAlgebra/spla/issues](https://github.com/SparseLinearAlgebra/spla/issues)
 28
 29We are welcome for contributions. Join project development on [GitHub](https://github.com/SparseLinearAlgebra/spla)!
 30
 31Installation
 32------------
 33
 34Install the release version of the package from **PyPI** repository for Windows, Linux and MacOS:
 35
 36    $ pip install pyspla
 37
 38Install the latest test version of the package from **Test PyPI** repository for Windows, Linux and MacOS:
 39
 40    $ pip install -i https://test.pypi.org/simple/ pyspla
 41
 42Delete package if no more required:
 43
 44    $ pip uninstall pyspla
 45
 46Summary
 47-------
 48
 49Generalized sparse liner algebra python package with GPUs accelerated computations. Library provides a set of
 50linear algebra primitives such as `matrix`, `vector` and `scalar` for mathematical computations parametrized
 51using one of built-in `type`. It allows to define sequence of execution tasks using `schedule` API. Desired
 52behavior of math operations can be customized using pre-defined or custom user-defined element operations in `op`
 53module.
 54
 55Library optionally uses GPUs acceleration through OpenCL or CUDA API.
 56It automatically attempts to initialize accelerator and trys to use
 57it to speed-up some operations. All GPU communication, data transformations
 58and transfers done internally automatically without any efforts from user perspective.
 59
 60Example of usage
 61----------------
 62
 63This example demonstrates basic library primitives usage and shows how to implement simple breadth-first search
 64algorithm using `spla` primitives in a few lines of code and run it on your GPU using OpenCL backend for acceleration.
 65
 66Import `spla` package to your python script.
 67>>> from pyspla import *
 68
 69Create an adjacency matrix of graph using lists of row-column indices and values.
 70>>> I = [0, 1, 2, 2, 3]
 71>>> J = [1, 2, 0, 3, 2]
 72>>> V = [1, 1, 1, 1, 1]
 73>>> A = Matrix.from_lists(I, J, V, shape=(4, 4), dtype=INT)
 74>>> print(A)
 75'
 76    0 1 2 3
 77 0| . 1 . .|  0
 78 1| . . 1 .|  1
 79 2| 1 . . 1|  2
 80 3| . . 1 .|  3
 81    0 1 2 3
 82'
 83
 84The following function implements single-source breadth-first search algoritm through masked matrix-vector product.
 85The algorithm accepts starting vertex and an adjacency matrix of a graph. It traverces graph using `vxm` and assigns
 86depths to reached vertices. Mask is used to update only unvisited vertices reducing number of required computations.
 87>>> def bfs(s: int, A: Matrix):
 88>>>     v = Vector(A.n_rows, INT)  # to store depths
 89>>>
 90>>>     front = Vector.from_lists([s], [1], A.n_rows, INT)  # front of new vertices to study
 91>>>     front_size = 1              # current front size
 92>>>     depth = Scalar(INT, 0)      # depth of search
 93>>>     count = 0                   # num of reached vertices
 94>>>
 95>>>     while front_size > 0:       # while have something to study
 96>>>         depth += 1
 97>>>         count += front_size
 98>>>         v.assign(front, depth, op_assign=INT.SECOND, op_select=INT.NQZERO)              # assign depths
 99>>>         front = front.vxm(v, A, op_mult=INT.LAND, op_add=INT.LOR, op_select=INT.EQZERO) # do traversal
100>>>         front_size = front.reduce(op_reduce=INT.PLUS).get()                             # update front count to end algorithm
101>>>
102>>>     return v, count, depth.get()
103
104Run bfs algorithm starting from 0-vertex with the graph adjacency matrix created earlier. None, that `spla` will
105automatically select GPU-based acceleration backed for computations.
106>>> v, c, d = bfs(0, A)
107
108Output the result vector with distances of reached vertices.
109>>> print(v)
110'
111 0| 1
112 1| 2
113 2| 3
114 3| 4
115'
116
117Total number of reached vertices.
118>>> print(c)
119'
120 4
121'
122
123Maximum depth of a discovered vertex.
124>>> print(d)
125'
126 4
127'
128
129Performance
130-----------
131
132Spla shows greate performance comparing to Nvidia CUDA based optimized GraphBLAST library, processing large graphs
133in extreme cases counting 1 BILLION edges with speed and without memory issues. Also, spla shows outstanding performance
134in Page-Rank algorithms, outperforming low-level Nvidia CUDA highly-optimized Gunrock library. Spla shows scalability
135on GPUs on Intel, Nvidia and AMD with acceptable performance. Spla can be run even on integrated GPUs. Here you can
136get good speedup, what is much faster than `scipy` or `networkx`.
137
138More details with performance study given down bellow.
139
140**Comparison on a Nvidia GPU**
141
142![stats](../../docs/stats/rq1_rel_compact.png)
143Description: Relative speedup of GraphBLAST, Gunrock and Spla compared to a LaGraph (SuiteSparse) used a baseline. Logarithmic scale is used.
144
145> **Configuration**: Ubuntu 20.04, 3.40Hz Intel Core i7-6700 4-core CPU, DDR4 64Gb RAM, Nvidia GeForce GTX 1070
146> dedicated GPU with 8Gb on-board VRAM.
147
148**Scalability on Intel, Amd and Nvidia GPUs**
149
150![stats](../../docs/stats/rq2_cores_compact.png)
151Description: Throughput of Spla library shown as a number of processed edges/s per single GPU core. Logarithmic scale is used.
152
153> **Configuration**: Nvidia GeForce GTX 1070 dedicated GPU with 8Gb on-board VRAM, Intel Arc A770 flux dedicated GPU
154> with 8GB on-board VRAM and or AMD Radeon Vega Frontier Edition dedicated GPU with 16GB on-board VRAM.
155
156**Comparison running on integrated Intel and Amd GPUs**
157
158![stats](../../docs/stats/rq3_int_compact.png)
159Description: Relative speedup of Spla compared to a LaGraph (SuiteSparse) used a baseline running on a single CPU device with integrated GPU.
160
161> **Configuration**: Ubuntu 20.04, 3.40Hz Intel Core i7-6700 4-core CPU, DDR4 64Gb RAM, Intel HD Graphics 530 integrated
162> GPU and Ubuntu 22.04, 4.70Hz AMD Ryzen 9 7900x 12-core CPU, DDR4 128 GB RAM, AMD GFX1036 integrated GPU.
163
164**Dataset**
165
166| Name              | Vertices |   Edges | Avg Deg | Sd Deg |   Max Deg |                                                                                              Link |
167|:------------------|---------:|--------:|--------:|-------:|----------:|--------------------------------------------------------------------------------------------------:|
168| coAuthorsCiteseer |   227.3K |    1.6M |     7.2 |   10.6 |    1372.0 | [link](https://suitesparse-collection-website.herokuapp.com/MM/DIMACS10/coAuthorsCiteseer.tar.gz) |
169| coPapersDBLP      |   540.5K |   30.5M |    56.4 |   66.2 |    3299.0 |      [link](https://suitesparse-collection-website.herokuapp.com/MM/DIMACS10/coPapersDBLP.tar.gz) |
170| amazon-2008       |   735.3K |    7.0M |     9.6 |    7.6 |    1077.0 |                                                    [link](http://sparse.tamu.edu/LAW/amazon-2008) |
171| hollywood-2009    |     1.1M |  112.8M |    98.9 |  271.9 |   11467.0 |         [link](https://suitesparse-collection-website.herokuapp.com/MM/LAW/hollywood-2009.tar.gz) |
172| belgium_osm       |     1.4M |    3.1M |     2.2 |    0.5 |      10.0 |                                               [link](http://sparse.tamu.edu/DIMACS10/belgium_osm) |
173| roadNet-CA        |     2.0M |    5.5M |     2.8 |    1.0 |      12.0 |            [link](https://suitesparse-collection-website.herokuapp.com/MM/SNAP/roadNet-CA.tar.gz) |
174| com-Orkut         |     3.1M |  234.4M |    76.3 |  154.8 |   33313.0 |             [link](https://suitesparse-collection-website.herokuapp.com/MM/SNAP/com-Orkut.tar.gz) |
175| cit-Patents       |     3.8M |   33.0M |     8.8 |   10.5 |     793.0 |           [link](https://suitesparse-collection-website.herokuapp.com/MM/SNAP/cit-Patents.tar.gz) |
176| rgg_n_2_22_s0     |     4.2M |   60.7M |    14.5 |    3.8 |      36.0 |     [link](https://suitesparse-collection-website.herokuapp.com/MM/DIMACS10/rgg_n_2_22_s0.tar.gz) |
177| soc-LiveJournal   |     4.8M |   85.7M |    17.7 |   52.0 |   20333.0 |      [link](https://suitesparse-collection-website.herokuapp.com/MM/SNAP/soc-LiveJournal1.tar.gz) |
178| indochina-2004    |     7.4M |  302.0M |    40.7 |  329.6 |  256425.0 |         [link](https://suitesparse-collection-website.herokuapp.com/MM/LAW/indochina-2004.tar.gz) |
179| rgg_n_2_23_s0     |     8.4M |  127.0M |    15.1 |    3.9 |      40.0 |     [link](https://suitesparse-collection-website.herokuapp.com/MM/DIMACS10/rgg_n_2_23_s0.tar.gz) |
180| road_central      |    14.1M |   33.9M |     2.4 |    0.9 |       8.0 |                                              [link](http://sparse.tamu.edu/DIMACS10/road_central) |
181
182Containers
183----------
184
185Library provides fundamental generalized linear algebra containers for data storage and mathematical computations.
186These containers are generalized, so any of built-in types may be used to parametrize type of data. Containers
187have sparse formats by default, so it is possible to create large-dimension but low data containers. Containers
188are storage-invariant, so the best format for the storage is automatically managed by container internally.
189All required format conversion done in the context of particular primitive usage.
190
191Types
192-----
193
194Library provides a set of standard and common built-in data types. Library value types
195differ a bit from a classic type definition. In `spla` library type is essentially is a
196storage characteristic, which defines count and layout of bytes per element. User
197can interpret stored data as her/she wants. Spla types set is limited due to the nature
198of GPUs accelerations, where arbitrary layout of data causes significant performance penalties.
199Types such as `int` `float` `uint` `bool` are supported. More types can be added on demand.
200
201Ops
202---
203
204Library provides a set of unary, binary and select ops for values data manipulation inside
205matrix and vector containers. Unary operations commonly used for apply and transformation
206operations, binary operations used for reductions and products, select operations used for
207filtration and mask application.
208
209Math operations
210---------------
211
212Library provides a set of high-level linera algebra operations over matrices and vectors with
213parametrization by binary, unary and select `ops`. There is avalable implementations for
214general `mxm` matrix-matrix, masked `mxmT` matrix-matrix, masked `mxv` matrix-vector,
215masked `vxm` vector-matrix products, matrix and vector reductions, assignment,
216matrix and vector element-wise `eadd` and `emult` oprations, and so on.
217Most operations have both CPU and GPU implementation. Thus, you will have GPU performance
218in computations out of the box.
219
220Details
221-------
222
223Spla C/C++ backend compiled library is automatically loaded and initialized on package import.
224State of the library managed by internal `bridge` module. All resources are unloaded automatically
225on package exit. Library state finalized automatically.
226
227"""
228
229__copyright__ = "Copyright (c) 2021-2023 SparseLinearAlgebra"
230
231__license__ = """
232MIT License
233
234Permission is hereby granted, free of charge, to any person obtaining a copy
235of this software and associated documentation files (the "Software"), to deal
236in the Software without restriction, including without limitation the rights
237to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
238copies of the Software, and to permit persons to whom the Software is
239furnished to do so, subject to the following conditions:
240
241The above copyright notice and this permission notice shall be included in all
242copies or substantial portions of the Software.
243
244THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
245IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
246FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
247AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
248LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
249OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
250SOFTWARE.
251"""
252
253from .bridge import *
254
255bridge.initialize()
256
257from .library import *
258from .descriptor import *
259from .op import *
260from .object import *
261from .schedule import *
262from .type import *
263from .array import *
264from .matrix import *
265from .vector import *
266from .scalar import *
267from .version import *
268
269__version__ = VERSIONS[-1]
270
271__all__ = [
272    "Type",
273    "BOOL",
274    "INT",
275    "UINT",
276    "FLOAT",
277    "FormatMatrix",
278    "FormatVector",
279    "Descriptor",
280    "Op",
281    "OpUnary",
282    "OpBinary",
283    "OpSelect",
284    "MemView",
285    "Object",
286    "Array",
287    "Matrix",
288    "Vector",
289    "Scalar",
290    "VERSIONS"
291]
class Type:
 45class Type:
 46    """
 47    Spla base Type for storage parametrization.
 48
 49    List of built-in Unary operations
 50    ---------------------------------
 51
 52    | Name      | Type     | Meaning        |
 53    |:----------|:---------|:---------------|
 54    |`IDENTITY` | unary(x) | r = x          |
 55    |`AINV`     | unary(x) | r = -x         |
 56    |`MINV`     | unary(x) | r = 1/x        |
 57    |`LNOT`     | unary(x) | r = !(x!=0)    |
 58    |`UONE`     | unary(x) | r = 1          |
 59    |`ABS`      | unary(x) | r = abs(x)     |
 60    |`BNOT`     | unary(x) | r = ~x         |
 61    |`SQRT`     | unary(x) | r = sqrt(x)    |
 62    |`LOG`      | unary(x) | r = log(x)     |
 63    |`EXP`      | unary(x) | r = exp(x)     |
 64    |`SIN`      | unary(x) | r = sin(x)     |
 65    |`COS`      | unary(x) | r = cos(x)     |
 66    |`TAN`      | unary(x) | r = tan(x)     |
 67    |`ASIN`     | unary(x) | r = asin(x)    |
 68    |`ACOS`     | unary(x) | r = acos(x)    |
 69    |`ATAN`     | unary(x) | r = atan(x)    |
 70    |`CEIL`     | unary(x) | r = ceil(x)    |
 71    |`FLOOR`    | unary(x) | r = floor(x)   |
 72    |`ROUND`    | unary(x) | r = round(x)   |
 73    |`TRUNC`    | unary(x) | r = trunc(x)   |
 74
 75    List of built-in Binary operations
 76    ----------------------------------
 77
 78    | Name    | Type        | Meaning        |
 79    |:--------|:------------|:---------------|
 80    |`PLUS`   | binary(x,y) | r = x + y      |
 81    |`MINUS`  | binary(x,y) | r = x - y      |
 82    |`MULT`   | binary(x,y) | r = x * y      |
 83    |`DIV`    | binary(x,y) | r = x / y      |
 84    |`FIRST`  | binary(x,y) | r = x          |
 85    |`SECOND` | binary(x,y) | r = y          |
 86    |`BONE`   | binary(x,y) | r = 1          |
 87    |`MIN`    | binary(x,y) | r = min(x, y)  |
 88    |`MAX`    | binary(x,y) | r = max(x, y)  |
 89    |`LOR`    | binary(x,y) | r = x lor y    |
 90    |`LAND`   | binary(x,y) | r = x && y     |
 91    |`BOR`    | binary(x,y) | r = x bor y    |
 92    |`BAND`   | binary(x,y) | r = x & y      |
 93    |`BXOR`   | binary(x,y) | r = x ^ y      |
 94
 95    List of built-in Select operations
 96    ----------------------------------
 97
 98    | Name    | Type        | Meaning        |
 99    |:--------|:------------|:---------------|
100    |`EQZERO` | select(x)   | x == 0         |
101    |`NQZERO` | select(x)   | x != 0         |
102    |`GTZERO` | select(x)   | x > 0          |
103    |`GEZERO` | select(x)   | x >= 0         |
104    |`LTZERO` | select(x)   | x < 0          |
105    |`LEZERO` | select(x)   | x <= 0         |
106    |`ALWAYS` | select(x)   | true           |
107    |`NEVER`  | select(x)   | false          |
108
109    """
110
111    _c_type = None
112    _c_type_p = None
113    _code = ''
114    _scalar_get = None
115    _scalar_set = None
116    _array_get = None
117    _array_set = None
118    _vector_get = None
119    _vector_set = None
120    _matrix_get = None
121    _matrix_set = None
122    _hnd = None
123
124    IDENTITY: OpUnary
125    AINV: OpUnary
126    MINV: OpUnary
127    LNOT: OpUnary
128    UONE: OpUnary
129    ABS: OpUnary
130    BNOT: OpUnary
131    SQRT: OpUnary
132    LOG: OpUnary
133    EXP: OpUnary
134    SIN: OpUnary
135    COS: OpUnary
136    TAN: OpUnary
137    ASIN: OpUnary
138    ACOS: OpUnary
139    ATAN: OpUnary
140    CEIL: OpUnary
141    FLOOR: OpUnary
142    ROUND: OpUnary
143    TRUNC: OpUnary
144
145    PLUS: OpBinary
146    MINUS: OpBinary
147    MULT: OpBinary
148    DIV: OpBinary
149    MINUS_POW2: OpBinary
150    FIRST: OpBinary
151    SECOND: OpBinary
152    BONE: OpBinary
153    MIN: OpBinary
154    MAX: OpBinary
155    LOR: OpBinary
156    LAND: OpBinary
157    BOR: OpBinary
158    BAND: OpBinary
159    BXOR: OpBinary
160
161    EQZERO: OpSelect
162    NQZERO: OpSelect
163    GTZERO: OpSelect
164    GEZERO: OpSelect
165    LTZERO: OpSelect
166    LEZERO: OpSelect
167    ALWAYS: OpSelect
168    NEVER: OpSelect
169
170    @classmethod
171    def get_code(cls):
172        """
173        Literal code of the type in numpy style.
174        """
175        return cls._code
176
177    @classmethod
178    def cast_value(cls, value):
179        """
180        Transforms native C value into python value.
181
182        :param value: any.
183            Ctypes value to unpack to python value.
184
185        :return: Transformed value.
186        """
187        pass
188
189    @classmethod
190    def format_value(cls, value, width=2, precision=2):
191        """
192        Format value of this type for a pretty printing.
193
194        :param value: any.
195            Value to format by this type.
196
197        :param width: optional: int. default: 2.
198            Formatted string integral part width.
199
200        :param precision:
201            Formatted string fractional part width.
202
203        :return: Formatted value.
204        """
205        f = "{:>%s}" % width
206        if not isinstance(value, bool):
207            return f.format(value)
208        return f.format("t") if value is True else f.format("f")
209
210    @classmethod
211    def _setup_op_unary(cls):
212        b = backend()
213        type_name = cls.__name__
214
215        def load_op(name):
216            f = f"spla_OpUnary_{name}_{type_name}"
217            func = getattr(b, f) if hasattr(b, f) else None
218            return OpUnary(hnd=func(), name=name, dtype_res=cls, dtype_arg0=cls) if func else None
219
220        cls.IDENTITY = load_op('IDENTITY')
221        cls.AINV = load_op('AINV')
222        cls.MINV = load_op('MINV')
223        cls.LNOT = load_op('LNOT')
224        cls.UONE = load_op('UONE')
225        cls.ABS = load_op('ABS')
226        cls.BNOT = load_op('BNOT')
227        cls.SQRT = load_op('SQRT')
228        cls.LOG = load_op('LOG')
229        cls.EXP = load_op('EXP')
230        cls.SIN = load_op('SIN')
231        cls.COS = load_op('COS')
232        cls.TAN = load_op('TAN')
233        cls.ASIN = load_op('ASIN')
234        cls.ACOS = load_op('ACOS')
235        cls.ATAN = load_op('ATAN')
236        cls.CEIL = load_op('CEIL')
237        cls.FLOOR = load_op('FLOOR')
238        cls.ROUND = load_op('ROUND')
239        cls.TRUNC = load_op('TRUNC')
240
241    @classmethod
242    def _setup_op_binary(cls):
243        b = backend()
244        type_name = cls.__name__
245
246        def load_op(name):
247            f = f"spla_OpBinary_{name}_{type_name}"
248            func = getattr(b, f) if hasattr(b, f) else None
249            return OpBinary(hnd=func(), name=name, dtype_res=cls, dtype_arg0=cls, dtype_arg1=cls) if func else None
250
251        cls.PLUS = load_op('PLUS')
252        cls.MINUS = load_op('MINUS')
253        cls.MULT = load_op('MULT')
254        cls.DIV = load_op('DIV')
255        cls.MINUS_POW2 = load_op('MINUS_POW2')
256        cls.FIRST = load_op('FIRST')
257        cls.SECOND = load_op('SECOND')
258        cls.BONE = load_op('BONE')
259        cls.MIN = load_op('MIN')
260        cls.MAX = load_op('MAX')
261        cls.LOR = load_op('LOR')
262        cls.LAND = load_op('LAND')
263        cls.BOR = load_op('BOR')
264        cls.BAND = load_op('BAND')
265        cls.BXOR = load_op('BXOR')
266
267    @classmethod
268    def _setup_op_select(cls):
269        b = backend()
270        type_name = cls.__name__
271
272        def load_op(name):
273            f = f"spla_OpSelect_{name}_{type_name}"
274            func = getattr(b, f) if hasattr(b, f) else None
275            return OpSelect(hnd=func(), name=name, dtype_arg0=cls) if func else None
276
277        cls.EQZERO = load_op('EQZERO')
278        cls.NQZERO = load_op('NQZERO')
279        cls.GTZERO = load_op('GTZERO')
280        cls.GEZERO = load_op('GEZERO')
281        cls.LTZERO = load_op('LTZERO')
282        cls.LEZERO = load_op('LEZERO')
283        cls.ALWAYS = load_op('ALWAYS')
284        cls.NEVER = load_op('NEVER')
285
286    @classmethod
287    def _setup(cls):
288        b = backend()
289        type_name = cls.__name__
290        type_name_lower = type_name.lower()
291
292        if not b:
293            return
294
295        cls._scalar_get = getattr(b, f"spla_Scalar_get_{type_name_lower}")
296        cls._scalar_set = getattr(b, f"spla_Scalar_set_{type_name_lower}")
297        cls._array_get = getattr(b, f"spla_Array_get_{type_name_lower}")
298        cls._array_set = getattr(b, f"spla_Array_set_{type_name_lower}")
299        cls._vector_get = getattr(b, f"spla_Vector_get_{type_name_lower}")
300        cls._vector_set = getattr(b, f"spla_Vector_set_{type_name_lower}")
301        cls._matrix_get = getattr(b, f"spla_Matrix_get_{type_name_lower}")
302        cls._matrix_set = getattr(b, f"spla_Matrix_set_{type_name_lower}")
303        cls._hnd = getattr(b, f"spla_Type_{type_name}")()
304
305        cls._setup_op_unary()
306        cls._setup_op_binary()
307        cls._setup_op_select()

Spla base Type for storage parametrization.

List of built-in Unary operations

Name Type Meaning
IDENTITY unary(x) r = x
AINV unary(x) r = -x
MINV unary(x) r = 1/x
LNOT unary(x) r = !(x!=0)
UONE unary(x) r = 1
ABS unary(x) r = abs(x)
BNOT unary(x) r = ~x
SQRT unary(x) r = sqrt(x)
LOG unary(x) r = log(x)
EXP unary(x) r = exp(x)
SIN unary(x) r = sin(x)
COS unary(x) r = cos(x)
TAN unary(x) r = tan(x)
ASIN unary(x) r = asin(x)
ACOS unary(x) r = acos(x)
ATAN unary(x) r = atan(x)
CEIL unary(x) r = ceil(x)
FLOOR unary(x) r = floor(x)
ROUND unary(x) r = round(x)
TRUNC unary(x) r = trunc(x)

List of built-in Binary operations

Name Type Meaning
PLUS binary(x,y) r = x + y
MINUS binary(x,y) r = x - y
MULT binary(x,y) r = x * y
DIV binary(x,y) r = x / y
FIRST binary(x,y) r = x
SECOND binary(x,y) r = y
BONE binary(x,y) r = 1
MIN binary(x,y) r = min(x, y)
MAX binary(x,y) r = max(x, y)
LOR binary(x,y) r = x lor y
LAND binary(x,y) r = x && y
BOR binary(x,y) r = x bor y
BAND binary(x,y) r = x & y
BXOR binary(x,y) r = x ^ y

List of built-in Select operations

Name Type Meaning
EQZERO select(x) x == 0
NQZERO select(x) x != 0
GTZERO select(x) x > 0
GEZERO select(x) x >= 0
LTZERO select(x) x < 0
LEZERO select(x) x <= 0
ALWAYS select(x) true
NEVER select(x) false
IDENTITY: pyspla.OpUnary
MINUS_POW2: pyspla.OpBinary
SECOND: pyspla.OpBinary
EQZERO: pyspla.OpSelect
NQZERO: pyspla.OpSelect
GTZERO: pyspla.OpSelect
GEZERO: pyspla.OpSelect
LTZERO: pyspla.OpSelect
LEZERO: pyspla.OpSelect
ALWAYS: pyspla.OpSelect
@classmethod
def get_code(cls):
170    @classmethod
171    def get_code(cls):
172        """
173        Literal code of the type in numpy style.
174        """
175        return cls._code

Literal code of the type in numpy style.

@classmethod
def cast_value(cls, value):
177    @classmethod
178    def cast_value(cls, value):
179        """
180        Transforms native C value into python value.
181
182        :param value: any.
183            Ctypes value to unpack to python value.
184
185        :return: Transformed value.
186        """
187        pass

Transforms native C value into python value.

Parameters
  • value: any. Ctypes value to unpack to python value.
Returns

Transformed value.

@classmethod
def format_value(cls, value, width=2, precision=2):
189    @classmethod
190    def format_value(cls, value, width=2, precision=2):
191        """
192        Format value of this type for a pretty printing.
193
194        :param value: any.
195            Value to format by this type.
196
197        :param width: optional: int. default: 2.
198            Formatted string integral part width.
199
200        :param precision:
201            Formatted string fractional part width.
202
203        :return: Formatted value.
204        """
205        f = "{:>%s}" % width
206        if not isinstance(value, bool):
207            return f.format(value)
208        return f.format("t") if value is True else f.format("f")

Format value of this type for a pretty printing.

Parameters
  • value: any. Value to format by this type.

  • width: optional: int. default: 2. Formatted string integral part width.

  • precision: Formatted string fractional part width.

Returns

Formatted value.

class BOOL(pyspla.Type):
310class BOOL(Type):
311    """Spla logical BOOL-32 type."""
312
313    _c_type = ctypes.c_bool
314    _c_type_p = ctypes.POINTER(ctypes.c_bool)
315    _code = 'B'
316
317    @classmethod
318    def cast_value(cls, value):
319        return bool(value.value)

Spla logical BOOL-32 type.

@classmethod
def cast_value(cls, value):
317    @classmethod
318    def cast_value(cls, value):
319        return bool(value.value)

Transforms native C value into python value.

Parameters
  • value: any. Ctypes value to unpack to python value.
Returns

Transformed value.

class INT(pyspla.Type):
322class INT(Type):
323    """Spla integral INT-32 type."""
324
325    _c_type = ctypes.c_int
326    _c_type_p = ctypes.POINTER(ctypes.c_int)
327    _code = 'I'
328
329    @classmethod
330    def cast_value(cls, value):
331        return int(value.value)

Spla integral INT-32 type.

@classmethod
def cast_value(cls, value):
329    @classmethod
330    def cast_value(cls, value):
331        return int(value.value)

Transforms native C value into python value.

Parameters
  • value: any. Ctypes value to unpack to python value.
Returns

Transformed value.

class UINT(pyspla.Type):
334class UINT(Type):
335    """Spla integral UINT-32 type."""
336
337    _c_type = ctypes.c_uint
338    _c_type_p = ctypes.POINTER(ctypes.c_uint)
339    _code = 'U'
340
341    @classmethod
342    def cast_value(cls, value):
343        return int(value.value)

Spla integral UINT-32 type.

@classmethod
def cast_value(cls, value):
341    @classmethod
342    def cast_value(cls, value):
343        return int(value.value)

Transforms native C value into python value.

Parameters
  • value: any. Ctypes value to unpack to python value.
Returns

Transformed value.

class FLOAT(pyspla.Type):
346class FLOAT(Type):
347    """Spla floating-point FLOAT-32 type."""
348
349    _c_type = ctypes.c_float
350    _c_type_p = ctypes.POINTER(ctypes.c_float)
351    _code = 'F'
352
353    @classmethod
354    def cast_value(cls, value):
355        return float(value.value)
356
357    @classmethod
358    def format_value(cls, value, width=2, precision=2):
359        return f"{value:>{width}.{precision}}"

Spla floating-point FLOAT-32 type.

@classmethod
def cast_value(cls, value):
353    @classmethod
354    def cast_value(cls, value):
355        return float(value.value)

Transforms native C value into python value.

Parameters
  • value: any. Ctypes value to unpack to python value.
Returns

Transformed value.

@classmethod
def format_value(cls, value, width=2, precision=2):
357    @classmethod
358    def format_value(cls, value, width=2, precision=2):
359        return f"{value:>{width}.{precision}}"

Format value of this type for a pretty printing.

Parameters
  • value: any. Value to format by this type.

  • width: optional: int. default: 2. Formatted string integral part width.

  • precision: Formatted string fractional part width.

Returns

Formatted value.

class FormatMatrix(enum.Enum):
102class FormatMatrix(enum.Enum):
103    """
104    Mapping for spla supported matrix storage formats enumeration.
105
106    | Name     | Memory type   | Description                                                       |
107    |:---------|--------------:|:------------------------------------------------------------------|
108    |`CPU_LIL` | RAM (host)    | List of lists, storing adjacency lists per vertex                 |
109    |`CPU_DOK` | RAM (host)    | Dictionary of keys, effectively hash map of row,column to value   |
110    |`CPU_COO` | RAM (host)    | Lists of coordinates, storing rows, columns and values separately |
111    |`CPU_CSR` | RAM (host)    | Compressed sparse rows format                                     |
112    |`CPU_CSC` | RAM (host)    | Compressed sparse columns format                                  |
113    |`ACC_COO` | VRAM (device) | List of coordinates, but implemented for GPU/ACC usage            |
114    |`ACC_CSR` | VRAM (device) | CSR, but implemented for GPU/ACC usage                            |
115    |`ACC_CSC` | VRAM (device) | CSC, but implemented for GPU/ACC usage                            |
116
117    """
118
119    CPU_LIL = 0
120    CPU_DOK = 1
121    CPU_COO = 2
122    CPU_CSR = 3
123    CPU_CSC = 4
124    ACC_COO = 5
125    ACC_CSR = 6
126    ACC_CSC = 7
127    COUNT = 8

Mapping for spla supported matrix storage formats enumeration.

Name Memory type Description
CPU_LIL RAM (host) List of lists, storing adjacency lists per vertex
CPU_DOK RAM (host) Dictionary of keys, effectively hash map of row,column to value
CPU_COO RAM (host) Lists of coordinates, storing rows, columns and values separately
CPU_CSR RAM (host) Compressed sparse rows format
CPU_CSC RAM (host) Compressed sparse columns format
ACC_COO VRAM (device) List of coordinates, but implemented for GPU/ACC usage
ACC_CSR VRAM (device) CSR, but implemented for GPU/ACC usage
ACC_CSC VRAM (device) CSC, but implemented for GPU/ACC usage
CPU_LIL = <FormatMatrix.CPU_LIL: 0>
CPU_DOK = <FormatMatrix.CPU_DOK: 1>
CPU_COO = <FormatMatrix.CPU_COO: 2>
CPU_CSR = <FormatMatrix.CPU_CSR: 3>
CPU_CSC = <FormatMatrix.CPU_CSC: 4>
ACC_COO = <FormatMatrix.ACC_COO: 5>
ACC_CSR = <FormatMatrix.ACC_CSR: 6>
ACC_CSC = <FormatMatrix.ACC_CSC: 7>
COUNT = <FormatMatrix.COUNT: 8>
Inherited Members
enum.Enum
name
value
class FormatVector(enum.Enum):
130class FormatVector(enum.Enum):
131    """
132    Mapping for spla supported vector storage formats enumeration.
133
134    | Name       | Memory type   | Description                                                    |
135    |:-----------|--------------:|:---------------------------------------------------------------|
136    |`CPU_DOK`   | RAM (host)    | Dictionary of keys, hash map of index to value                 |
137    |`CPU_DENSE` | RAM (host)    | Dense array of values with direct indexing                     |
138    |`CPU_COO`   | RAM (host)    | List of coordinates, storing rows and values separately        |
139    |`ACC_DENSE` | VRAM (device) | Dense array, but implemented for GPU/ACC usage                 |
140    |`ACC_COO`   | VRAM (device) | List of coordinates, but implemented for GPU/ACC usage         |
141    """
142
143    CPU_DOK = 0
144    CPU_DENSE = 1
145    CPU_COO = 2
146    ACC_DENSE = 3
147    ACC_COO = 4
148    COUNT = 5

Mapping for spla supported vector storage formats enumeration.

Name Memory type Description
CPU_DOK RAM (host) Dictionary of keys, hash map of index to value
CPU_DENSE RAM (host) Dense array of values with direct indexing
CPU_COO RAM (host) List of coordinates, storing rows and values separately
ACC_DENSE VRAM (device) Dense array, but implemented for GPU/ACC usage
ACC_COO VRAM (device) List of coordinates, but implemented for GPU/ACC usage
CPU_DOK = <FormatVector.CPU_DOK: 0>
CPU_DENSE = <FormatVector.CPU_DENSE: 1>
CPU_COO = <FormatVector.CPU_COO: 2>
ACC_DENSE = <FormatVector.ACC_DENSE: 3>
ACC_COO = <FormatVector.ACC_COO: 4>
COUNT = <FormatVector.COUNT: 5>
Inherited Members
enum.Enum
name
value
class Descriptor(pyspla.Object):
36class Descriptor(Object):
37    """
38    Wrapper for a descriptor object from a library.
39    """
40
41    def __init__(self, label=None, hnd=None):
42        """
43        Creates a new descriptor from existing hnd or making new for a buffer resource.
44
45        :param label: optional: str. default: None.
46            MemView name for debugging.
47
48        :param hnd: optional: ctypes.c_void_p. default: None.
49            MemView native void* handle to a C counterpart.
50        """
51
52        super().__init__(label, hnd)

Wrapper for a descriptor object from a library.

Descriptor(label=None, hnd=None)
41    def __init__(self, label=None, hnd=None):
42        """
43        Creates a new descriptor from existing hnd or making new for a buffer resource.
44
45        :param label: optional: str. default: None.
46            MemView name for debugging.
47
48        :param hnd: optional: ctypes.c_void_p. default: None.
49            MemView native void* handle to a C counterpart.
50        """
51
52        super().__init__(label, hnd)

Creates a new descriptor from existing hnd or making new for a buffer resource.

Parameters
  • label: optional: str. default: None. MemView name for debugging.

  • hnd: optional: ctypes.c_void_p. default: None. MemView native void* handle to a C counterpart.

Inherited Members
Object
hnd
label
class Op(pyspla.Object):
40class Op(Object):
41    """
42    Wrapper for a spla Op (operation) object.
43
44    Notes
45    -----
46
47    Operation represents some callable function with a return value.
48    This function may be used for mathematical calculations with
49    library primitives such as scalars, vectors and matrices.
50    """
51
52    __slots__ = ["_name", "_dtype_res"]
53
54    def __init__(self, hnd, name, dtype_res, label=None):
55        """
56        Creates new operation from a native C api object handle.
57
58        :param  hnd: ctypes.c_void_p.
59            Mandatory handle to native C object.
60
61        :param name: str.
62            Mandatory name of the operation.
63
64        :param dtype_res: Type.
65            Type of the return value of the operation.
66
67        :param label: optional: str. default: None.
68            Optional debug label to set for the object.
69        """
70
71        assert hnd
72        assert name
73        assert dtype_res
74
75        super().__init__(label, hnd)
76
77        self._name = name
78        self._dtype_res = dtype_res
79
80    @property
81    def name(self):
82        """
83        Name of operation.
84        """
85        return self._name
86
87    @property
88    def dtype_res(self):
89        """
90        Data type of the return value of the operation.
91        """
92        return self._dtype_res

Wrapper for a spla Op (operation) object.

Notes

Operation represents some callable function with a return value. This function may be used for mathematical calculations with library primitives such as scalars, vectors and matrices.

Op(hnd, name, dtype_res, label=None)
54    def __init__(self, hnd, name, dtype_res, label=None):
55        """
56        Creates new operation from a native C api object handle.
57
58        :param  hnd: ctypes.c_void_p.
59            Mandatory handle to native C object.
60
61        :param name: str.
62            Mandatory name of the operation.
63
64        :param dtype_res: Type.
65            Type of the return value of the operation.
66
67        :param label: optional: str. default: None.
68            Optional debug label to set for the object.
69        """
70
71        assert hnd
72        assert name
73        assert dtype_res
74
75        super().__init__(label, hnd)
76
77        self._name = name
78        self._dtype_res = dtype_res

Creates new operation from a native C api object handle.

Parameters
  • hnd: ctypes.c_void_p. Mandatory handle to native C object.

  • name: str. Mandatory name of the operation.

  • dtype_res: Type. Type of the return value of the operation.

  • label: optional: str. default: None. Optional debug label to set for the object.

name

Name of operation.

dtype_res

Data type of the return value of the operation.

Inherited Members
Object
hnd
label
class OpUnary(pyspla.Op):
 95class OpUnary(Op):
 96    """
 97    Wrapper for a spla OpUnary (unary operation) object.
 98
 99    Notes
100    -----
101
102    Unary operation is a callable function with a signature `T0 -> R`.
103    This function may be used in transformation and apply operations.
104    """
105
106    __slots__ = ["_dtype_arg0"]
107
108    def __init__(self, hnd, name, dtype_res, dtype_arg0, label=None):
109        """
110        Creates new unary operation from a native C api object handle.
111
112        :param hnd: ctypes.c_void_p.
113            Mandatory handle to native C object.
114
115        :param name: str.
116            Mandatory name of the operation.
117
118        :param dtype_res: Type.
119            Type of the return value of the operation.
120
121        :param dtype_arg0: Type.
122            Type of the first operation argument.
123
124        :param label: optional: str. default: None.
125            Optional debug label to set for the object.
126        """
127
128        super().__init__(hnd=hnd, name=name, dtype_res=dtype_res, label=label)
129
130        self._dtype_arg0 = dtype_arg0
131
132    @property
133    def dtype_arg0(self):
134        """
135        Data type of the first argument of the unary operation.
136        """
137        return self._dtype_arg0

Wrapper for a spla OpUnary (unary operation) object.

Notes

Unary operation is a callable function with a signature T0 -> R. This function may be used in transformation and apply operations.

OpUnary(hnd, name, dtype_res, dtype_arg0, label=None)
108    def __init__(self, hnd, name, dtype_res, dtype_arg0, label=None):
109        """
110        Creates new unary operation from a native C api object handle.
111
112        :param hnd: ctypes.c_void_p.
113            Mandatory handle to native C object.
114
115        :param name: str.
116            Mandatory name of the operation.
117
118        :param dtype_res: Type.
119            Type of the return value of the operation.
120
121        :param dtype_arg0: Type.
122            Type of the first operation argument.
123
124        :param label: optional: str. default: None.
125            Optional debug label to set for the object.
126        """
127
128        super().__init__(hnd=hnd, name=name, dtype_res=dtype_res, label=label)
129
130        self._dtype_arg0 = dtype_arg0

Creates new unary operation from a native C api object handle.

Parameters
  • hnd: ctypes.c_void_p. Mandatory handle to native C object.

  • name: str. Mandatory name of the operation.

  • dtype_res: Type. Type of the return value of the operation.

  • dtype_arg0: Type. Type of the first operation argument.

  • label: optional: str. default: None. Optional debug label to set for the object.

dtype_arg0

Data type of the first argument of the unary operation.

Inherited Members
Op
name
dtype_res
Object
hnd
label
class OpBinary(pyspla.Op):
140class OpBinary(Op):
141    """
142    Wrapper for a spla OpBinary (binary operation) object.
143
144    Notes
145    -----
146
147    Binary operation is a callable function with signature `T0 x T1 -> R`.
148    It is commonly used in math matrix vector products, reductions, etc.
149    """
150
151    __slots__ = ["_dtype_arg0", "_dtype_arg1"]
152
153    def __init__(self, hnd, name, dtype_res, dtype_arg0, dtype_arg1, label=None):
154        """
155        Creates new binary operation from a native C api object handle.
156
157        :param hnd: ctypes.c_void_p.
158            Mandatory handle to native C object.
159
160        :param name: str.
161            Mandatory name of the operation.
162
163        :param dtype_res: Type.
164            Type of the return value of the operation.
165
166        :param dtype_arg0: Type.
167            Type of the first operation argument.
168
169        :param dtype_arg1: Type.
170            Type of the second operation argument.
171
172        :param  label: optional: str. default: None.
173            Optional debug label to set for the object.
174        """
175
176        super().__init__(hnd=hnd, name=name, dtype_res=dtype_res, label=label)
177
178        self._dtype_arg0 = dtype_arg0
179        self._dtype_arg1 = dtype_arg1
180
181    @property
182    def dtype_arg0(self):
183        """
184        Data type of the first argument of the binary operation.
185        """
186        return self._dtype_arg0
187
188    @property
189    def dtype_arg1(self):
190        """
191        Data type of the second argument of the binary operation.
192        """
193        return self._dtype_arg1

Wrapper for a spla OpBinary (binary operation) object.

Notes

Binary operation is a callable function with signature T0 x T1 -> R. It is commonly used in math matrix vector products, reductions, etc.

OpBinary(hnd, name, dtype_res, dtype_arg0, dtype_arg1, label=None)
153    def __init__(self, hnd, name, dtype_res, dtype_arg0, dtype_arg1, label=None):
154        """
155        Creates new binary operation from a native C api object handle.
156
157        :param hnd: ctypes.c_void_p.
158            Mandatory handle to native C object.
159
160        :param name: str.
161            Mandatory name of the operation.
162
163        :param dtype_res: Type.
164            Type of the return value of the operation.
165
166        :param dtype_arg0: Type.
167            Type of the first operation argument.
168
169        :param dtype_arg1: Type.
170            Type of the second operation argument.
171
172        :param  label: optional: str. default: None.
173            Optional debug label to set for the object.
174        """
175
176        super().__init__(hnd=hnd, name=name, dtype_res=dtype_res, label=label)
177
178        self._dtype_arg0 = dtype_arg0
179        self._dtype_arg1 = dtype_arg1

Creates new binary operation from a native C api object handle.

Parameters
  • hnd: ctypes.c_void_p. Mandatory handle to native C object.

  • name: str. Mandatory name of the operation.

  • dtype_res: Type. Type of the return value of the operation.

  • dtype_arg0: Type. Type of the first operation argument.

  • dtype_arg1: Type. Type of the second operation argument.

  • label: optional: str. default: None. Optional debug label to set for the object.

dtype_arg0

Data type of the first argument of the binary operation.

dtype_arg1

Data type of the second argument of the binary operation.

Inherited Members
Op
name
dtype_res
Object
hnd
label
class OpSelect(pyspla.Op):
196class OpSelect(Op):
197    """
198    Wrapper for a spla OpSelect (select operation) object.
199
200    Notes
201    -----
202
203    Selection operation is a special kind of callable function with signature `T0 -> BOOL`.
204    This type of `unary predicate` usually used for masking and filtering operations.
205    """
206
207    __slots__ = ["_dtype_arg0"]
208
209    def __init__(self, hnd, name, dtype_arg0, label=None):
210        """
211        Creates new select operation from a native C api object handle.
212
213        :param hnd: ctypes.c_void_p.
214            Mandatory handle to native C object.
215
216        :param name: str.
217            Mandatory name of the operation.
218
219        :param dtype_arg0: Type.
220            Type of the first operation argument.
221
222        :param label: optional: str. default: None.
223            Optional debug label to set for the object.
224        """
225
226        from .type import BOOL
227
228        super().__init__(hnd=hnd, name=name, dtype_res=BOOL, label=label)
229
230        self._dtype_arg0 = dtype_arg0
231
232    @property
233    def dtype_arg0(self):
234        """
235        Data type of the first argument of the select operation.
236        """
237        return self._dtype_arg0

Wrapper for a spla OpSelect (select operation) object.

Notes

Selection operation is a special kind of callable function with signature T0 -> BOOL. This type of unary predicate usually used for masking and filtering operations.

OpSelect(hnd, name, dtype_arg0, label=None)
209    def __init__(self, hnd, name, dtype_arg0, label=None):
210        """
211        Creates new select operation from a native C api object handle.
212
213        :param hnd: ctypes.c_void_p.
214            Mandatory handle to native C object.
215
216        :param name: str.
217            Mandatory name of the operation.
218
219        :param dtype_arg0: Type.
220            Type of the first operation argument.
221
222        :param label: optional: str. default: None.
223            Optional debug label to set for the object.
224        """
225
226        from .type import BOOL
227
228        super().__init__(hnd=hnd, name=name, dtype_res=BOOL, label=label)
229
230        self._dtype_arg0 = dtype_arg0

Creates new select operation from a native C api object handle.

Parameters
  • hnd: ctypes.c_void_p. Mandatory handle to native C object.

  • name: str. Mandatory name of the operation.

  • dtype_arg0: Type. Type of the first operation argument.

  • label: optional: str. default: None. Optional debug label to set for the object.

dtype_arg0

Data type of the first argument of the select operation.

Inherited Members
Op
name
dtype_res
Object
hnd
label
class MemView(pyspla.Object):
 36class MemView(Object):
 37    """
 38    Wrapper for a memory view object from a library.
 39
 40    Details
 41    -------
 42
 43    Memory view is a wrapper for a raw memory resource. It allows to inspect
 44    spla library containers data without an extra overhead on copy operations
 45    and without explicit memory lifetime control.
 46    """
 47
 48    __slots__ = ["_buffer", "_owner"]
 49
 50    def __init__(self, label=None, hnd=None, buffer=None, size=None, mutable=None, owner=None):
 51        """
 52        Creates a new memory view from existing hnd or making new for a buffer resource.
 53
 54        :param label: optional: str. default: None.
 55            MemView name for debugging.
 56
 57        :param hnd: optional: ctypes.c_void_p. default: None.
 58            MemView native void* handle to a C counterpart.
 59
 60        :param buffer: optional: ctypes.c_void_p. default: None.
 61            Optional buffer in case making new view.
 62
 63        :param size: optional: int. default: None.
 64            Optional size, must be provided if buffer provided.
 65
 66        :param mutable: optional: bool. default: None.
 67            Optional flag if buffer content is mutable.
 68
 69        :param owner: optional: Object. default: None.
 70            Optional owner of a given memory view.
 71        """
 72
 73        super().__init__(None, None)
 74
 75        self._buffer = buffer
 76        self._owner = owner
 77
 78        if hnd is None:
 79            assert buffer
 80            assert size
 81
 82            if mutable is None:
 83                mutable = 0
 84
 85            hnd = ctypes.c_void_p(0)
 86            check(backend().spla_MemView_make(ctypes.byref(hnd), buffer, ctypes.c_size_t(size), ctypes.c_int(mutable)))
 87
 88        super().__init__(label, hnd)
 89
 90    @property
 91    def buffer(self):
 92        """
 93        Pointer to a native C-buffer viewed by this view.
 94        """
 95        c_buffer = ctypes.c_void_p(0)
 96        check(backend().spla_MemView_get_buffer(self._hnd, ctypes.byref(c_buffer)))
 97        return c_buffer
 98
 99    @property
100    def size(self):
101        """
102        Size of viewed memory buffer in bytes.
103        """
104
105        c_size = ctypes.c_size_t(0)
106        check(backend().spla_MemView_get_size(self._hnd, ctypes.byref(c_size)))
107        return int(c_size.value)
108
109    @property
110    def is_mutable(self):
111        """
112        True if the content of viewed memory buffer can be modified.
113        """
114
115        c_is_mutable = ctypes.c_int(0)
116        check(backend().spla_MemView_get_buffer(self._hnd, ctypes.byref(c_is_mutable)))
117        return bool(c_is_mutable.value)

Wrapper for a memory view object from a library.

Details

Memory view is a wrapper for a raw memory resource. It allows to inspect spla library containers data without an extra overhead on copy operations and without explicit memory lifetime control.

MemView( label=None, hnd=None, buffer=None, size=None, mutable=None, owner=None)
50    def __init__(self, label=None, hnd=None, buffer=None, size=None, mutable=None, owner=None):
51        """
52        Creates a new memory view from existing hnd or making new for a buffer resource.
53
54        :param label: optional: str. default: None.
55            MemView name for debugging.
56
57        :param hnd: optional: ctypes.c_void_p. default: None.
58            MemView native void* handle to a C counterpart.
59
60        :param buffer: optional: ctypes.c_void_p. default: None.
61            Optional buffer in case making new view.
62
63        :param size: optional: int. default: None.
64            Optional size, must be provided if buffer provided.
65
66        :param mutable: optional: bool. default: None.
67            Optional flag if buffer content is mutable.
68
69        :param owner: optional: Object. default: None.
70            Optional owner of a given memory view.
71        """
72
73        super().__init__(None, None)
74
75        self._buffer = buffer
76        self._owner = owner
77
78        if hnd is None:
79            assert buffer
80            assert size
81
82            if mutable is None:
83                mutable = 0
84
85            hnd = ctypes.c_void_p(0)
86            check(backend().spla_MemView_make(ctypes.byref(hnd), buffer, ctypes.c_size_t(size), ctypes.c_int(mutable)))
87
88        super().__init__(label, hnd)

Creates a new memory view from existing hnd or making new for a buffer resource.

Parameters
  • label: optional: str. default: None. MemView name for debugging.

  • hnd: optional: ctypes.c_void_p. default: None. MemView native void* handle to a C counterpart.

  • buffer: optional: ctypes.c_void_p. default: None. Optional buffer in case making new view.

  • size: optional: int. default: None. Optional size, must be provided if buffer provided.

  • mutable: optional: bool. default: None. Optional flag if buffer content is mutable.

  • owner: optional: Object. default: None. Optional owner of a given memory view.

buffer

Pointer to a native C-buffer viewed by this view.

size

Size of viewed memory buffer in bytes.

is_mutable

True if the content of viewed memory buffer can be modified.

Inherited Members
Object
hnd
label
class Object:
35class Object:
36    """
37    Base class for any spla library object.
38
39    Details
40    -------
41
42    Object class support all spla C API matrix functions.
43    It provides bind functionality as well as new functions/methods for better python user experience.
44
45    Object class used for runtime-introspection of spla primitives, as well as for safe ref-count
46    of native spla C/C++ instances, created inside imported native shared spla (.dll/.so/.dylib) library.
47    """
48
49    __slots__ = ["_hnd", "_label"]
50
51    def __init__(self, label, hnd):
52        """
53        Creates a base spla object class instance with common attributes.
54
55        :param label: optional: str. default: None.
56            Object name for debugging.
57
58        :param hnd: optional: ctypes.c_void_p. default: None.
59            Object native void* handle to a C counterpart.
60        """
61
62        self._hnd = hnd
63        self._label = label
64
65    def __del__(self):
66        if self._hnd:
67            check(backend().spla_RefCnt_unref(self._hnd))
68
69    @property
70    def hnd(self):
71        """
72        Return handle (ctypes.c_void_p) to a wrapped native C object.
73        """
74        return self._hnd
75
76    @property
77    def label(self):
78        """
79        Returns optional debug string label for the object.
80        """
81        return self._label

Base class for any spla library object.

Details

Object class support all spla C API matrix functions. It provides bind functionality as well as new functions/methods for better python user experience.

Object class used for runtime-introspection of spla primitives, as well as for safe ref-count of native spla C/C++ instances, created inside imported native shared spla (.dll/.so/.dylib) library.

Object(label, hnd)
51    def __init__(self, label, hnd):
52        """
53        Creates a base spla object class instance with common attributes.
54
55        :param label: optional: str. default: None.
56            Object name for debugging.
57
58        :param hnd: optional: ctypes.c_void_p. default: None.
59            Object native void* handle to a C counterpart.
60        """
61
62        self._hnd = hnd
63        self._label = label

Creates a base spla object class instance with common attributes.

Parameters
  • label: optional: str. default: None. Object name for debugging.

  • hnd: optional: ctypes.c_void_p. default: None. Object native void* handle to a C counterpart.

hnd

Return handle (ctypes.c_void_p) to a wrapped native C object.

label

Returns optional debug string label for the object.

class Array(pyspla.Object):
 39class Array(Object):
 40    """
 41    Generalized statically-typed dense linear array primitive.
 42
 43    Notes
 44    -----
 45
 46    Array typical usage:
 47
 48    - Instantiate array primitive
 49    - Fill with values from your data
 50    - Use array to build entire vector or matrix
 51    - Read-back results of computations from vector or matrix
 52
 53    Details
 54    -------
 55
 56    Array class support all spla C API vector functions.
 57    It provides bind functionality as well as new functions/methods for better python user experience.
 58
 59    Array internally manages native optimized storage for values.
 60    Reading and writing values into array is fast and has nearly no overhead.
 61    """
 62
 63    __slots__ = ["_dtype"]
 64
 65    def __init__(self, dtype=INT, shape=None, hnd=None, label=None):
 66        """
 67        Creates new array of specified type and shape.
 68
 69        :param dtype: Type.
 70            Type parametrization of a storage.
 71
 72        :param shape: optional: int. default: None.
 73            Size of the array.
 74
 75        :param hnd: optional: ctypes.c_void_p. default: None.
 76            Optional native handle to retain.
 77
 78        :param label: optional: str. default: None.
 79            Optional label to assign.
 80        """
 81
 82        super().__init__(None, None)
 83
 84        assert dtype
 85        assert issubclass(dtype, Type)
 86
 87        self._dtype = dtype
 88
 89        if not shape:
 90            shape = 0
 91
 92        if not hnd:
 93            hnd = ctypes.c_void_p(0)
 94            check(backend().spla_Array_make(ctypes.byref(hnd), ctypes.c_uint(shape), dtype._hnd))
 95
 96        super().__init__(label, hnd)
 97
 98    @property
 99    def dtype(self):
100        """
101        Type used for storage parametrization of this container.
102        """
103        return self._dtype
104
105    @property
106    def n_vals(self):
107        """
108        Number of values in the array.
109        """
110
111        n_values = ctypes.c_uint(0)
112        check(backend().spla_Array_get_n_values(self._hnd, ctypes.byref(n_values)))
113        return int(n_values.value)
114
115    @property
116    def shape(self):
117        """
118        2-Tuple with shape of array where second value is always 1.
119        """
120
121        return self.n_vals, 1
122
123    @property
124    def empty(self):
125        """
126        Checks if array is empty (has 0-size) and returns true. True if array is empty.
127        """
128
129        return self.shape[0] == 0
130
131    def set(self, index, value):
132        """
133        Set value at specified index.
134
135        :param index: int.
136            Index at which value to set.
137
138        :param value: any.
139            Value to set, must be convertible to destination type.
140        """
141
142        check(self._dtype._array_set(self._hnd, ctypes.c_uint(index), self._dtype._c_type(value)))
143
144    def get(self, index):
145        """
146        Get value at specified index.
147
148        :param index: int.
149            Index at which to get value.
150
151        :return: Value at specified index.
152        """
153
154        value = self._dtype._c_type(0)
155        check(self._dtype._array_get(self._hnd, ctypes.c_uint(index), ctypes.byref(value)))
156        return self._dtype.cast_value(value)
157
158    def build(self, view: MemView):
159        """
160        Builds array from a raw memory view resource.
161
162        :param view: MemView.
163            View to a memory to build the array content from.
164        """
165
166        check(backend().spla_Array_build(self._hnd, view._hnd))
167
168    def read(self):
169        """
170        Read the content of the array as a MemView.
171
172        :return: MemView object with view to the array content.
173        """
174
175        view_hnd = ctypes.c_void_p(0)
176        check(backend().spla_Array_read(self._hnd, ctypes.byref(view_hnd)))
177        return MemView(hnd=view_hnd, owner=self)
178
179    def resize(self, shape=0):
180        """
181        Resizes array to new size with desired num of values specified as shape.
182
183        :param shape: optional: int. default: 0.
184            New array capacity.
185        """
186
187        check(backend().spla_Array_resize(self._hnd, ctypes.c_uint(shape)))
188
189    def clear(self):
190        """
191        Clears array removing all elements, so it has 0 values.
192        """
193        check(backend().spla_Array_clear(self._hnd))
194
195    def to_list(self):
196        """
197        Read array data as a python list of values.
198
199        :return: List with values stored in the array.
200        """
201
202        buffer = (self.dtype._c_type * self.n_vals)()
203        size = ctypes.c_size_t(ctypes.sizeof(buffer))
204        view = self.read()
205        check(backend().spla_MemView_read(view._hnd, ctypes.c_size_t(0), size, buffer))
206        return list(buffer)
207
208    @classmethod
209    def from_list(cls, values, dtype=INT):
210        """
211        Creates new array of desired type from list of `values`.
212
213        :param values: List.
214            List with values to fill array.
215
216        :param dtype: Type.
217            Type of the array stored value.
218
219        :return: Created array filled with values.
220        """
221
222        buffer = (dtype._c_type * len(values))(*values)
223        view = MemView(buffer=buffer, size=ctypes.sizeof(buffer), mutable=False)
224        array = Array(dtype=dtype)
225        array.build(view)
226        return array
227
228    @classmethod
229    def rand(cls, dtype=INT, shape=0, seed=None, dist=(0, 1)):
230        """
231        Creates new array of desired type and shape and fills its content
232        with random values, generated using specified distribution.
233
234        :param dtype: optional: Type. default: INT.
235            Type of values array will have.
236
237        :param shape: optional: int. default: 0.
238            Size of the array (number of values).
239
240        :param seed: optional: int. default: None.
241            Optional seed to randomize generator.
242
243        :param dist: optional: tuple. default: [0,1].
244            Optional distribution for uniform generation of values.
245
246        :return: Created array filled with values.
247        """
248
249        array = Array(dtype=dtype, shape=shape)
250
251        if seed is not None:
252            rnd.seed(seed)
253
254        if dtype is INT:
255            for i in range(shape):
256                array.set(i, rnd.randint(dist[0], dist[1]))
257        elif dtype is UINT:
258            for i in range(shape):
259                array.set(i, rnd.randint(dist[0], dist[1]))
260        elif dtype is FLOAT:
261            for i in range(shape):
262                array.set(i, rnd.uniform(dist[0], dist[1]))
263        else:
264            raise Exception("unknown type")
265
266        return array
267
268    def __str__(self):
269        return str(self.to_list())
270
271    def __iter__(self):
272        return iter(self.to_list())
273
274    def __setitem__(self, key, value):
275        assert isinstance(key, int)
276        self.set(key, value)
277
278    def __getitem__(self, item):
279        assert isinstance(item, int)
280        return self.get(item)

Generalized statically-typed dense linear array primitive.

Notes

Array typical usage:

  • Instantiate array primitive
  • Fill with values from your data
  • Use array to build entire vector or matrix
  • Read-back results of computations from vector or matrix

Details

Array class support all spla C API vector functions. It provides bind functionality as well as new functions/methods for better python user experience.

Array internally manages native optimized storage for values. Reading and writing values into array is fast and has nearly no overhead.

Array(dtype=<class 'pyspla.INT'>, shape=None, hnd=None, label=None)
65    def __init__(self, dtype=INT, shape=None, hnd=None, label=None):
66        """
67        Creates new array of specified type and shape.
68
69        :param dtype: Type.
70            Type parametrization of a storage.
71
72        :param shape: optional: int. default: None.
73            Size of the array.
74
75        :param hnd: optional: ctypes.c_void_p. default: None.
76            Optional native handle to retain.
77
78        :param label: optional: str. default: None.
79            Optional label to assign.
80        """
81
82        super().__init__(None, None)
83
84        assert dtype
85        assert issubclass(dtype, Type)
86
87        self._dtype = dtype
88
89        if not shape:
90            shape = 0
91
92        if not hnd:
93            hnd = ctypes.c_void_p(0)
94            check(backend().spla_Array_make(ctypes.byref(hnd), ctypes.c_uint(shape), dtype._hnd))
95
96        super().__init__(label, hnd)

Creates new array of specified type and shape.

Parameters
  • dtype: Type. Type parametrization of a storage.

  • shape: optional: int. default: None. Size of the array.

  • hnd: optional: ctypes.c_void_p. default: None. Optional native handle to retain.

  • label: optional: str. default: None. Optional label to assign.

dtype

Type used for storage parametrization of this container.

n_vals

Number of values in the array.

shape

2-Tuple with shape of array where second value is always 1.

empty

Checks if array is empty (has 0-size) and returns true. True if array is empty.

def set(self, index, value):
131    def set(self, index, value):
132        """
133        Set value at specified index.
134
135        :param index: int.
136            Index at which value to set.
137
138        :param value: any.
139            Value to set, must be convertible to destination type.
140        """
141
142        check(self._dtype._array_set(self._hnd, ctypes.c_uint(index), self._dtype._c_type(value)))

Set value at specified index.

Parameters
  • index: int. Index at which value to set.

  • value: any. Value to set, must be convertible to destination type.

def get(self, index):
144    def get(self, index):
145        """
146        Get value at specified index.
147
148        :param index: int.
149            Index at which to get value.
150
151        :return: Value at specified index.
152        """
153
154        value = self._dtype._c_type(0)
155        check(self._dtype._array_get(self._hnd, ctypes.c_uint(index), ctypes.byref(value)))
156        return self._dtype.cast_value(value)

Get value at specified index.

Parameters
  • index: int. Index at which to get value.
Returns

Value at specified index.

def build(self, view: pyspla.MemView):
158    def build(self, view: MemView):
159        """
160        Builds array from a raw memory view resource.
161
162        :param view: MemView.
163            View to a memory to build the array content from.
164        """
165
166        check(backend().spla_Array_build(self._hnd, view._hnd))

Builds array from a raw memory view resource.

Parameters
  • view: MemView. View to a memory to build the array content from.
def read(self):
168    def read(self):
169        """
170        Read the content of the array as a MemView.
171
172        :return: MemView object with view to the array content.
173        """
174
175        view_hnd = ctypes.c_void_p(0)
176        check(backend().spla_Array_read(self._hnd, ctypes.byref(view_hnd)))
177        return MemView(hnd=view_hnd, owner=self)

Read the content of the array as a MemView.

Returns

MemView object with view to the array content.

def resize(self, shape=0):
179    def resize(self, shape=0):
180        """
181        Resizes array to new size with desired num of values specified as shape.
182
183        :param shape: optional: int. default: 0.
184            New array capacity.
185        """
186
187        check(backend().spla_Array_resize(self._hnd, ctypes.c_uint(shape)))

Resizes array to new size with desired num of values specified as shape.

Parameters
  • shape: optional: int. default: 0. New array capacity.
def clear(self):
189    def clear(self):
190        """
191        Clears array removing all elements, so it has 0 values.
192        """
193        check(backend().spla_Array_clear(self._hnd))

Clears array removing all elements, so it has 0 values.

def to_list(self):
195    def to_list(self):
196        """
197        Read array data as a python list of values.
198
199        :return: List with values stored in the array.
200        """
201
202        buffer = (self.dtype._c_type * self.n_vals)()
203        size = ctypes.c_size_t(ctypes.sizeof(buffer))
204        view = self.read()
205        check(backend().spla_MemView_read(view._hnd, ctypes.c_size_t(0), size, buffer))
206        return list(buffer)

Read array data as a python list of values.

Returns

List with values stored in the array.

@classmethod
def from_list(cls, values, dtype=<class 'pyspla.INT'>):
208    @classmethod
209    def from_list(cls, values, dtype=INT):
210        """
211        Creates new array of desired type from list of `values`.
212
213        :param values: List.
214            List with values to fill array.
215
216        :param dtype: Type.
217            Type of the array stored value.
218
219        :return: Created array filled with values.
220        """
221
222        buffer = (dtype._c_type * len(values))(*values)
223        view = MemView(buffer=buffer, size=ctypes.sizeof(buffer), mutable=False)
224        array = Array(dtype=dtype)
225        array.build(view)
226        return array

Creates new array of desired type from list of values.

Parameters
  • values: List. List with values to fill array.

  • dtype: Type. Type of the array stored value.

Returns

Created array filled with values.

@classmethod
def rand( cls, dtype=<class 'pyspla.INT'>, shape=0, seed=None, dist=(0, 1)):
228    @classmethod
229    def rand(cls, dtype=INT, shape=0, seed=None, dist=(0, 1)):
230        """
231        Creates new array of desired type and shape and fills its content
232        with random values, generated using specified distribution.
233
234        :param dtype: optional: Type. default: INT.
235            Type of values array will have.
236
237        :param shape: optional: int. default: 0.
238            Size of the array (number of values).
239
240        :param seed: optional: int. default: None.
241            Optional seed to randomize generator.
242
243        :param dist: optional: tuple. default: [0,1].
244            Optional distribution for uniform generation of values.
245
246        :return: Created array filled with values.
247        """
248
249        array = Array(dtype=dtype, shape=shape)
250
251        if seed is not None:
252            rnd.seed(seed)
253
254        if dtype is INT:
255            for i in range(shape):
256                array.set(i, rnd.randint(dist[0], dist[1]))
257        elif dtype is UINT:
258            for i in range(shape):
259                array.set(i, rnd.randint(dist[0], dist[1]))
260        elif dtype is FLOAT:
261            for i in range(shape):
262                array.set(i, rnd.uniform(dist[0], dist[1]))
263        else:
264            raise Exception("unknown type")
265
266        return array

Creates new array of desired type and shape and fills its content with random values, generated using specified distribution.

Parameters
  • dtype: optional: Type. default: INT. Type of values array will have.

  • shape: optional: int. default: 0. Size of the array (number of values).

  • seed: optional: int. default: None. Optional seed to randomize generator.

  • dist: optional: tuple. default: [0,1]. Optional distribution for uniform generation of values.

Returns

Created array filled with values.

Inherited Members
Object
hnd
label
class Matrix(pyspla.Object):
  42class Matrix(Object):
  43    """
  44    Generalized statically-typed sparse storage-invariant matrix primitive.
  45
  46    Notes
  47    -----
  48
  49    Matrix typical usage:
  50
  51    - Instantiate matrix primitive
  52    - Build incrementally from yours data source
  53    - Matrix usage in a sequence of math operations
  54    - Read-back matrix data to python to analyse results
  55
  56    Steps (2) and (4) requires internal format transformations and possible transfer of data
  57    from acc (GPU) side if acceleration was employed in computations. These steps may be very
  58    intensive, so you have to avoid them in critical parts of computations. If you need faster
  59    data reads, prefer usage of batched reads, where all content of storage read at once.
  60
  61    Details
  62    -------
  63
  64    Matrix class support all spla C API matrix functions.
  65    It provides bind functionality as well as new functions/methods for better python user experience.
  66
  67    Matrix internally manages optimal format of stored data. Use hints to
  68    force matrix state and format changes.
  69
  70    Matrix optional uses dedicated/integrated GPU to speedup computations
  71    using one of built-in OpenCL or CUDA accelerators.
  72    """
  73
  74    __slots__ = ["_dtype", "_shape"]
  75
  76    def __init__(self, shape, dtype=INT, hnd=None, label=None):
  77        """
  78        Creates new matrix of specified type and shape.
  79
  80        >>> M = Matrix((4, 5), INT)
  81        >>> print(M)
  82        '
  83            0 1 2 3 4
  84         0| . . . . .|  0
  85         1| . . . . .|  1
  86         2| . . . . .|  2
  87         3| . . . . .|  3
  88            0 1 2 3 4
  89        '
  90
  91        :param dtype: Type.
  92            Type parametrization of a storage.
  93
  94        :param shape: tuple.
  95            Matrix size (2-dim).
  96
  97        :param hnd: optional: ctypes.c_void_p. default: None.
  98            Optional native handle to retain.
  99
 100        :param label: optional: str. default: None.
 101            Optional label to assign.
 102        """
 103
 104        super().__init__(None, None)
 105
 106        assert dtype
 107        assert shape
 108        assert shape[0] > 0 and shape[1] > 0
 109        assert issubclass(dtype, Type)
 110
 111        self._dtype = dtype
 112        self._shape = shape
 113
 114        if not hnd:
 115            hnd = ctypes.c_void_p(0)
 116            check(backend().spla_Matrix_make(ctypes.byref(hnd),
 117                                             ctypes.c_uint(shape[0]),
 118                                             ctypes.c_uint(shape[1]),
 119                                             dtype._hnd))
 120
 121        super().__init__(label, hnd)
 122
 123    @property
 124    def dtype(self):
 125        """
 126        Type used for storage parametrization of this container.
 127
 128        >>> M = Matrix((4, 5), INT)
 129        >>> print(M.dtype)
 130        '
 131            <class 'pyspla.type.INT'>
 132        '
 133        """
 134        return self._dtype
 135
 136    @property
 137    def n_rows(self):
 138        """
 139        Number of rows in the matrix.
 140
 141        >>> M = Matrix((4, 5), INT)
 142        >>> print(M.n_rows)
 143        '
 144            4
 145        '
 146        """
 147        return self._shape[0]
 148
 149    @property
 150    def n_cols(self):
 151        """
 152        Number of cols in the matrix.
 153
 154        >>> M = Matrix((4, 5), INT)
 155        >>> print(M.n_cols)
 156        '
 157            5
 158        '
 159        """
 160        return self._shape[1]
 161
 162    @property
 163    def shape(self):
 164        """
 165        2-Tuple with shape of matrix.
 166
 167        >>> M = Matrix((4, 5), INT)
 168        >>> print(M.shape)
 169        '
 170            (4, 5)
 171        '
 172        """
 173
 174        return self._shape
 175
 176    def set_format(self, fmt):
 177        """
 178        Instruct container to format internal data with desired storage format.
 179        Multiple different formats may be set at same time, data will be duplicated in different formats.
 180        If selected data already in a selected format, then nothing to do.
 181
 182        See `FormatMatrix` enumeration for all supported formats.
 183
 184        :param fmt: FormatMatrix.
 185            One of built-in storage formats to set.
 186        """
 187
 188        check(backend().spla_Matrix_set_format(self.hnd, ctypes.c_int(fmt.value)))
 189
 190    def set(self, i, j, v):
 191        """
 192        Set value at specified index
 193
 194        >>> M = Matrix((4, 4), INT)
 195        >>> M.set(0, 0, -1)
 196        >>> M.set(1, 2, 4)
 197        >>> M.set(3, 1, 10)
 198        >>> print(M)
 199        '
 200            0 1 2 3
 201         0|-1 . . .|  0
 202         1| . . 4 .|  1
 203         2| . . . .|  2
 204         3| .10 . .|  3
 205            0 1 2 3
 206        '
 207
 208        :param i: uint.
 209            Row index to set.
 210
 211        :param j: uint.
 212            Column index to set.
 213
 214        :param v: any.
 215            Value to set.
 216        """
 217
 218        check(self._dtype._matrix_set(self.hnd, ctypes.c_uint(i), ctypes.c_uint(j), self._dtype._c_type(v)))
 219
 220    def get(self, i, j):
 221        """
 222        Get value at specified index.
 223
 224        >>> M = Matrix.from_lists([1, 2, 3, 3], [0, 1, 0, 3], [-1, -4, 4, 2], (4, 4), INT)
 225        >>> print(M.get(1, 0))
 226        '
 227            -1
 228        '
 229
 230        >>> M = Matrix.from_lists([1, 2, 3, 3], [0, 1, 0, 3], [-1, -4, 4, 2], (4, 4), INT)
 231        >>> print(M.get(1, 3))
 232        '
 233            0
 234        '
 235
 236        :param i: uint.
 237            Row index of value to get.
 238
 239        :param j: uint.
 240            Column index of value to get.
 241
 242        :return: Value.
 243        """
 244
 245        c_value = self._dtype._c_type(0)
 246        check(self._dtype._matrix_get(self.hnd, ctypes.c_uint(i), ctypes.c_uint(j), ctypes.byref(c_value)))
 247        return self._dtype.cast_value(c_value)
 248
 249    def build(self, view_I: MemView, view_J: MemView, view_V: MemView):
 250        """
 251        Builds matrix content from a raw memory view resources.
 252
 253        :param view_I: MemView.
 254            View to keys of matrix to assign.
 255
 256        :param view_J: MemView.
 257            View to keys of matrix to assign.
 258
 259        :param view_V: MemView.
 260            View to actual values to store.
 261        """
 262
 263        assert view_I
 264        assert view_J
 265        assert view_V
 266
 267        check(backend().spla_Matrix_build(self.hnd, view_I.hnd, view_J.hnd, view_V.hnd))
 268
 269    def read(self):
 270        """
 271        Read the content of the matrix as a MemView of I, J and V.
 272
 273        :return: tuple (MemView, MemView, MemView) objects with view to the matrix keys and matrix values.
 274        """
 275
 276        view_I_hnd = ctypes.c_void_p(0)
 277        view_J_hnd = ctypes.c_void_p(0)
 278        view_V_hnd = ctypes.c_void_p(0)
 279        check(backend().spla_Matrix_read(self.hnd,
 280                                         ctypes.byref(view_I_hnd),
 281                                         ctypes.byref(view_J_hnd),
 282                                         ctypes.byref(view_V_hnd)))
 283        return MemView(hnd=view_I_hnd, owner=self), \
 284               MemView(hnd=view_J_hnd, owner=self), \
 285               MemView(hnd=view_V_hnd, owner=self)
 286
 287    def clear(self):
 288        """
 289        Clears matrix removing all elements, so it has no values.
 290        """
 291
 292        check(backend().spla_Matrix_clear(self.hnd))
 293
 294    def to_lists(self):
 295        """
 296        Read matrix data as a python lists of I, J and V.
 297
 298        >>> M = Matrix.from_lists([1, 2, 3, 3], [0, 1, 0, 3], [-1, -4, 4, 2], (4, 4), INT)
 299        >>> print(M.to_lists())
 300        '
 301            ([1, 2, 3, 3], [0, 1, 0, 3], [-1, -4, 4, 2])
 302        '
 303
 304        :return: Tuple (List, List, List) with the matrix keys and matrix values.
 305        """
 306
 307        I, J, V = self.read()
 308        count = int(I.size / ctypes.sizeof(UINT._c_type))
 309
 310        if count == 0:
 311            return [], [], []
 312
 313        buffer_I = (UINT._c_type * count)()
 314        buffer_J = (UINT._c_type * count)()
 315        buffer_V = (self._dtype._c_type * count)()
 316
 317        check(backend().spla_MemView_read(I.hnd, ctypes.c_size_t(0), ctypes.sizeof(buffer_I), buffer_I))
 318        check(backend().spla_MemView_read(J.hnd, ctypes.c_size_t(0), ctypes.sizeof(buffer_J), buffer_J))
 319        check(backend().spla_MemView_read(V.hnd, ctypes.c_size_t(0), ctypes.sizeof(buffer_V), buffer_V))
 320
 321        return list(buffer_I), list(buffer_J), list(buffer_V)
 322
 323    def to_list(self):
 324        """
 325        Read matrix data as a python lists of tuples where key and value stored together.
 326
 327        >>> M = Matrix.from_lists([1, 2, 3, 3], [0, 1, 0, 3], [-1, -4, 4, 2], (4, 4), INT)
 328        >>> print(M.to_list())
 329        '
 330            [(1, 0, -1), (2, 1, -4), (3, 0, 4), (3, 3, 2)]
 331        '
 332
 333        :return: List of matrix entries as (I, J, V).
 334        """
 335
 336        I, J, V = self.to_lists()
 337        return list(zip(I, J, V))
 338
 339    def to_string(self, format_string="{:>%s}", width=2, precision=2, skip_value=0, cell_sep=""):
 340        """
 341        Generate from a vector a pretty string for a display.
 342
 343        >>> M = Matrix.from_lists([1, 2, 3], [1, 2, 3], [-1, 5, 10], (4, 4), INT)
 344        >>> print(M)
 345        '
 346            0 1 2 3
 347         0| . . . .|  0
 348         1| .-1 . .|  1
 349         2| . . 5 .|  2
 350         3| . . .10|  3
 351            0 1 2 3
 352        '
 353
 354        :param format_string: str.
 355            How to format single value.
 356
 357        :param width: int.
 358            Integral part length.
 359
 360        :param precision: int.
 361            Fractional part length.
 362
 363        :param skip_value: any.
 364            Value to skip and not display
 365
 366        :param cell_sep: str.
 367            How to separate values in a row.
 368
 369        :return: Pretty string with vector content.
 370        """
 371
 372        format_string = format_string % width
 373        header = format_string.format("") + " " + "".join(format_string.format(i) for i in range(self.n_cols))
 374
 375        result = header + "\n"
 376        for row in range(self.n_rows):
 377            result += format_string.format(row) + "|"
 378            for col in range(self.n_cols):
 379                value = self.get(row, col)
 380                value = value if value != skip_value else "."
 381                result += cell_sep + self.dtype.format_value(value, width, precision)
 382            result += "|  " + str(row) + "\n"
 383        result += header
 384
 385        return result
 386
 387    @classmethod
 388    def from_lists(cls, I: list, J: list, V: list, shape, dtype=INT):
 389        """
 390        Build matrix from a list of sorted keys and associated values to store in matrix.
 391        List with keys `I` and `J` must index entries from range [0, shape-1] and all keys must be sorted.
 392
 393        >>> M = Matrix.from_lists([1, 2, 3], [1, 2, 3], [-1, 5, 10], (4, 4), INT)
 394        >>> print(M)
 395        '
 396            0 1 2 3
 397         0| . . . .|  0
 398         1| .-1 . .|  1
 399         2| . . 5 .|  2
 400         3| . . .10|  3
 401            0 1 2 3
 402        '
 403
 404        :param I: list[UINT].
 405             List with integral keys of entries.
 406
 407        :param J: list[UINT].
 408             List with integral keys of entries.
 409
 410        :param V: list[Type].
 411             List with values to store in the matrix.
 412
 413        :param shape: tuple.
 414             Matrix size.
 415
 416        :param dtype:
 417             Type of storage parametrization for matrix.
 418
 419        :return: Created matrix filled with values.
 420        """
 421
 422        assert len(I) == len(V)
 423        assert len(J) == len(V)
 424        assert shape
 425        assert shape[0] > 0 and shape[1] > 0
 426
 427        if not I:
 428            return Matrix(shape, dtype)
 429
 430        count = len(I)
 431
 432        c_I = (UINT._c_type * count)(*I)
 433        c_J = (UINT._c_type * count)(*J)
 434        c_V = (dtype._c_type * count)(*V)
 435
 436        view_I = MemView(buffer=c_I, size=ctypes.sizeof(c_I), mutable=False)
 437        view_J = MemView(buffer=c_J, size=ctypes.sizeof(c_J), mutable=False)
 438        view_V = MemView(buffer=c_V, size=ctypes.sizeof(c_V), mutable=False)
 439
 440        M = Matrix(shape=shape, dtype=dtype)
 441        M.build(view_I, view_J, view_V)
 442
 443        return M
 444
 445    @classmethod
 446    def rand(cls, shape, dtype=INT, density=0.1, seed=None, dist=(0, 1)):
 447        """
 448        Creates new matrix of desired type and shape and fills its content
 449        with random values, generated using specified distribution.
 450
 451        >>> M = Matrix.rand((4, 4), INT, density=0.3, dist=[0, 10])
 452        >>> print(M)
 453        '
 454            0 1 2 3
 455         0| . 4 . 5|  0
 456         1| . 7 . .|  1
 457         2| . . . .|  2
 458         3| . . . 2|  3
 459            0 1 2 3
 460        '
 461
 462        :param shape: tuple.
 463            Size of the matrix (number of values).
 464
 465        :param dtype: optional: Type. default: INT.
 466            Type of values matrix will have.
 467
 468        :param density: optional: float. default: 0.1.
 469            Density of matrix or how many entries to generate.
 470
 471        :param seed: optional: int. default: None.
 472            Optional seed to randomize generator.
 473
 474        :param dist: optional: tuple. default: [0,1].
 475            Optional distribution for uniform generation of values.
 476
 477        :return: Created matrix filled with values.
 478        """
 479
 480        if seed is not None:
 481            rnd.seed(seed)
 482
 483        keys = sorted(list({(rnd.randint(0, shape[0] - 1), rnd.randint(0, shape[1] - 1))
 484                            for _ in range(int(shape[0] * shape[1] * density))}))
 485
 486        I = [k[0] for k in keys]
 487        J = [k[1] for k in keys]
 488        count = len(keys)
 489
 490        if dtype is INT:
 491            V = [rnd.randint(dist[0], dist[1]) for i in range(count)]
 492        elif dtype is UINT:
 493            V = [rnd.randint(dist[0], dist[1]) for i in range(count)]
 494        elif dtype is FLOAT:
 495            V = [rnd.uniform(dist[0], dist[1]) for i in range(count)]
 496        else:
 497            raise Exception("unknown type")
 498
 499        return cls.from_lists(I, J, V, shape=shape, dtype=dtype)
 500
 501    @classmethod
 502    def dense(cls, shape, dtype=INT, fill_value=0):
 503        """
 504        Creates new dense matrix of specified shape and fills with desired value.
 505
 506        >>> M = Matrix.dense((3, 4), INT, 2)
 507        >>> print(M)
 508        '
 509            0 1 2 3
 510         0| 2 2 2 2|  0
 511         1| 2 2 2 2|  1
 512         2| 2 2 2 2|  2
 513            0 1 2 3
 514        '
 515
 516        :param shape: 2-tuple.
 517            Size of the matrix.
 518
 519        :param dtype: optional: Type. default: INT.
 520            Type of values matrix will have.
 521
 522        :param fill_value: optional: any. default: 0.
 523            Optional value to fill with.
 524
 525        :return: Matrix filled with value.
 526        """
 527
 528        from .bridge import FormatMatrix
 529
 530        M = Matrix(shape, dtype)
 531        M.set_format(FormatMatrix.CPU_LIL)
 532
 533        for i in range(shape[0]):
 534            for j in range(shape[1]):
 535                M.set(i, j, fill_value)
 536
 537        return M
 538
 539    @classmethod
 540    def diag(cls, shape, dtype=INT, diag_value=1):
 541        """
 542        Diagonal matrix of desired shape and desired fill value on diagonal.
 543
 544        >>> M = Matrix.diag((5, 5), INT, -1)
 545        >>> print(M)
 546        '
 547            0 1 2 3 4
 548         0|-1 . . . .|  0
 549         1| .-1 . . .|  1
 550         2| . .-1 . .|  2
 551         3| . . .-1 .|  3
 552         4| . . . .-1|  4
 553            0 1 2 3 4
 554        '
 555
 556        :param shape: 2-tuple.
 557            Size of the matrix.
 558
 559        :param dtype: optional: Type. default: INT.
 560            Type of values matrix will have.
 561
 562        :param diag_value: optional: any. default: 1.
 563            Optional value to fill the diagonal with.
 564
 565        :return: Matrix with main diagonal filled with value.
 566        """
 567
 568        M = Matrix(shape, dtype)
 569
 570        for i in range(min(shape[0], shape[1])):
 571            M.set(i, i, diag_value)
 572
 573        return M
 574
 575    def mxm(self, M, op_mult, op_add, out=None, init=None, desc=None):
 576        """
 577        General sparse-matrix by sparse-matrix product.
 578
 579        Generate left operand matrix of shape 3x5 for product.
 580        >>> M = Matrix.from_lists([0, 1, 2, 2], [1, 2, 0, 4], [1, 2, 3, 4], (3, 5), INT)
 581        >>> print(M)
 582        '
 583            0 1 2 3 4
 584         0| . 1 . . .|  0
 585         1| . . 2 . .|  1
 586         2| 3 . . . 4|  2
 587            0 1 2 3 4
 588        '
 589
 590        Generate right operand matrix of shape 5x4 for product, num of rows must match.
 591        >>> N = Matrix.from_lists([0, 1, 2, 3], [2, 0, 1, 3], [2, 3, 4, 5], (5, 4), INT)
 592        >>> print(N)
 593        '
 594            0 1 2 3
 595         0| . . 2 .|  0
 596         1| 3 . . .|  1
 597         2| . 4 . .|  2
 598         3| . . . 5|  3
 599         4| . . . .|  4
 600            0 1 2 3
 601        '
 602
 603        Evaluate product using respective element-wise operations.
 604        >>> R = M.mxm(N, INT.MULT, INT.PLUS)
 605        >>> print(R)
 606        '
 607            0 1 2 3
 608         0| 3 . . .|  0
 609         1| . 8 . .|  1
 610         2| . . 6 .|  2
 611            0 1 2 3
 612        '
 613
 614        :param M: Matrix.
 615            Matrix for a product.
 616
 617        :param op_mult: OpBinary.
 618            Element-wise binary operator for matrix vector elements product.
 619
 620        :param op_add: OpBinary.
 621            Element-wise binary operator for matrix vector products sum.
 622
 623        :param out: optional: Matrix: default: None.
 624            Optional matrix to store result of product.
 625
 626        :param init: optional: Scalar: default: 0.
 627            Optional neutral init value for reduction.
 628
 629        :param desc: optional: Descriptor. default: None.
 630            Optional descriptor object to configure the execution.
 631
 632        :return: Matrix with result.
 633        """
 634
 635        if out is None:
 636            out = Matrix(shape=(self.n_rows, M.n_cols), dtype=self.dtype)
 637        if init is None:
 638            init = Scalar(dtype=self.dtype, value=0)
 639
 640        assert M
 641        assert out
 642        assert init
 643        assert out.dtype == self.dtype
 644        assert M.dtype == self.dtype
 645        assert init.dtype == self.dtype
 646        assert out.n_rows == self.n_rows
 647        assert out.n_cols == M.n_cols
 648        assert self.n_cols == M.n_rows
 649
 650        check(backend().spla_Exec_mxm(out.hnd, self.hnd, M.hnd,
 651                                      op_mult.hnd, op_add.hnd,
 652                                      init.hnd, self._get_desc(desc), self._get_task(None)))
 653
 654        return out
 655
 656    def mxmT(self, mask, M, op_mult, op_add, op_select, out=None, init=None, desc=None):
 657        """
 658        Masked sparse-matrix by sparse-matrix^T (transposed) product with sparse-mask.
 659
 660        Generate left operand matrix of shape 3x5 for product.
 661        >>> M = Matrix.from_lists([0, 1, 2, 2], [1, 2, 0, 4], [1, 2, 3, 4], (3, 5), INT)
 662        >>> print(M)
 663        '
 664            0 1 2 3 4
 665         0| . 1 . . .|  0
 666         1| . . 2 . .|  1
 667         2| 3 . . . 4|  2
 668            0 1 2 3 4
 669        '
 670
 671        Generate right operand matrix of shape 4x5 for product, since transposed only num of columns must match.
 672        >>> N = Matrix.from_lists([0, 1, 2, 3], [1, 2, 0, 3], [2, 3, 4, 5], (4, 5), INT)
 673        >>> print(N)
 674        '
 675            0 1 2 3 4
 676         0| . 2 . . .|  0
 677         1| . . 3 . .|  1
 678         2| 4 . . . .|  2
 679         3| . . . 5 .|  3
 680            0 1 2 3 4
 681        '
 682
 683        Generate mask of interested us values of shape 3x4 where dim is num of rows from `M` and `N`.
 684        >>> mask = Matrix.dense((3, 4), INT, fill_value=1)
 685        >>> print(mask)
 686        '
 687            0 1 2 3
 688         0| 1 1 1 1|  0
 689         1| 1 1 1 1|  1
 690         2| 1 1 1 1|  2
 691            0 1 2 3
 692        '
 693
 694        Evaluate product for all values using respective select operation.
 695        >>> R = M.mxmT(mask, N, INT.MULT, INT.PLUS, INT.GTZERO)
 696        >>> print(R)
 697        '
 698            0 1 2 3
 699         0| 2 . . .|  0
 700         1| . 6 . .|  1
 701         2| . .12 .|  2
 702            0 1 2 3
 703        '
 704
 705        Evaluate the same product but disable by mask using falsified predicate.
 706        >>> R = M.mxmT(mask, N, INT.MULT, INT.PLUS, INT.EQZERO)
 707        >>> print(R)
 708        '
 709            0 1 2 3
 710         0| . . . .|  0
 711         1| . . . .|  1
 712         2| . . . .|  2
 713            0 1 2 3
 714        '
 715
 716        :param mask: Matrix.
 717            Matrix to select for which values to compute product.
 718
 719        :param M: Matrix.
 720            Matrix for a product.
 721
 722        :param op_mult: OpBinary.
 723            Element-wise binary operator for matrix vector elements product.
 724
 725        :param op_add: OpBinary.
 726            Element-wise binary operator for matrix vector products sum.
 727
 728        :param op_select: OpSelect.
 729            Selection op to filter mask.
 730
 731        :param out: optional: Matrix: default: None.
 732            Optional matrix to store result of product.
 733
 734        :param init: optional: Scalar: default: 0.
 735            Optional neutral init value for reduction.
 736
 737        :param desc: optional: Descriptor. default: None.
 738            Optional descriptor object to configure the execution.
 739
 740        :return: Matrix with result.
 741        """
 742
 743        if out is None:
 744            out = Matrix(shape=mask.shape, dtype=self.dtype)
 745        if init is None:
 746            init = Scalar(dtype=self.dtype, value=0)
 747
 748        assert M
 749        assert out
 750        assert init
 751        assert mask
 752        assert out.dtype == self.dtype
 753        assert M.dtype == self.dtype
 754        assert mask.dtype == self.dtype
 755        assert init.dtype == self.dtype
 756        assert out.n_rows == self.n_rows
 757        assert out.n_cols == M.n_rows
 758        assert self.n_cols == M.n_cols
 759        assert mask.shape == out.shape
 760
 761        check(backend().spla_Exec_mxmT_masked(out.hnd, mask.hnd, self.hnd, M.hnd,
 762                                              op_mult.hnd, op_add.hnd, op_select.hnd,
 763                                              init.hnd, self._get_desc(desc), self._get_task(None)))
 764
 765        return out
 766
 767    def kron(self, M, op_mult, out=None, desc=None):
 768        """
 769        Kronecker product of two sparse matrices.
 770
 771        Generate two matrices, sparse with different values and dense with 1.
 772        >>> A = Matrix.from_lists([0, 1, 2], [1, 2, 0], [2, 3, 4], (3, 3), INT)
 773        >>> B = Matrix.dense((3, 3), INT, 1)
 774
 775        Evaluate product with default `mutl` and show result.
 776        >>> print(A.kron(B, op_mult=INT.MULT))
 777        '
 778            0 1 2 3 4 5 6 7 8
 779         0| . . . 2 2 2 . . .|  0
 780         1| . . . 2 2 2 . . .|  1
 781         2| . . . 2 2 2 . . .|  2
 782         3| . . . . . . 3 3 3|  3
 783         4| . . . . . . 3 3 3|  4
 784         5| . . . . . . 3 3 3|  5
 785         6| 4 4 4 . . . . . .|  6
 786         7| 4 4 4 . . . . . .|  7
 787         8| 4 4 4 . . . . . .|  8
 788            0 1 2 3 4 5 6 7 8
 789        '
 790
 791        The same matrices but order is changed gives a bit of different result.
 792        >>> print(B.kron(A, op_mult=INT.MULT))
 793        '
 794            0 1 2 3 4 5 6 7 8
 795         0| . 2 . . 2 . . 2 .|  0
 796         1| . . 3 . . 3 . . 3|  1
 797         2| 4 . . 4 . . 4 . .|  2
 798         3| . 2 . . 2 . . 2 .|  3
 799         4| . . 3 . . 3 . . 3|  4
 800         5| 4 . . 4 . . 4 . .|  5
 801         6| . 2 . . 2 . . 2 .|  6
 802         7| . . 3 . . 3 . . 3|  7
 803         8| 4 . . 4 . . 4 . .|  8
 804            0 1 2 3 4 5 6 7 8
 805        '
 806
 807        Generate diagonal matrix and dense (not square).
 808        >>> A = Matrix.diag((3, 3), INT, 1)
 809        >>> B = Matrix.dense((2, 4), INT, 1)
 810
 811        Eval product with `plus` operation instead.
 812        >>> print(A.kron(B, op_mult=INT.PLUS).to_string(width=3))
 813        '
 814              0  1  2  3  4  5  6  7  8  9 10 11
 815          0|  2  2  2  2  .  .  .  .  .  .  .  .|  0
 816          1|  2  2  2  2  .  .  .  .  .  .  .  .|  1
 817          2|  .  .  .  .  2  2  2  2  .  .  .  .|  2
 818          3|  .  .  .  .  2  2  2  2  .  .  .  .|  3
 819          4|  .  .  .  .  .  .  .  .  2  2  2  2|  4
 820          5|  .  .  .  .  .  .  .  .  2  2  2  2|  5
 821              0  1  2  3  4  5  6  7  8  9 10 11
 822        '
 823
 824        :param M: Matrix.
 825            Right matrix for product.
 826
 827        :param op_mult: OpBinary.
 828            Element-wise binary operator for matrix elements product.
 829
 830        :param out: optional: Matrix: default: None.
 831            Optional matrix to store result of product.
 832
 833        :param desc: optional: Descriptor. default: None.
 834            Optional descriptor object to configure the execution.
 835
 836        :return: Matrix with result.
 837        """
 838
 839        if out is None:
 840            out = Matrix(shape=(self.n_rows * M.n_rows, self.n_cols * M.n_cols), dtype=self.dtype)
 841
 842        assert M
 843        assert out
 844        assert M.dtype == self.dtype
 845        assert out.dtype == self.dtype
 846        assert out.n_rows == self.n_rows * M.n_rows
 847        assert out.n_cols == self.n_cols * M.n_cols
 848
 849        check(backend().spla_Exec_kron(out.hnd, self.hnd, M.hnd, op_mult.hnd,
 850                                       self._get_desc(desc), self._get_task(None)))
 851
 852        return out
 853
 854    def kronpow(self, exponent, op_mult=None):
 855        """
 856        Kronecker's expansion, evaluate product for matrix itself giving nice pattern.
 857        Useful operation for synthetic graphs generation.
 858
 859        Source 2x2 pattern matrix for expansion.
 860        >>> M = Matrix.from_lists([0, 0, 1], [0, 1, 1], [1, 2, 3], (2, 2), INT)
 861
 862        Exponent with 0 is the identinty matrix of the source shape.
 863        >>> print(M.kronpow(0))
 864        '
 865            0 1
 866         0| 1 .|  0
 867         1| . 1|  1
 868            0 1
 869        '
 870
 871        Exmponent with 1 is the source matrix.
 872        >>> print(M.kronpow(1))
 873        '
 874            0 1
 875         0| 1 2|  0
 876         1| . 3|  1
 877            0 1
 878        '
 879
 880        Exmponent with 2 it is kron product of self by itself.
 881        >>> print(M.kronpow(2))
 882        '
 883            0 1 2 3
 884         0| 1 2 2 4|  0
 885         1| . 3 . 6|  1
 886         2| . . 3 6|  2
 887         3| . . . 9|  3
 888            0 1 2 3
 889        '
 890
 891        Exmponent with 3 it is effectively prev result matrix kron by itself.
 892        >>> print(M.kronpow(3).to_string(width=3))
 893        '
 894              0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
 895          0|  1  2  2  4  2  4  4  8  2  4  4  8  4  8  8 16|  0
 896          1|  .  3  .  6  .  6  . 12  .  6  . 12  . 12  . 24|  1
 897          2|  .  .  3  6  .  .  6 12  .  .  6 12  .  . 12 24|  2
 898          3|  .  .  .  9  .  .  . 18  .  .  . 18  .  .  . 36|  3
 899          4|  .  .  .  .  3  6  6 12  .  .  .  .  6 12 12 24|  4
 900          5|  .  .  .  .  .  9  . 18  .  .  .  .  . 18  . 36|  5
 901          6|  .  .  .  .  .  .  9 18  .  .  .  .  .  . 18 36|  6
 902          7|  .  .  .  .  .  .  . 27  .  .  .  .  .  .  . 54|  7
 903          8|  .  .  .  .  .  .  .  .  3  6  6 12  6 12 12 24|  8
 904          9|  .  .  .  .  .  .  .  .  .  9  . 18  . 18  . 36|  9
 905         10|  .  .  .  .  .  .  .  .  .  .  9 18  .  . 18 36|  10
 906         11|  .  .  .  .  .  .  .  .  .  .  . 27  .  .  . 54|  11
 907         12|  .  .  .  .  .  .  .  .  .  .  .  .  9 18 18 36|  12
 908         13|  .  .  .  .  .  .  .  .  .  .  .  .  . 27  . 54|  13
 909         14|  .  .  .  .  .  .  .  .  .  .  .  .  .  . 27 54|  14
 910         15|  .  .  .  .  .  .  .  .  .  .  .  .  .  .  . 81|  15
 911              0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
 912        '
 913
 914        :param exponent: int.
 915            Power to evaluate, must be >= 0.
 916
 917        :param op_mult: optional: OpBinary. default: None.
 918            Optional operator for `kron`, by default used `mult`.
 919
 920        :return: Kronecker power of a matrix.
 921        """
 922
 923        assert exponent >= 0
 924
 925        if op_mult is None:
 926            op_mult = self.dtype.MULT
 927
 928        if exponent == 0:
 929            return Matrix.diag(shape=self.shape, dtype=self.dtype)
 930        if exponent == 1:
 931            return self
 932
 933        result = self
 934
 935        for _ in range(exponent - 1):
 936            result = result.kron(result, op_mult)
 937
 938        return result
 939
 940    def mxv(self, mask, v, op_mult, op_add, op_select, out=None, init=None, desc=None):
 941        """
 942        Masked sparse-matrix by a dense vector product with dense mask.
 943
 944        >>> M = Matrix.from_lists([0, 1, 2, 2, 3], [1, 2, 0, 3, 2], [1, 2, 3, 4, 5], (4, 4), INT)
 945        >>> v = Vector.from_lists([2], [1], 4, INT)
 946        >>> mask = Vector.from_lists(list(range(4)), [1] * 4, 4, INT)
 947        >>> print(M.mxv(mask, v, INT.LAND, INT.LOR, INT.GTZERO))
 948        '
 949         0| .
 950         1| 1
 951         2| .
 952         3| 1
 953        '
 954
 955        >>> M = Matrix.from_lists([0, 1, 2], [1, 2, 0], [1, 2, 3], (4, 4), INT)
 956        >>> v = Vector.from_lists([0, 1, 2], [2, 3, 4], 4, INT)
 957        >>> mask = Vector.from_lists(list(range(4)), [0] * 4, 4, INT)
 958        >>> print(M.mxv(mask, v, INT.MULT, INT.PLUS, INT.EQZERO))
 959        '
 960         0| 3
 961         1| 8
 962         2| 6
 963         3| .
 964        '
 965
 966        :param mask: Vector.
 967            Vector to select for which values to compute product.
 968
 969        :param v: Vector.
 970            Vector for a product.
 971
 972        :param op_mult: OpBinary.
 973            Element-wise binary operator for matrix vector elements product.
 974
 975        :param op_add: OpBinary.
 976            Element-wise binary operator for matrix vector products sum.
 977
 978        :param op_select: OpSelect.
 979            Selection op to filter mask.
 980
 981        :param out: optional: Vector: default: None.
 982            Optional vector to store result of product.
 983
 984        :param init: optional: Scalar: default: 0.
 985            Optional neutral init value for reduction.
 986
 987        :param desc: optional: Descriptor. default: None.
 988            Optional descriptor object to configure the execution.
 989
 990        :return: Vector with result.
 991        """
 992
 993        from .vector import Vector
 994
 995        if out is None:
 996            out = Vector(shape=self.n_rows, dtype=self.dtype)
 997        if init is None:
 998            init = Scalar(dtype=self.dtype, value=0)
 999
1000        assert v
1001        assert out
1002        assert init
1003        assert mask
1004        assert out.dtype == self.dtype
1005        assert v.dtype == self.dtype
1006        assert mask.dtype == self.dtype
1007        assert init.dtype == self.dtype
1008        assert out.n_rows == self.n_rows
1009        assert mask.n_rows == self.n_rows
1010        assert v.n_rows == self.n_cols
1011
1012        check(backend().spla_Exec_mxv_masked(out.hnd, mask.hnd, self.hnd, v.hnd,
1013                                             op_mult.hnd, op_add.hnd, op_select.hnd,
1014                                             init.hnd, self._get_desc(desc), self._get_task(None)))
1015
1016        return out
1017
1018    def eadd(self, op_add, M, out=None, desc=None):
1019        """
1020        Element-wise addition with other matrix.
1021
1022        Element-wise addition takes the set union of the patterns of A and B and applies a binary operator
1023        for all entries that appear in the set intersection of the patterns of A and B, preserving values
1024        without the pair unchanged in the result.
1025
1026        >>> A = Matrix.from_lists([0, 1, 2], [1, 0, 2], [1, 2, 3], (3, 3), INT)
1027        >>> B = Matrix.from_lists([0, 1, 2], [1, 2, 2], [4, 5, 6], (3, 3), INT)
1028        >>> print(A.eadd(INT.PLUS, B))
1029        '
1030            0 1 2
1031         0| . 5 .|  0
1032         1| 2 . 5|  1
1033         2| . . 9|  2
1034            0 1 2
1035        '
1036
1037        >>> M = Matrix.from_lists([0, 0, 1], [0, 1, 1], [1, 2, 3], (2, 2), INT)
1038        >>> print(M.eadd(INT.MULT, M.transpose()))
1039        '
1040            0 1
1041         0| 1 2|  0
1042         1| 2 9|  1
1043            0 1
1044        '
1045
1046        :param op_add: OpBinary.
1047            Binary element-wise operation to apply.
1048
1049        :param M: Matrix.
1050            Matrix for operation on the right side.
1051
1052        :param out: optional: Matrix. default: None.
1053            Optional matrix to store result.
1054
1055        :param desc: optional: Descriptor. default: None.
1056            Optional descriptor object to configure the execution.
1057
1058        :return: Matrix with a result.
1059        """
1060
1061        if out is None:
1062            out = Matrix(shape=self.shape, dtype=self.dtype)
1063
1064        assert M
1065        assert out
1066        assert op_add
1067        assert self.shape == M.shape
1068        assert self.shape == out.shape
1069        assert self.dtype == M.dtype
1070        assert self.dtype == out.dtype
1071
1072        check(backend().spla_Exec_m_eadd(out.hnd, self.hnd, M.hnd, op_add.hnd,
1073                                         self._get_desc(desc), self._get_task(None)))
1074
1075        return out
1076
1077    def emult(self, op_mult, M, out=None, desc=None):
1078        """
1079        Element-wise multiplication with other matrix.
1080
1081        Element-wise multiplication takes the set intersection of the patterns of A and B and applies a binary operator
1082        for all entries that appear in the set intersection of the patterns of A and B, removing the values without
1083        the pair from the result.
1084
1085        >>> A = Matrix.from_lists([0, 1, 2], [1, 0, 2], [1, 2, 3], (3, 3), INT)
1086        >>> B = Matrix.from_lists([0, 1, 2], [1, 2, 2], [4, 5, 6], (3, 3), INT)
1087        >>> print(A.emult(INT.PLUS, B))
1088        '
1089            0 1 2
1090         0| . 5 .|  0
1091         1| . . .|  1
1092         2| . . 9|  2
1093            0 1 2
1094        '
1095
1096        >>> M = Matrix.from_lists([0, 0, 1], [0, 1, 1], [1, 2, 3], (2, 2), INT)
1097        >>> print(M.emult(INT.MULT, M.transpose()))
1098        '
1099            0 1
1100         0| 1 .|  0
1101         1| . 9|  1
1102            0 1
1103        '
1104
1105        :param op_mult: OpBinary.
1106            Binary element-wise operation to apply.
1107
1108        :param M: Matrix.
1109            Matrix for operation on the right side.
1110
1111        :param out: optional: Matrix. default: None.
1112            Optional matrix to store result.
1113
1114        :param desc: optional: Descriptor. default: None.
1115            Optional descriptor object to configure the execution.
1116
1117        :return: Matrix with a result.
1118        """
1119
1120        if out is None:
1121            out = Matrix(shape=self.shape, dtype=self.dtype)
1122
1123        assert M
1124        assert out
1125        assert op_mult
1126        assert self.shape == M.shape
1127        assert self.shape == out.shape
1128        assert self.dtype == M.dtype
1129        assert self.dtype == out.dtype
1130
1131        check(backend().spla_Exec_m_emult(out.hnd, self.hnd, M.hnd, op_mult.hnd,
1132                                          self._get_desc(desc), self._get_task(None)))
1133
1134        return out
1135
1136    def reduce_by_row(self, op_reduce, out=None, init=None, desc=None):
1137        """
1138        Reduce matrix elements by a row to a column vector.
1139
1140        >>> M = Matrix.from_lists([0, 2, 2, 3], [0, 1, 3, 2], [1, 2, 3, 4], (4, 4), INT)
1141        >>> print(M.reduce_by_row(INT.PLUS))
1142        '
1143         0| 1
1144         1| .
1145         2| 5
1146         3| 4
1147        '
1148
1149        :param op_reduce: OpBinary.
1150            Binary operation to apply for reduction of matrix elements.
1151
1152        :param out: optional: Vector: default: None.
1153            Optional vector to store result of reduction.
1154
1155        :param init: optional: Scalar: default: 0.
1156            Optional neutral init value for reduction.
1157
1158        :param desc: optional: Descriptor. default: None.
1159            Optional descriptor object to configure the execution.
1160
1161        :return: Vector with result.
1162        """
1163
1164        from .vector import Vector
1165
1166        if out is None:
1167            out = Vector(shape=self.n_rows, dtype=self.dtype)
1168        if init is None:
1169            init = Scalar(dtype=self.dtype, value=0)
1170
1171        assert out
1172        assert init
1173        assert out.n_rows == self.n_rows
1174        assert out.dtype == self.dtype
1175        assert init.dtype == self.dtype
1176
1177        check(backend().spla_Exec_m_reduce_by_row(out.hnd, self.hnd, op_reduce.hnd, init.hnd,
1178                                                  self._get_desc(desc), self._get_task(None)))
1179
1180        return out
1181
1182    def reduce_by_column(self, op_reduce, out=None, init=None, desc=None):
1183        """
1184        Reduce matrix elements by a column to a row vector.
1185
1186        >>> M = Matrix.from_lists([0, 1, 2, 3], [0, 3, 3, 2], [1, 2, 3, 4], (4, 4), INT)
1187        >>> print(M.reduce_by_column(INT.PLUS))
1188        '
1189         0| 1
1190         1| .
1191         2| 4
1192         3| 5
1193        '
1194
1195        :param op_reduce: OpBinary.
1196            Binary operation to apply for reduction of matrix elements.
1197
1198        :param out: optional: Vector: default: None.
1199            Optional vector to store result of reduction.
1200
1201        :param init: optional: Scalar: default: 0.
1202            Optional neutral init value for reduction.
1203
1204        :param desc: optional: Descriptor. default: None.
1205            Optional descriptor object to configure the execution.
1206
1207        :return: Vector with result.
1208        """
1209
1210        from .vector import Vector
1211
1212        if out is None:
1213            out = Vector(shape=self.n_cols, dtype=self.dtype)
1214        if init is None:
1215            init = Scalar(dtype=self.dtype, value=0)
1216
1217        assert out
1218        assert init
1219        assert out.n_rows == self.n_cols
1220        assert out.dtype == self.dtype
1221        assert init.dtype == self.dtype
1222
1223        check(backend().spla_Exec_m_reduce_by_column(out.hnd, self.hnd, op_reduce.hnd, init.hnd,
1224                                                     self._get_desc(desc), self._get_task(None)))
1225
1226        return out
1227
1228    def reduce(self, op_reduce, out=None, init=None, desc=None):
1229        """
1230        Reduce matrix elements.
1231
1232        >>> M = Matrix.from_lists([1, 2, 3, 3], [0, 1, 0, 3], [-1, -4, 4, 2], (4, 4), INT)
1233        >>> print(M.reduce(op_reduce=INT.MULT, init=Scalar(INT, 1)))
1234        '
1235            32
1236        '
1237
1238        :param op_reduce: OpBinary.
1239            Binary operation to apply for reduction of matrix elements.
1240
1241        :param out: optional: Scalar: default: 0.
1242            Optional scalar to store result of reduction.
1243
1244        :param init: optional: Scalar: default: 0.
1245            Optional neutral init value for reduction.
1246
1247        :param desc: optional: Descriptor. default: None.
1248            Optional descriptor object to configure the execution.
1249
1250        :return: Scalar value with result.
1251        """
1252
1253        if out is None:
1254            out = Scalar(dtype=self.dtype)
1255        if init is None:
1256            init = Scalar(dtype=self.dtype, value=0)
1257
1258        assert out.dtype == self.dtype
1259        assert init.dtype == self.dtype
1260
1261        check(backend().spla_Exec_m_reduce(out.hnd, init.hnd, self.hnd, op_reduce.hnd,
1262                                           self._get_desc(desc), self._get_task(None)))
1263
1264        return out
1265
1266    def transpose(self, out=None, op_apply=None, desc=None):
1267        """
1268        Transpose matrix.
1269
1270        Generate 3x4 matrix with int source data.
1271        >>> M = Matrix.from_lists([0, 1, 2], [3, 2, 0], [-5, 3, 9], (3, 4), INT)
1272        >>> print(M)
1273        '
1274            0 1 2 3
1275         0| . . .-5|  0
1276         1| . . 3 .|  1
1277         2| 9 . . .|  2
1278            0 1 2 3
1279        '
1280
1281        Transpose matrix `M` as usual and print result.
1282        >>> print(M.transpose())
1283        '
1284            0 1 2
1285         0| . . 9|  0
1286         1| . . .|  1
1287         2| . 3 .|  2
1288         3|-5 . .|  3
1289            0 1 2
1290        '
1291
1292        Transpose by map each value to `1`, discarding prev value.
1293        >>> print(M.transpose(op_apply=INT.UONE))
1294        '
1295            0 1 2
1296         0| . . 1|  0
1297         1| . . .|  1
1298         2| . 1 .|  2
1299         3| 1 . .|  3
1300            0 1 2
1301        '
1302
1303        Transpose and apply additive-inverse for each value effectively changing the sign of values.
1304        >>> print(M.transpose(op_apply=INT.AINV))
1305        '
1306            0 1 2
1307         0| . .-9|  0
1308         1| . . .|  1
1309         2| .-3 .|  2
1310         3| 5 . .|  3
1311            0 1 2
1312        '
1313
1314        :param out: optional: Matrix: default: none.
1315            Optional matrix to store result.
1316
1317        :param op_apply: optional: OpUnary. default: None.
1318            Optional unary function to apply on transposition.
1319
1320        :param desc: optional: Descriptor. default: None.
1321            Optional descriptor object to configure the execution.
1322
1323        :return: Transposed matrix.
1324        """
1325
1326        if out is None:
1327            out = Matrix(shape=(self.n_cols, self.n_rows), dtype=self.dtype)
1328        if op_apply is None:
1329            op_apply = self.dtype.IDENTITY
1330
1331        assert out
1332        assert op_apply
1333        assert out.n_rows == self.n_cols
1334        assert out.n_cols == self.n_rows
1335        assert out.dtype == self.dtype
1336
1337        check(backend().spla_Exec_m_transpose(out.hnd, self.hnd, op_apply.hnd,
1338                                              self._get_desc(desc), self._get_task(None)))
1339
1340        return out
1341
1342    def extract_row(self, index, out=None, op_apply=None, desc=None):
1343        """
1344        Extract matrix row.
1345
1346        >>> M = Matrix.from_lists([0, 0, 1, 2], [1, 2, 3, 0], [-1, 1, 2, 3], (3, 4), INT)
1347        >>> print(M)
1348        '
1349            0 1 2 3
1350         0| .-1 1 .|  0
1351         1| . . . 2|  1
1352         2| 3 . . .|  2
1353            0 1 2 3
1354        '
1355
1356        >>> print(M.extract_row(0))
1357        '
1358         0| .
1359         1|-1
1360         2| 1
1361         3| .
1362        '
1363
1364        >>> print(M.extract_row(0, op_apply=INT.AINV))
1365        '
1366         0| .
1367         1| 1
1368         2|-1
1369         3| .
1370        '
1371
1372        :param index: int.
1373            Index of row to extract.
1374
1375        :param out: optional: Vector: default: none.
1376            Optional vector to store result.
1377
1378        :param op_apply: optional: OpUnary. default: None.
1379            Optional unary function to apply on extraction.
1380
1381        :param desc: optional: Descriptor. default: None.
1382            Optional descriptor object to configure the execution.
1383
1384        :return: Vector.
1385        """
1386
1387        from .vector import Vector
1388
1389        if out is None:
1390            out = Vector(shape=self.n_cols, dtype=self.dtype)
1391        if op_apply is None:
1392            op_apply = self.dtype.IDENTITY
1393
1394        assert out
1395        assert op_apply
1396        assert out.dtype == self.dtype
1397        assert out.n_rows == self.n_cols
1398        assert 0 <= index < self.n_rows
1399
1400        check(backend().spla_Exec_m_extract_row(out.hnd, self.hnd, ctypes.c_uint(index), op_apply.hnd,
1401                                                self._get_desc(desc), self._get_task(None)))
1402
1403        return out
1404
1405    def extract_column(self, index, out=None, op_apply=None, desc=None):
1406        """
1407        Extract matrix column.
1408
1409        >>> M = Matrix.from_lists([0, 1, 1, 2], [1, 0, 3, 1], [-1, 1, 2, 3], (3, 4), INT)
1410        >>> print(M)
1411        '
1412            0 1 2 3
1413         0| .-1 . .|  0
1414         1| 1 . . 2|  1
1415         2| . 3 . .|  2
1416            0 1 2 3
1417        '
1418
1419        >>> print(M.extract_column(1))
1420        '
1421         0|-1
1422         1| .
1423         2| 3
1424        '
1425
1426        >>> print(M.extract_column(1, op_apply=INT.AINV))
1427        '
1428         0| 1
1429         1| .
1430         2|-3
1431        '
1432
1433        :param index: int.
1434            Index of column to extract.
1435
1436        :param out: optional: Vector: default: none.
1437            Optional vector to store result.
1438
1439        :param op_apply: optional: OpUnary. default: None.
1440            Optional unary function to apply on extraction.
1441
1442        :param desc: optional: Descriptor. default: None.
1443            Optional descriptor object to configure the execution.
1444
1445        :return: Vector.
1446        """
1447
1448        from .vector import Vector
1449
1450        if out is None:
1451            out = Vector(shape=self.n_rows, dtype=self.dtype)
1452        if op_apply is None:
1453            op_apply = self.dtype.IDENTITY
1454
1455        assert out
1456        assert op_apply
1457        assert out.dtype == self.dtype
1458        assert out.n_rows == self.n_rows
1459        assert 0 <= index < self.n_cols
1460
1461        check(backend().spla_Exec_m_extract_column(out.hnd, self.hnd, ctypes.c_uint(index), op_apply.hnd,
1462                                                   self._get_desc(desc), self._get_task(None)))
1463
1464        return out
1465
1466    def __str__(self):
1467        return self.to_string()
1468
1469    def __iter__(self):
1470        I, J, V = self.to_lists()
1471        return zip(I, J, V)
1472
1473    def _get_desc(self, desc: Descriptor):
1474        return desc.hnd if desc else ctypes.c_void_p(0)
1475
1476    def _get_task(self, task):
1477        return ctypes.POINTER(ctypes.c_void_p)()

Generalized statically-typed sparse storage-invariant matrix primitive.

Notes

Matrix typical usage:

  • Instantiate matrix primitive
  • Build incrementally from yours data source
  • Matrix usage in a sequence of math operations
  • Read-back matrix data to python to analyse results

Steps (2) and (4) requires internal format transformations and possible transfer of data from acc (GPU) side if acceleration was employed in computations. These steps may be very intensive, so you have to avoid them in critical parts of computations. If you need faster data reads, prefer usage of batched reads, where all content of storage read at once.

Details

Matrix class support all spla C API matrix functions. It provides bind functionality as well as new functions/methods for better python user experience.

Matrix internally manages optimal format of stored data. Use hints to force matrix state and format changes.

Matrix optional uses dedicated/integrated GPU to speedup computations using one of built-in OpenCL or CUDA accelerators.

Matrix(shape, dtype=<class 'pyspla.INT'>, hnd=None, label=None)
 76    def __init__(self, shape, dtype=INT, hnd=None, label=None):
 77        """
 78        Creates new matrix of specified type and shape.
 79
 80        >>> M = Matrix((4, 5), INT)
 81        >>> print(M)
 82        '
 83            0 1 2 3 4
 84         0| . . . . .|  0
 85         1| . . . . .|  1
 86         2| . . . . .|  2
 87         3| . . . . .|  3
 88            0 1 2 3 4
 89        '
 90
 91        :param dtype: Type.
 92            Type parametrization of a storage.
 93
 94        :param shape: tuple.
 95            Matrix size (2-dim).
 96
 97        :param hnd: optional: ctypes.c_void_p. default: None.
 98            Optional native handle to retain.
 99
100        :param label: optional: str. default: None.
101            Optional label to assign.
102        """
103
104        super().__init__(None, None)
105
106        assert dtype
107        assert shape
108        assert shape[0] > 0 and shape[1] > 0
109        assert issubclass(dtype, Type)
110
111        self._dtype = dtype
112        self._shape = shape
113
114        if not hnd:
115            hnd = ctypes.c_void_p(0)
116            check(backend().spla_Matrix_make(ctypes.byref(hnd),
117                                             ctypes.c_uint(shape[0]),
118                                             ctypes.c_uint(shape[1]),
119                                             dtype._hnd))
120
121        super().__init__(label, hnd)

Creates new matrix of specified type and shape.

>>> M = Matrix((4, 5), INT)
>>> print(M)
'
    0 1 2 3 4
 0| . . . . .|  0
 1| . . . . .|  1
 2| . . . . .|  2
 3| . . . . .|  3
    0 1 2 3 4
'
Parameters
  • dtype: Type. Type parametrization of a storage.

  • shape: tuple. Matrix size (2-dim).

  • hnd: optional: ctypes.c_void_p. default: None. Optional native handle to retain.

  • label: optional: str. default: None. Optional label to assign.

dtype

Type used for storage parametrization of this container.

>>> M = Matrix((4, 5), INT)
>>> print(M.dtype)
'
    <class 'pyspla.INT'>
'
n_rows

Number of rows in the matrix.

>>> M = Matrix((4, 5), INT)
>>> print(M.n_rows)
'
    4
'
n_cols

Number of cols in the matrix.

>>> M = Matrix((4, 5), INT)
>>> print(M.n_cols)
'
    5
'
shape

2-Tuple with shape of matrix.

>>> M = Matrix((4, 5), INT)
>>> print(M.shape)
'
    (4, 5)
'
def set_format(self, fmt):
176    def set_format(self, fmt):
177        """
178        Instruct container to format internal data with desired storage format.
179        Multiple different formats may be set at same time, data will be duplicated in different formats.
180        If selected data already in a selected format, then nothing to do.
181
182        See `FormatMatrix` enumeration for all supported formats.
183
184        :param fmt: FormatMatrix.
185            One of built-in storage formats to set.
186        """
187
188        check(backend().spla_Matrix_set_format(self.hnd, ctypes.c_int(fmt.value)))

Instruct container to format internal data with desired storage format. Multiple different formats may be set at same time, data will be duplicated in different formats. If selected data already in a selected format, then nothing to do.

See FormatMatrix enumeration for all supported formats.

Parameters
  • fmt: FormatMatrix. One of built-in storage formats to set.
def set(self, i, j, v):
190    def set(self, i, j, v):
191        """
192        Set value at specified index
193
194        >>> M = Matrix((4, 4), INT)
195        >>> M.set(0, 0, -1)
196        >>> M.set(1, 2, 4)
197        >>> M.set(3, 1, 10)
198        >>> print(M)
199        '
200            0 1 2 3
201         0|-1 . . .|  0
202         1| . . 4 .|  1
203         2| . . . .|  2
204         3| .10 . .|  3
205            0 1 2 3
206        '
207
208        :param i: uint.
209            Row index to set.
210
211        :param j: uint.
212            Column index to set.
213
214        :param v: any.
215            Value to set.
216        """
217
218        check(self._dtype._matrix_set(self.hnd, ctypes.c_uint(i), ctypes.c_uint(j), self._dtype._c_type(v)))

Set value at specified index

>>> M = Matrix((4, 4), INT)
>>> M.set(0, 0, -1)
>>> M.set(1, 2, 4)
>>> M.set(3, 1, 10)
>>> print(M)
'
    0 1 2 3
 0|-1 . . .|  0
 1| . . 4 .|  1
 2| . . . .|  2
 3| .10 . .|  3
    0 1 2 3
'
Parameters
  • i: uint. Row index to set.

  • j: uint. Column index to set.

  • v: any. Value to set.

def get(self, i, j):
220    def get(self, i, j):
221        """
222        Get value at specified index.
223
224        >>> M = Matrix.from_lists([1, 2, 3, 3], [0, 1, 0, 3], [-1, -4, 4, 2], (4, 4), INT)
225        >>> print(M.get(1, 0))
226        '
227            -1
228        '
229
230        >>> M = Matrix.from_lists([1, 2, 3, 3], [0, 1, 0, 3], [-1, -4, 4, 2], (4, 4), INT)
231        >>> print(M.get(1, 3))
232        '
233            0
234        '
235
236        :param i: uint.
237            Row index of value to get.
238
239        :param j: uint.
240            Column index of value to get.
241
242        :return: Value.
243        """
244
245        c_value = self._dtype._c_type(0)
246        check(self._dtype._matrix_get(self.hnd, ctypes.c_uint(i), ctypes.c_uint(j), ctypes.byref(c_value)))
247        return self._dtype.cast_value(c_value)

Get value at specified index.

>>> M = Matrix.from_lists([1, 2, 3, 3], [0, 1, 0, 3], [-1, -4, 4, 2], (4, 4), INT)
>>> print(M.get(1, 0))
'
    -1
'
>>> M = Matrix.from_lists([1, 2, 3, 3], [0, 1, 0, 3], [-1, -4, 4, 2], (4, 4), INT)
>>> print(M.get(1, 3))
'
    0
'
Parameters
  • i: uint. Row index of value to get.

  • j: uint. Column index of value to get.

Returns

Value.

def build( self, view_I: pyspla.MemView, view_J: pyspla.MemView, view_V: pyspla.MemView):
249    def build(self, view_I: MemView, view_J: MemView, view_V: MemView):
250        """
251        Builds matrix content from a raw memory view resources.
252
253        :param view_I: MemView.
254            View to keys of matrix to assign.
255
256        :param view_J: MemView.
257            View to keys of matrix to assign.
258
259        :param view_V: MemView.
260            View to actual values to store.
261        """
262
263        assert view_I
264        assert view_J
265        assert view_V
266
267        check(backend().spla_Matrix_build(self.hnd, view_I.hnd, view_J.hnd, view_V.hnd))

Builds matrix content from a raw memory view resources.

Parameters
  • view_I: MemView. View to keys of matrix to assign.

  • view_J: MemView. View to keys of matrix to assign.

  • view_V: MemView. View to actual values to store.

def read(self):
269    def read(self):
270        """
271        Read the content of the matrix as a MemView of I, J and V.
272
273        :return: tuple (MemView, MemView, MemView) objects with view to the matrix keys and matrix values.
274        """
275
276        view_I_hnd = ctypes.c_void_p(0)
277        view_J_hnd = ctypes.c_void_p(0)
278        view_V_hnd = ctypes.c_void_p(0)
279        check(backend().spla_Matrix_read(self.hnd,
280                                         ctypes.byref(view_I_hnd),
281                                         ctypes.byref(view_J_hnd),
282                                         ctypes.byref(view_V_hnd)))
283        return MemView(hnd=view_I_hnd, owner=self), \
284               MemView(hnd=view_J_hnd, owner=self), \
285               MemView(hnd=view_V_hnd, owner=self)

Read the content of the matrix as a MemView of I, J and V.

Returns

tuple (MemView, MemView, MemView) objects with view to the matrix keys and matrix values.

def clear(self):
287    def clear(self):
288        """
289        Clears matrix removing all elements, so it has no values.
290        """
291
292        check(backend().spla_Matrix_clear(self.hnd))

Clears matrix removing all elements, so it has no values.

def to_lists(self):
294    def to_lists(self):
295        """
296        Read matrix data as a python lists of I, J and V.
297
298        >>> M = Matrix.from_lists([1, 2, 3, 3], [0, 1, 0, 3], [-1, -4, 4, 2], (4, 4), INT)
299        >>> print(M.to_lists())
300        '
301            ([1, 2, 3, 3], [0, 1, 0, 3], [-1, -4, 4, 2])
302        '
303
304        :return: Tuple (List, List, List) with the matrix keys and matrix values.
305        """
306
307        I, J, V = self.read()
308        count = int(I.size / ctypes.sizeof(UINT._c_type))
309
310        if count == 0:
311            return [], [], []
312
313        buffer_I = (UINT._c_type * count)()
314        buffer_J = (UINT._c_type * count)()
315        buffer_V = (self._dtype._c_type * count)()
316
317        check(backend().spla_MemView_read(I.hnd, ctypes.c_size_t(0), ctypes.sizeof(buffer_I), buffer_I))
318        check(backend().spla_MemView_read(J.hnd, ctypes.c_size_t(0), ctypes.sizeof(buffer_J), buffer_J))
319        check(backend().spla_MemView_read(V.hnd, ctypes.c_size_t(0), ctypes.sizeof(buffer_V), buffer_V))
320
321        return list(buffer_I), list(buffer_J), list(buffer_V)

Read matrix data as a python lists of I, J and V.

>>> M = Matrix.from_lists([1, 2, 3, 3], [0, 1, 0, 3], [-1, -4, 4, 2], (4, 4), INT)
>>> print(M.to_lists())
'
    ([1, 2, 3, 3], [0, 1, 0, 3], [-1, -4, 4, 2])
'
Returns

Tuple (List, List, List) with the matrix keys and matrix values.

def to_list(self):
323    def to_list(self):
324        """
325        Read matrix data as a python lists of tuples where key and value stored together.
326
327        >>> M = Matrix.from_lists([1, 2, 3, 3], [0, 1, 0, 3], [-1, -4, 4, 2], (4, 4), INT)
328        >>> print(M.to_list())
329        '
330            [(1, 0, -1), (2, 1, -4), (3, 0, 4), (3, 3, 2)]
331        '
332
333        :return: List of matrix entries as (I, J, V).
334        """
335
336        I, J, V = self.to_lists()
337        return list(zip(I, J, V))

Read matrix data as a python lists of tuples where key and value stored together.

>>> M = Matrix.from_lists([1, 2, 3, 3], [0, 1, 0, 3], [-1, -4, 4, 2], (4, 4), INT)
>>> print(M.to_list())
'
    [(1, 0, -1), (2, 1, -4), (3, 0, 4), (3, 3, 2)]
'
Returns

List of matrix entries as (I, J, V).

def to_string( self, format_string='{:>%s}', width=2, precision=2, skip_value=0, cell_sep=''):
339    def to_string(self, format_string="{:>%s}", width=2, precision=2, skip_value=0, cell_sep=""):
340        """
341        Generate from a vector a pretty string for a display.
342
343        >>> M = Matrix.from_lists([1, 2, 3], [1, 2, 3], [-1, 5, 10], (4, 4), INT)
344        >>> print(M)
345        '
346            0 1 2 3
347         0| . . . .|  0
348         1| .-1 . .|  1
349         2| . . 5 .|  2
350         3| . . .10|  3
351            0 1 2 3
352        '
353
354        :param format_string: str.
355            How to format single value.
356
357        :param width: int.
358            Integral part length.
359
360        :param precision: int.
361            Fractional part length.
362
363        :param skip_value: any.
364            Value to skip and not display
365
366        :param cell_sep: str.
367            How to separate values in a row.
368
369        :return: Pretty string with vector content.
370        """
371
372        format_string = format_string % width
373        header = format_string.format("") + " " + "".join(format_string.format(i) for i in range(self.n_cols))
374
375        result = header + "\n"
376        for row in range(self.n_rows):
377            result += format_string.format(row) + "|"
378            for col in range(self.n_cols):
379                value = self.get(row, col)
380                value = value if value != skip_value else "."
381                result += cell_sep + self.dtype.format_value(value, width, precision)
382            result += "|  " + str(row) + "\n"
383        result += header
384
385        return result

Generate from a vector a pretty string for a display.

>>> M = Matrix.from_lists([1, 2, 3], [1, 2, 3], [-1, 5, 10], (4, 4), INT)
>>> print(M)
'
    0 1 2 3
 0| . . . .|  0
 1| .-1 . .|  1
 2| . . 5 .|  2
 3| . . .10|  3
    0 1 2 3
'
Parameters
  • format_string: str. How to format single value.

  • width: int. Integral part length.

  • precision: int. Fractional part length.

  • skip_value: any. Value to skip and not display

  • cell_sep: str. How to separate values in a row.

Returns

Pretty string with vector content.

@classmethod
def from_lists( cls, I: list, J: list, V: list, shape, dtype=<class 'pyspla.INT'>):
387    @classmethod
388    def from_lists(cls, I: list, J: list, V: list, shape, dtype=INT):
389        """
390        Build matrix from a list of sorted keys and associated values to store in matrix.
391        List with keys `I` and `J` must index entries from range [0, shape-1] and all keys must be sorted.
392
393        >>> M = Matrix.from_lists([1, 2, 3], [1, 2, 3], [-1, 5, 10], (4, 4), INT)
394        >>> print(M)
395        '
396            0 1 2 3
397         0| . . . .|  0
398         1| .-1 . .|  1
399         2| . . 5 .|  2
400         3| . . .10|  3
401            0 1 2 3
402        '
403
404        :param I: list[UINT].
405             List with integral keys of entries.
406
407        :param J: list[UINT].
408             List with integral keys of entries.
409
410        :param V: list[Type].
411             List with values to store in the matrix.
412
413        :param shape: tuple.
414             Matrix size.
415
416        :param dtype:
417             Type of storage parametrization for matrix.
418
419        :return: Created matrix filled with values.
420        """
421
422        assert len(I) == len(V)
423        assert len(J) == len(V)
424        assert shape
425        assert shape[0] > 0 and shape[1] > 0
426
427        if not I:
428            return Matrix(shape, dtype)
429
430        count = len(I)
431
432        c_I = (UINT._c_type * count)(*I)
433        c_J = (UINT._c_type * count)(*J)
434        c_V = (dtype._c_type * count)(*V)
435
436        view_I = MemView(buffer=c_I, size=ctypes.sizeof(c_I), mutable=False)
437        view_J = MemView(buffer=c_J, size=ctypes.sizeof(c_J), mutable=False)
438        view_V = MemView(buffer=c_V, size=ctypes.sizeof(c_V), mutable=False)
439
440        M = Matrix(shape=shape, dtype=dtype)
441        M.build(view_I, view_J, view_V)
442
443        return M

Build matrix from a list of sorted keys and associated values to store in matrix. List with keys I and J must index entries from range [0, shape-1] and all keys must be sorted.

>>> M = Matrix.from_lists([1, 2, 3], [1, 2, 3], [-1, 5, 10], (4, 4), INT)
>>> print(M)
'
    0 1 2 3
 0| . . . .|  0
 1| .-1 . .|  1
 2| . . 5 .|  2
 3| . . .10|  3
    0 1 2 3
'
Parameters
  • I: list[UINT]. List with integral keys of entries.

  • J: list[UINT]. List with integral keys of entries.

  • V: list[Type]. List with values to store in the matrix.

  • shape: tuple. Matrix size.

  • dtype: Type of storage parametrization for matrix.

Returns

Created matrix filled with values.

@classmethod
def rand( cls, shape, dtype=<class 'pyspla.INT'>, density=0.1, seed=None, dist=(0, 1)):
445    @classmethod
446    def rand(cls, shape, dtype=INT, density=0.1, seed=None, dist=(0, 1)):
447        """
448        Creates new matrix of desired type and shape and fills its content
449        with random values, generated using specified distribution.
450
451        >>> M = Matrix.rand((4, 4), INT, density=0.3, dist=[0, 10])
452        >>> print(M)
453        '
454            0 1 2 3
455         0| . 4 . 5|  0
456         1| . 7 . .|  1
457         2| . . . .|  2
458         3| . . . 2|  3
459            0 1 2 3
460        '
461
462        :param shape: tuple.
463            Size of the matrix (number of values).
464
465        :param dtype: optional: Type. default: INT.
466            Type of values matrix will have.
467
468        :param density: optional: float. default: 0.1.
469            Density of matrix or how many entries to generate.
470
471        :param seed: optional: int. default: None.
472            Optional seed to randomize generator.
473
474        :param dist: optional: tuple. default: [0,1].
475            Optional distribution for uniform generation of values.
476
477        :return: Created matrix filled with values.
478        """
479
480        if seed is not None:
481            rnd.seed(seed)
482
483        keys = sorted(list({(rnd.randint(0, shape[0] - 1), rnd.randint(0, shape[1] - 1))
484                            for _ in range(int(shape[0] * shape[1] * density))}))
485
486        I = [k[0] for k in keys]
487        J = [k[1] for k in keys]
488        count = len(keys)
489
490        if dtype is INT:
491            V = [rnd.randint(dist[0], dist[1]) for i in range(count)]
492        elif dtype is UINT:
493            V = [rnd.randint(dist[0], dist[1]) for i in range(count)]
494        elif dtype is FLOAT:
495            V = [rnd.uniform(dist[0], dist[1]) for i in range(count)]
496        else:
497            raise Exception("unknown type")
498
499        return cls.from_lists(I, J, V, shape=shape, dtype=dtype)

Creates new matrix of desired type and shape and fills its content with random values, generated using specified distribution.

>>> M = Matrix.rand((4, 4), INT, density=0.3, dist=[0, 10])
>>> print(M)
'
    0 1 2 3
 0| . 4 . 5|  0
 1| . 7 . .|  1
 2| . . . .|  2
 3| . . . 2|  3
    0 1 2 3
'
Parameters
  • shape: tuple. Size of the matrix (number of values).

  • dtype: optional: Type. default: INT. Type of values matrix will have.

  • density: optional: float. default: 0.1. Density of matrix or how many entries to generate.

  • seed: optional: int. default: None. Optional seed to randomize generator.

  • dist: optional: tuple. default: [0,1]. Optional distribution for uniform generation of values.

Returns

Created matrix filled with values.

@classmethod
def dense(cls, shape, dtype=<class 'pyspla.INT'>, fill_value=0):
501    @classmethod
502    def dense(cls, shape, dtype=INT, fill_value=0):
503        """
504        Creates new dense matrix of specified shape and fills with desired value.
505
506        >>> M = Matrix.dense((3, 4), INT, 2)
507        >>> print(M)
508        '
509            0 1 2 3
510         0| 2 2 2 2|  0
511         1| 2 2 2 2|  1
512         2| 2 2 2 2|  2
513            0 1 2 3
514        '
515
516        :param shape: 2-tuple.
517            Size of the matrix.
518
519        :param dtype: optional: Type. default: INT.
520            Type of values matrix will have.
521
522        :param fill_value: optional: any. default: 0.
523            Optional value to fill with.
524
525        :return: Matrix filled with value.
526        """
527
528        from .bridge import FormatMatrix
529
530        M = Matrix(shape, dtype)
531        M.set_format(FormatMatrix.CPU_LIL)
532
533        for i in range(shape[0]):
534            for j in range(shape[1]):
535                M.set(i, j, fill_value)
536
537        return M

Creates new dense matrix of specified shape and fills with desired value.

>>> M = Matrix.dense((3, 4), INT, 2)
>>> print(M)
'
    0 1 2 3
 0| 2 2 2 2|  0
 1| 2 2 2 2|  1
 2| 2 2 2 2|  2
    0 1 2 3
'
Parameters
  • shape: 2-tuple. Size of the matrix.

  • dtype: optional: Type. default: INT. Type of values matrix will have.

  • fill_value: optional: any. default: 0. Optional value to fill with.

Returns

Matrix filled with value.

@classmethod
def diag(cls, shape, dtype=<class 'pyspla.INT'>, diag_value=1):
539    @classmethod
540    def diag(cls, shape, dtype=INT, diag_value=1):
541        """
542        Diagonal matrix of desired shape and desired fill value on diagonal.
543
544        >>> M = Matrix.diag((5, 5), INT, -1)
545        >>> print(M)
546        '
547            0 1 2 3 4
548         0|-1 . . . .|  0
549         1| .-1 . . .|  1
550         2| . .-1 . .|  2
551         3| . . .-1 .|  3
552         4| . . . .-1|  4
553            0 1 2 3 4
554        '
555
556        :param shape: 2-tuple.
557            Size of the matrix.
558
559        :param dtype: optional: Type. default: INT.
560            Type of values matrix will have.
561
562        :param diag_value: optional: any. default: 1.
563            Optional value to fill the diagonal with.
564
565        :return: Matrix with main diagonal filled with value.
566        """
567
568        M = Matrix(shape, dtype)
569
570        for i in range(min(shape[0], shape[1])):
571            M.set(i, i, diag_value)
572
573        return M

Diagonal matrix of desired shape and desired fill value on diagonal.

>>> M = Matrix.diag((5, 5), INT, -1)
>>> print(M)
'
    0 1 2 3 4
 0|-1 . . . .|  0
 1| .-1 . . .|  1
 2| . .-1 . .|  2
 3| . . .-1 .|  3
 4| . . . .-1|  4
    0 1 2 3 4
'
Parameters
  • shape: 2-tuple. Size of the matrix.

  • dtype: optional: Type. default: INT. Type of values matrix will have.

  • diag_value: optional: any. default: 1. Optional value to fill the diagonal with.

Returns

Matrix with main diagonal filled with value.

def mxm(self, M, op_mult, op_add, out=None, init=None, desc=None):
575    def mxm(self, M, op_mult, op_add, out=None, init=None, desc=None):
576        """
577        General sparse-matrix by sparse-matrix product.
578
579        Generate left operand matrix of shape 3x5 for product.
580        >>> M = Matrix.from_lists([0, 1, 2, 2], [1, 2, 0, 4], [1, 2, 3, 4], (3, 5), INT)
581        >>> print(M)
582        '
583            0 1 2 3 4
584         0| . 1 . . .|  0
585         1| . . 2 . .|  1
586         2| 3 . . . 4|  2
587            0 1 2 3 4
588        '
589
590        Generate right operand matrix of shape 5x4 for product, num of rows must match.
591        >>> N = Matrix.from_lists([0, 1, 2, 3], [2, 0, 1, 3], [2, 3, 4, 5], (5, 4), INT)
592        >>> print(N)
593        '
594            0 1 2 3
595         0| . . 2 .|  0
596         1| 3 . . .|  1
597         2| . 4 . .|  2
598         3| . . . 5|  3
599         4| . . . .|  4
600            0 1 2 3
601        '
602
603        Evaluate product using respective element-wise operations.
604        >>> R = M.mxm(N, INT.MULT, INT.PLUS)
605        >>> print(R)
606        '
607            0 1 2 3
608         0| 3 . . .|  0
609         1| . 8 . .|  1
610         2| . . 6 .|  2
611            0 1 2 3
612        '
613
614        :param M: Matrix.
615            Matrix for a product.
616
617        :param op_mult: OpBinary.
618            Element-wise binary operator for matrix vector elements product.
619
620        :param op_add: OpBinary.
621            Element-wise binary operator for matrix vector products sum.
622
623        :param out: optional: Matrix: default: None.
624            Optional matrix to store result of product.
625
626        :param init: optional: Scalar: default: 0.
627            Optional neutral init value for reduction.
628
629        :param desc: optional: Descriptor. default: None.
630            Optional descriptor object to configure the execution.
631
632        :return: Matrix with result.
633        """
634
635        if out is None:
636            out = Matrix(shape=(self.n_rows, M.n_cols), dtype=self.dtype)
637        if init is None:
638            init = Scalar(dtype=self.dtype, value=0)
639
640        assert M
641        assert out
642        assert init
643        assert out.dtype == self.dtype
644        assert M.dtype == self.dtype
645        assert init.dtype == self.dtype
646        assert out.n_rows == self.n_rows
647        assert out.n_cols == M.n_cols
648        assert self.n_cols == M.n_rows
649
650        check(backend().spla_Exec_mxm(out.hnd, self.hnd, M.hnd,
651                                      op_mult.hnd, op_add.hnd,
652                                      init.hnd, self._get_desc(desc), self._get_task(None)))
653
654        return out

General sparse-matrix by sparse-matrix product.

Generate left operand matrix of shape 3x5 for product.

>>> M = Matrix.from_lists([0, 1, 2, 2], [1, 2, 0, 4], [1, 2, 3, 4], (3, 5), INT)
>>> print(M)
'
    0 1 2 3 4
 0| . 1 . . .|  0
 1| . . 2 . .|  1
 2| 3 . . . 4|  2
    0 1 2 3 4
'

Generate right operand matrix of shape 5x4 for product, num of rows must match.

>>> N = Matrix.from_lists([0, 1, 2, 3], [2, 0, 1, 3], [2, 3, 4, 5], (5, 4), INT)
>>> print(N)
'
    0 1 2 3
 0| . . 2 .|  0
 1| 3 . . .|  1
 2| . 4 . .|  2
 3| . . . 5|  3
 4| . . . .|  4
    0 1 2 3
'

Evaluate product using respective element-wise operations.

>>> R = M.mxm(N, INT.MULT, INT.PLUS)
>>> print(R)
'
    0 1 2 3
 0| 3 . . .|  0
 1| . 8 . .|  1
 2| . . 6 .|  2
    0 1 2 3
'
Parameters
  • M: Matrix. Matrix for a product.

  • op_mult: OpBinary. Element-wise binary operator for matrix vector elements product.

  • op_add: OpBinary. Element-wise binary operator for matrix vector products sum.

  • out: optional: Matrix: default: None. Optional matrix to store result of product.

  • init: optional: Scalar: default: 0. Optional neutral init value for reduction.

  • desc: optional: Descriptor. default: None. Optional descriptor object to configure the execution.

Returns

Matrix with result.

def mxmT( self, mask, M, op_mult, op_add, op_select, out=None, init=None, desc=None):
656    def mxmT(self, mask, M, op_mult, op_add, op_select, out=None, init=None, desc=None):
657        """
658        Masked sparse-matrix by sparse-matrix^T (transposed) product with sparse-mask.
659
660        Generate left operand matrix of shape 3x5 for product.
661        >>> M = Matrix.from_lists([0, 1, 2, 2], [1, 2, 0, 4], [1, 2, 3, 4], (3, 5), INT)
662        >>> print(M)
663        '
664            0 1 2 3 4
665         0| . 1 . . .|  0
666         1| . . 2 . .|  1
667         2| 3 . . . 4|  2
668            0 1 2 3 4
669        '
670
671        Generate right operand matrix of shape 4x5 for product, since transposed only num of columns must match.
672        >>> N = Matrix.from_lists([0, 1, 2, 3], [1, 2, 0, 3], [2, 3, 4, 5], (4, 5), INT)
673        >>> print(N)
674        '
675            0 1 2 3 4
676         0| . 2 . . .|  0
677         1| . . 3 . .|  1
678         2| 4 . . . .|  2
679         3| . . . 5 .|  3
680            0 1 2 3 4
681        '
682
683        Generate mask of interested us values of shape 3x4 where dim is num of rows from `M` and `N`.
684        >>> mask = Matrix.dense((3, 4), INT, fill_value=1)
685        >>> print(mask)
686        '
687            0 1 2 3
688         0| 1 1 1 1|  0
689         1| 1 1 1 1|  1
690         2| 1 1 1 1|  2
691            0 1 2 3
692        '
693
694        Evaluate product for all values using respective select operation.
695        >>> R = M.mxmT(mask, N, INT.MULT, INT.PLUS, INT.GTZERO)
696        >>> print(R)
697        '
698            0 1 2 3
699         0| 2 . . .|  0
700         1| . 6 . .|  1
701         2| . .12 .|  2
702            0 1 2 3
703        '
704
705        Evaluate the same product but disable by mask using falsified predicate.
706        >>> R = M.mxmT(mask, N, INT.MULT, INT.PLUS, INT.EQZERO)
707        >>> print(R)
708        '
709            0 1 2 3
710         0| . . . .|  0
711         1| . . . .|  1
712         2| . . . .|  2
713            0 1 2 3
714        '
715
716        :param mask: Matrix.
717            Matrix to select for which values to compute product.
718
719        :param M: Matrix.
720            Matrix for a product.
721
722        :param op_mult: OpBinary.
723            Element-wise binary operator for matrix vector elements product.
724
725        :param op_add: OpBinary.
726            Element-wise binary operator for matrix vector products sum.
727
728        :param op_select: OpSelect.
729            Selection op to filter mask.
730
731        :param out: optional: Matrix: default: None.
732            Optional matrix to store result of product.
733
734        :param init: optional: Scalar: default: 0.
735            Optional neutral init value for reduction.
736
737        :param desc: optional: Descriptor. default: None.
738            Optional descriptor object to configure the execution.
739
740        :return: Matrix with result.
741        """
742
743        if out is None:
744            out = Matrix(shape=mask.shape, dtype=self.dtype)
745        if init is None:
746            init = Scalar(dtype=self.dtype, value=0)
747
748        assert M
749        assert out
750        assert init
751        assert mask
752        assert out.dtype == self.dtype
753        assert M.dtype == self.dtype
754        assert mask.dtype == self.dtype
755        assert init.dtype == self.dtype
756        assert out.n_rows == self.n_rows
757        assert out.n_cols == M.n_rows
758        assert self.n_cols == M.n_cols
759        assert mask.shape == out.shape
760
761        check(backend().spla_Exec_mxmT_masked(out.hnd, mask.hnd, self.hnd, M.hnd,
762                                              op_mult.hnd, op_add.hnd, op_select.hnd,
763                                              init.hnd, self._get_desc(desc), self._get_task(None)))
764
765        return out

Masked sparse-matrix by sparse-matrix^T (transposed) product with sparse-mask.

Generate left operand matrix of shape 3x5 for product.

>>> M = Matrix.from_lists([0, 1, 2, 2], [1, 2, 0, 4], [1, 2, 3, 4], (3, 5), INT)
>>> print(M)
'
    0 1 2 3 4
 0| . 1 . . .|  0
 1| . . 2 . .|  1
 2| 3 . . . 4|  2
    0 1 2 3 4
'

Generate right operand matrix of shape 4x5 for product, since transposed only num of columns must match.

>>> N = Matrix.from_lists([0, 1, 2, 3], [1, 2, 0, 3], [2, 3, 4, 5], (4, 5), INT)
>>> print(N)
'
    0 1 2 3 4
 0| . 2 . . .|  0
 1| . . 3 . .|  1
 2| 4 . . . .|  2
 3| . . . 5 .|  3
    0 1 2 3 4
'

Generate mask of interested us values of shape 3x4 where dim is num of rows from M and N.

>>> mask = Matrix.dense((3, 4), INT, fill_value=1)
>>> print(mask)
'
    0 1 2 3
 0| 1 1 1 1|  0
 1| 1 1 1 1|  1
 2| 1 1 1 1|  2
    0 1 2 3
'

Evaluate product for all values using respective select operation.

>>> R = M.mxmT(mask, N, INT.MULT, INT.PLUS, INT.GTZERO)
>>> print(R)
'
    0 1 2 3
 0| 2 . . .|  0
 1| . 6 . .|  1
 2| . .12 .|  2
    0 1 2 3
'

Evaluate the same product but disable by mask using falsified predicate.

>>> R = M.mxmT(mask, N, INT.MULT, INT.PLUS, INT.EQZERO)
>>> print(R)
'
    0 1 2 3
 0| . . . .|  0
 1| . . . .|  1
 2| . . . .|  2
    0 1 2 3
'
Parameters
  • mask: Matrix. Matrix to select for which values to compute product.

  • M: Matrix. Matrix for a product.

  • op_mult: OpBinary. Element-wise binary operator for matrix vector elements product.

  • op_add: OpBinary. Element-wise binary operator for matrix vector products sum.

  • op_select: OpSelect. Selection op to filter mask.

  • out: optional: Matrix: default: None. Optional matrix to store result of product.

  • init: optional: Scalar: default: 0. Optional neutral init value for reduction.

  • desc: optional: Descriptor. default: None. Optional descriptor object to configure the execution.

Returns

Matrix with result.

def kron(self, M, op_mult, out=None, desc=None):
767    def kron(self, M, op_mult, out=None, desc=None):
768        """
769        Kronecker product of two sparse matrices.
770
771        Generate two matrices, sparse with different values and dense with 1.
772        >>> A = Matrix.from_lists([0, 1, 2], [1, 2, 0], [2, 3, 4], (3, 3), INT)
773        >>> B = Matrix.dense((3, 3), INT, 1)
774
775        Evaluate product with default `mutl` and show result.
776        >>> print(A.kron(B, op_mult=INT.MULT))
777        '
778            0 1 2 3 4 5 6 7 8
779         0| . . . 2 2 2 . . .|  0
780         1| . . . 2 2 2 . . .|  1
781         2| . . . 2 2 2 . . .|  2
782         3| . . . . . . 3 3 3|  3
783         4| . . . . . . 3 3 3|  4
784         5| . . . . . . 3 3 3|  5
785         6| 4 4 4 . . . . . .|  6
786         7| 4 4 4 . . . . . .|  7
787         8| 4 4 4 . . . . . .|  8
788            0 1 2 3 4 5 6 7 8
789        '
790
791        The same matrices but order is changed gives a bit of different result.
792        >>> print(B.kron(A, op_mult=INT.MULT))
793        '
794            0 1 2 3 4 5 6 7 8
795         0| . 2 . . 2 . . 2 .|  0
796         1| . . 3 . . 3 . . 3|  1
797         2| 4 . . 4 . . 4 . .|  2
798         3| . 2 . . 2 . . 2 .|  3
799         4| . . 3 . . 3 . . 3|  4
800         5| 4 . . 4 . . 4 . .|  5
801         6| . 2 . . 2 . . 2 .|  6
802         7| . . 3 . . 3 . . 3|  7
803         8| 4 . . 4 . . 4 . .|  8
804            0 1 2 3 4 5 6 7 8
805        '
806
807        Generate diagonal matrix and dense (not square).
808        >>> A = Matrix.diag((3, 3), INT, 1)
809        >>> B = Matrix.dense((2, 4), INT, 1)
810
811        Eval product with `plus` operation instead.
812        >>> print(A.kron(B, op_mult=INT.PLUS).to_string(width=3))
813        '
814              0  1  2  3  4  5  6  7  8  9 10 11
815          0|  2  2  2  2  .  .  .  .  .  .  .  .|  0
816          1|  2  2  2  2  .  .  .  .  .  .  .  .|  1
817          2|  .  .  .  .  2  2  2  2  .  .  .  .|  2
818          3|  .  .  .  .  2  2  2  2  .  .  .  .|  3
819          4|  .  .  .  .  .  .  .  .  2  2  2  2|  4
820          5|  .  .  .  .  .  .  .  .  2  2  2  2|  5
821              0  1  2  3  4  5  6  7  8  9 10 11
822        '
823
824        :param M: Matrix.
825            Right matrix for product.
826
827        :param op_mult: OpBinary.
828            Element-wise binary operator for matrix elements product.
829
830        :param out: optional: Matrix: default: None.
831            Optional matrix to store result of product.
832
833        :param desc: optional: Descriptor. default: None.
834            Optional descriptor object to configure the execution.
835
836        :return: Matrix with result.
837        """
838
839        if out is None:
840            out = Matrix(shape=(self.n_rows * M.n_rows, self.n_cols * M.n_cols), dtype=self.dtype)
841
842        assert M
843        assert out
844        assert M.dtype == self.dtype
845        assert out.dtype == self.dtype
846        assert out.n_rows == self.n_rows * M.n_rows
847        assert out.n_cols == self.n_cols * M.n_cols
848
849        check(backend().spla_Exec_kron(out.hnd, self.hnd, M.hnd, op_mult.hnd,
850                                       self._get_desc(desc), self._get_task(None)))
851
852        return out

Kronecker product of two sparse matrices.

Generate two matrices, sparse with different values and dense with 1.

>>> A = Matrix.from_lists([0, 1, 2], [1, 2, 0], [2, 3, 4], (3, 3), INT)
>>> B = Matrix.dense((3, 3), INT, 1)

Evaluate product with default mutl and show result.

>>> print(A.kron(B, op_mult=INT.MULT))
'
    0 1 2 3 4 5 6 7 8
 0| . . . 2 2 2 . . .|  0
 1| . . . 2 2 2 . . .|  1
 2| . . . 2 2 2 . . .|  2
 3| . . . . . . 3 3 3|  3
 4| . . . . . . 3 3 3|  4
 5| . . . . . . 3 3 3|  5
 6| 4 4 4 . . . . . .|  6
 7| 4 4 4 . . . . . .|  7
 8| 4 4 4 . . . . . .|  8
    0 1 2 3 4 5 6 7 8
'

The same matrices but order is changed gives a bit of different result.

>>> print(B.kron(A, op_mult=INT.MULT))
'
    0 1 2 3 4 5 6 7 8
 0| . 2 . . 2 . . 2 .|  0
 1| . . 3 . . 3 . . 3|  1
 2| 4 . . 4 . . 4 . .|  2
 3| . 2 . . 2 . . 2 .|  3
 4| . . 3 . . 3 . . 3|  4
 5| 4 . . 4 . . 4 . .|  5
 6| . 2 . . 2 . . 2 .|  6
 7| . . 3 . . 3 . . 3|  7
 8| 4 . . 4 . . 4 . .|  8
    0 1 2 3 4 5 6 7 8
'

Generate diagonal matrix and dense (not square).

>>> A = Matrix.diag((3, 3), INT, 1)
>>> B = Matrix.dense((2, 4), INT, 1)

Eval product with plus operation instead.

>>> print(A.kron(B, op_mult=INT.PLUS).to_string(width=3))
'
      0  1  2  3  4  5  6  7  8  9 10 11
  0|  2  2  2  2  .  .  .  .  .  .  .  .|  0
  1|  2  2  2  2  .  .  .  .  .  .  .  .|  1
  2|  .  .  .  .  2  2  2  2  .  .  .  .|  2
  3|  .  .  .  .  2  2  2  2  .  .  .  .|  3
  4|  .  .  .  .  .  .  .  .  2  2  2  2|  4
  5|  .  .  .  .  .  .  .  .  2  2  2  2|  5
      0  1  2  3  4  5  6  7  8  9 10 11
'
Parameters
  • M: Matrix. Right matrix for product.

  • op_mult: OpBinary. Element-wise binary operator for matrix elements product.

  • out: optional: Matrix: default: None. Optional matrix to store result of product.

  • desc: optional: Descriptor. default: None. Optional descriptor object to configure the execution.

Returns

Matrix with result.

def kronpow(self, exponent, op_mult=None):
854    def kronpow(self, exponent, op_mult=None):
855        """
856        Kronecker's expansion, evaluate product for matrix itself giving nice pattern.
857        Useful operation for synthetic graphs generation.
858
859        Source 2x2 pattern matrix for expansion.
860        >>> M = Matrix.from_lists([0, 0, 1], [0, 1, 1], [1, 2, 3], (2, 2), INT)
861
862        Exponent with 0 is the identinty matrix of the source shape.
863        >>> print(M.kronpow(0))
864        '
865            0 1
866         0| 1 .|  0
867         1| . 1|  1
868            0 1
869        '
870
871        Exmponent with 1 is the source matrix.
872        >>> print(M.kronpow(1))
873        '
874            0 1
875         0| 1 2|  0
876         1| . 3|  1
877            0 1
878        '
879
880        Exmponent with 2 it is kron product of self by itself.
881        >>> print(M.kronpow(2))
882        '
883            0 1 2 3
884         0| 1 2 2 4|  0
885         1| . 3 . 6|  1
886         2| . . 3 6|  2
887         3| . . . 9|  3
888            0 1 2 3
889        '
890
891        Exmponent with 3 it is effectively prev result matrix kron by itself.
892        >>> print(M.kronpow(3).to_string(width=3))
893        '
894              0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
895          0|  1  2  2  4  2  4  4  8  2  4  4  8  4  8  8 16|  0
896          1|  .  3  .  6  .  6  . 12  .  6  . 12  . 12  . 24|  1
897          2|  .  .  3  6  .  .  6 12  .  .  6 12  .  . 12 24|  2
898          3|  .  .  .  9  .  .  . 18  .  .  . 18  .  .  . 36|  3
899          4|  .  .  .  .  3  6  6 12  .  .  .  .  6 12 12 24|  4
900          5|  .  .  .  .  .  9  . 18  .  .  .  .  . 18  . 36|  5
901          6|  .  .  .  .  .  .  9 18  .  .  .  .  .  . 18 36|  6
902          7|  .  .  .  .  .  .  . 27  .  .  .  .  .  .  . 54|  7
903          8|  .  .  .  .  .  .  .  .  3  6  6 12  6 12 12 24|  8
904          9|  .  .  .  .  .  .  .  .  .  9  . 18  . 18  . 36|  9
905         10|  .  .  .  .  .  .  .  .  .  .  9 18  .  . 18 36|  10
906         11|  .  .  .  .  .  .  .  .  .  .  . 27  .  .  . 54|  11
907         12|  .  .  .  .  .  .  .  .  .  .  .  .  9 18 18 36|  12
908         13|  .  .  .  .  .  .  .  .  .  .  .  .  . 27  . 54|  13
909         14|  .  .  .  .  .  .  .  .  .  .  .  .  .  . 27 54|  14
910         15|  .  .  .  .  .  .  .  .  .  .  .  .  .  .  . 81|  15
911              0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
912        '
913
914        :param exponent: int.
915            Power to evaluate, must be >= 0.
916
917        :param op_mult: optional: OpBinary. default: None.
918            Optional operator for `kron`, by default used `mult`.
919
920        :return: Kronecker power of a matrix.
921        """
922
923        assert exponent >= 0
924
925        if op_mult is None:
926            op_mult = self.dtype.MULT
927
928        if exponent == 0:
929            return Matrix.diag(shape=self.shape, dtype=self.dtype)
930        if exponent == 1:
931            return self
932
933        result = self
934
935        for _ in range(exponent - 1):
936            result = result.kron(result, op_mult)
937
938        return result

Kronecker's expansion, evaluate product for matrix itself giving nice pattern. Useful operation for synthetic graphs generation.

Source 2x2 pattern matrix for expansion.

>>> M = Matrix.from_lists([0, 0, 1], [0, 1, 1], [1, 2, 3], (2, 2), INT)

Exponent with 0 is the identinty matrix of the source shape.

>>> print(M.kronpow(0))
'
    0 1
 0| 1 .|  0
 1| . 1|  1
    0 1
'

Exmponent with 1 is the source matrix.

>>> print(M.kronpow(1))
'
    0 1
 0| 1 2|  0
 1| . 3|  1
    0 1
'

Exmponent with 2 it is kron product of self by itself.

>>> print(M.kronpow(2))
'
    0 1 2 3
 0| 1 2 2 4|  0
 1| . 3 . 6|  1
 2| . . 3 6|  2
 3| . . . 9|  3
    0 1 2 3
'

Exmponent with 3 it is effectively prev result matrix kron by itself.

>>> print(M.kronpow(3).to_string(width=3))
'
      0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
  0|  1  2  2  4  2  4  4  8  2  4  4  8  4  8  8 16|  0
  1|  .  3  .  6  .  6  . 12  .  6  . 12  . 12  . 24|  1
  2|  .  .  3  6  .  .  6 12  .  .  6 12  .  . 12 24|  2
  3|  .  .  .  9  .  .  . 18  .  .  . 18  .  .  . 36|  3
  4|  .  .  .  .  3  6  6 12  .  .  .  .  6 12 12 24|  4
  5|  .  .  .  .  .  9  . 18  .  .  .  .  . 18  . 36|  5
  6|  .  .  .  .  .  .  9 18  .  .  .  .  .  . 18 36|  6
  7|  .  .  .  .  .  .  . 27  .  .  .  .  .  .  . 54|  7
  8|  .  .  .  .  .  .  .  .  3  6  6 12  6 12 12 24|  8
  9|  .  .  .  .  .  .  .  .  .  9  . 18  . 18  . 36|  9
 10|  .  .  .  .  .  .  .  .  .  .  9 18  .  . 18 36|  10
 11|  .  .  .  .  .  .  .  .  .  .  . 27  .  .  . 54|  11
 12|  .  .  .  .  .  .  .  .  .  .  .  .  9 18 18 36|  12
 13|  .  .  .  .  .  .  .  .  .  .  .  .  . 27  . 54|  13
 14|  .  .  .  .  .  .  .  .  .  .  .  .  .  . 27 54|  14
 15|  .  .  .  .  .  .  .  .  .  .  .  .  .  .  . 81|  15
      0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
'
Parameters
  • exponent: int. Power to evaluate, must be >= 0.

  • op_mult: optional: OpBinary. default: None. Optional operator for kron, by default used mult.

Returns

Kronecker power of a matrix.

def mxv( self, mask, v, op_mult, op_add, op_select, out=None, init=None, desc=None):
 940    def mxv(self, mask, v, op_mult, op_add, op_select, out=None, init=None, desc=None):
 941        """
 942        Masked sparse-matrix by a dense vector product with dense mask.
 943
 944        >>> M = Matrix.from_lists([0, 1, 2, 2, 3], [1, 2, 0, 3, 2], [1, 2, 3, 4, 5], (4, 4), INT)
 945        >>> v = Vector.from_lists([2], [1], 4, INT)
 946        >>> mask = Vector.from_lists(list(range(4)), [1] * 4, 4, INT)
 947        >>> print(M.mxv(mask, v, INT.LAND, INT.LOR, INT.GTZERO))
 948        '
 949         0| .
 950         1| 1
 951         2| .
 952         3| 1
 953        '
 954
 955        >>> M = Matrix.from_lists([0, 1, 2], [1, 2, 0], [1, 2, 3], (4, 4), INT)
 956        >>> v = Vector.from_lists([0, 1, 2], [2, 3, 4], 4, INT)
 957        >>> mask = Vector.from_lists(list(range(4)), [0] * 4, 4, INT)
 958        >>> print(M.mxv(mask, v, INT.MULT, INT.PLUS, INT.EQZERO))
 959        '
 960         0| 3
 961         1| 8
 962         2| 6
 963         3| .
 964        '
 965
 966        :param mask: Vector.
 967            Vector to select for which values to compute product.
 968
 969        :param v: Vector.
 970            Vector for a product.
 971
 972        :param op_mult: OpBinary.
 973            Element-wise binary operator for matrix vector elements product.
 974
 975        :param op_add: OpBinary.
 976            Element-wise binary operator for matrix vector products sum.
 977
 978        :param op_select: OpSelect.
 979            Selection op to filter mask.
 980
 981        :param out: optional: Vector: default: None.
 982            Optional vector to store result of product.
 983
 984        :param init: optional: Scalar: default: 0.
 985            Optional neutral init value for reduction.
 986
 987        :param desc: optional: Descriptor. default: None.
 988            Optional descriptor object to configure the execution.
 989
 990        :return: Vector with result.
 991        """
 992
 993        from .vector import Vector
 994
 995        if out is None:
 996            out = Vector(shape=self.n_rows, dtype=self.dtype)
 997        if init is None:
 998            init = Scalar(dtype=self.dtype, value=0)
 999
1000        assert v
1001        assert out
1002        assert init
1003        assert mask
1004        assert out.dtype == self.dtype
1005        assert v.dtype == self.dtype
1006        assert mask.dtype == self.dtype
1007        assert init.dtype == self.dtype
1008        assert out.n_rows == self.n_rows
1009        assert mask.n_rows == self.n_rows
1010        assert v.n_rows == self.n_cols
1011
1012        check(backend().spla_Exec_mxv_masked(out.hnd, mask.hnd, self.hnd, v.hnd,
1013                                             op_mult.hnd, op_add.hnd, op_select.hnd,
1014                                             init.hnd, self._get_desc(desc), self._get_task(None)))
1015
1016        return out

Masked sparse-matrix by a dense vector product with dense mask.

>>> M = Matrix.from_lists([0, 1, 2, 2, 3], [1, 2, 0, 3, 2], [1, 2, 3, 4, 5], (4, 4), INT)
>>> v = Vector.from_lists([2], [1], 4, INT)
>>> mask = Vector.from_lists(list(range(4)), [1] * 4, 4, INT)
>>> print(M.mxv(mask, v, INT.LAND, INT.LOR, INT.GTZERO))
'
 0| .
 1| 1
 2| .
 3| 1
'
>>> M = Matrix.from_lists([0, 1, 2], [1, 2, 0], [1, 2, 3], (4, 4), INT)
>>> v = Vector.from_lists([0, 1, 2], [2, 3, 4], 4, INT)
>>> mask = Vector.from_lists(list(range(4)), [0] * 4, 4, INT)
>>> print(M.mxv(mask, v, INT.MULT, INT.PLUS, INT.EQZERO))
'
 0| 3
 1| 8
 2| 6
 3| .
'
Parameters
  • mask: Vector. Vector to select for which values to compute product.

  • v: Vector. Vector for a product.

  • op_mult: OpBinary. Element-wise binary operator for matrix vector elements product.

  • op_add: OpBinary. Element-wise binary operator for matrix vector products sum.

  • op_select: OpSelect. Selection op to filter mask.

  • out: optional: Vector: default: None. Optional vector to store result of product.

  • init: optional: Scalar: default: 0. Optional neutral init value for reduction.

  • desc: optional: Descriptor. default: None. Optional descriptor object to configure the execution.

Returns

Vector with result.

def eadd(self, op_add, M, out=None, desc=None):
1018    def eadd(self, op_add, M, out=None, desc=None):
1019        """
1020        Element-wise addition with other matrix.
1021
1022        Element-wise addition takes the set union of the patterns of A and B and applies a binary operator
1023        for all entries that appear in the set intersection of the patterns of A and B, preserving values
1024        without the pair unchanged in the result.
1025
1026        >>> A = Matrix.from_lists([0, 1, 2], [1, 0, 2], [1, 2, 3], (3, 3), INT)
1027        >>> B = Matrix.from_lists([0, 1, 2], [1, 2, 2], [4, 5, 6], (3, 3), INT)
1028        >>> print(A.eadd(INT.PLUS, B))
1029        '
1030            0 1 2
1031         0| . 5 .|  0
1032         1| 2 . 5|  1
1033         2| . . 9|  2
1034            0 1 2
1035        '
1036
1037        >>> M = Matrix.from_lists([0, 0, 1], [0, 1, 1], [1, 2, 3], (2, 2), INT)
1038        >>> print(M.eadd(INT.MULT, M.transpose()))
1039        '
1040            0 1
1041         0| 1 2|  0
1042         1| 2 9|  1
1043            0 1
1044        '
1045
1046        :param op_add: OpBinary.
1047            Binary element-wise operation to apply.
1048
1049        :param M: Matrix.
1050            Matrix for operation on the right side.
1051
1052        :param out: optional: Matrix. default: None.
1053            Optional matrix to store result.
1054
1055        :param desc: optional: Descriptor. default: None.
1056            Optional descriptor object to configure the execution.
1057
1058        :return: Matrix with a result.
1059        """
1060
1061        if out is None:
1062            out = Matrix(shape=self.shape, dtype=self.dtype)
1063
1064        assert M
1065        assert out
1066        assert op_add
1067        assert self.shape == M.shape
1068        assert self.shape == out.shape
1069        assert self.dtype == M.dtype
1070        assert self.dtype == out.dtype
1071
1072        check(backend().spla_Exec_m_eadd(out.hnd, self.hnd, M.hnd, op_add.hnd,
1073                                         self._get_desc(desc), self._get_task(None)))
1074
1075        return out

Element-wise addition with other matrix.

Element-wise addition takes the set union of the patterns of A and B and applies a binary operator for all entries that appear in the set intersection of the patterns of A and B, preserving values without the pair unchanged in the result.

>>> A = Matrix.from_lists([0, 1, 2], [1, 0, 2], [1, 2, 3], (3, 3), INT)
>>> B = Matrix.from_lists([0, 1, 2], [1, 2, 2], [4, 5, 6], (3, 3), INT)
>>> print(A.eadd(INT.PLUS, B))
'
    0 1 2
 0| . 5 .|  0
 1| 2 . 5|  1
 2| . . 9|  2
    0 1 2
'
>>> M = Matrix.from_lists([0, 0, 1], [0, 1, 1], [1, 2, 3], (2, 2), INT)
>>> print(M.eadd(INT.MULT, M.transpose()))
'
    0 1
 0| 1 2|  0
 1| 2 9|  1
    0 1
'
Parameters
  • op_add: OpBinary. Binary element-wise operation to apply.

  • M: Matrix. Matrix for operation on the right side.

  • out: optional: Matrix. default: None. Optional matrix to store result.

  • desc: optional: Descriptor. default: None. Optional descriptor object to configure the execution.

Returns

Matrix with a result.

def emult(self, op_mult, M, out=None, desc=None):
1077    def emult(self, op_mult, M, out=None, desc=None):
1078        """
1079        Element-wise multiplication with other matrix.
1080
1081        Element-wise multiplication takes the set intersection of the patterns of A and B and applies a binary operator
1082        for all entries that appear in the set intersection of the patterns of A and B, removing the values without
1083        the pair from the result.
1084
1085        >>> A = Matrix.from_lists([0, 1, 2], [1, 0, 2], [1, 2, 3], (3, 3), INT)
1086        >>> B = Matrix.from_lists([0, 1, 2], [1, 2, 2], [4, 5, 6], (3, 3), INT)
1087        >>> print(A.emult(INT.PLUS, B))
1088        '
1089            0 1 2
1090         0| . 5 .|  0
1091         1| . . .|  1
1092         2| . . 9|  2
1093            0 1 2
1094        '
1095
1096        >>> M = Matrix.from_lists([0, 0, 1], [0, 1, 1], [1, 2, 3], (2, 2), INT)
1097        >>> print(M.emult(INT.MULT, M.transpose()))
1098        '
1099            0 1
1100         0| 1 .|  0
1101         1| . 9|  1
1102            0 1
1103        '
1104
1105        :param op_mult: OpBinary.
1106            Binary element-wise operation to apply.
1107
1108        :param M: Matrix.
1109            Matrix for operation on the right side.
1110
1111        :param out: optional: Matrix. default: None.
1112            Optional matrix to store result.
1113
1114        :param desc: optional: Descriptor. default: None.
1115            Optional descriptor object to configure the execution.
1116
1117        :return: Matrix with a result.
1118        """
1119
1120        if out is None:
1121            out = Matrix(shape=self.shape, dtype=self.dtype)
1122
1123        assert M
1124        assert out
1125        assert op_mult
1126        assert self.shape == M.shape
1127        assert self.shape == out.shape
1128        assert self.dtype == M.dtype
1129        assert self.dtype == out.dtype
1130
1131        check(backend().spla_Exec_m_emult(out.hnd, self.hnd, M.hnd, op_mult.hnd,
1132                                          self._get_desc(desc), self._get_task(None)))
1133
1134        return out

Element-wise multiplication with other matrix.

Element-wise multiplication takes the set intersection of the patterns of A and B and applies a binary operator for all entries that appear in the set intersection of the patterns of A and B, removing the values without the pair from the result.

>>> A = Matrix.from_lists([0, 1, 2], [1, 0, 2], [1, 2, 3], (3, 3), INT)
>>> B = Matrix.from_lists([0, 1, 2], [1, 2, 2], [4, 5, 6], (3, 3), INT)
>>> print(A.emult(INT.PLUS, B))
'
    0 1 2
 0| . 5 .|  0
 1| . . .|  1
 2| . . 9|  2
    0 1 2
'
>>> M = Matrix.from_lists([0, 0, 1], [0, 1, 1], [1, 2, 3], (2, 2), INT)
>>> print(M.emult(INT.MULT, M.transpose()))
'
    0 1
 0| 1 .|  0
 1| . 9|  1
    0 1
'
Parameters
  • op_mult: OpBinary. Binary element-wise operation to apply.

  • M: Matrix. Matrix for operation on the right side.

  • out: optional: Matrix. default: None. Optional matrix to store result.

  • desc: optional: Descriptor. default: None. Optional descriptor object to configure the execution.

Returns

Matrix with a result.

def reduce_by_row(self, op_reduce, out=None, init=None, desc=None):
1136    def reduce_by_row(self, op_reduce, out=None, init=None, desc=None):
1137        """
1138        Reduce matrix elements by a row to a column vector.
1139
1140        >>> M = Matrix.from_lists([0, 2, 2, 3], [0, 1, 3, 2], [1, 2, 3, 4], (4, 4), INT)
1141        >>> print(M.reduce_by_row(INT.PLUS))
1142        '
1143         0| 1
1144         1| .
1145         2| 5
1146         3| 4
1147        '
1148
1149        :param op_reduce: OpBinary.
1150            Binary operation to apply for reduction of matrix elements.
1151
1152        :param out: optional: Vector: default: None.
1153            Optional vector to store result of reduction.
1154
1155        :param init: optional: Scalar: default: 0.
1156            Optional neutral init value for reduction.
1157
1158        :param desc: optional: Descriptor. default: None.
1159            Optional descriptor object to configure the execution.
1160
1161        :return: Vector with result.
1162        """
1163
1164        from .vector import Vector
1165
1166        if out is None:
1167            out = Vector(shape=self.n_rows, dtype=self.dtype)
1168        if init is None:
1169            init = Scalar(dtype=self.dtype, value=0)
1170
1171        assert out
1172        assert init
1173        assert out.n_rows == self.n_rows
1174        assert out.dtype == self.dtype
1175        assert init.dtype == self.dtype
1176
1177        check(backend().spla_Exec_m_reduce_by_row(out.hnd, self.hnd, op_reduce.hnd, init.hnd,
1178                                                  self._get_desc(desc), self._get_task(None)))
1179
1180        return out

Reduce matrix elements by a row to a column vector.

>>> M = Matrix.from_lists([0, 2, 2, 3], [0, 1, 3, 2], [1, 2, 3, 4], (4, 4), INT)
>>> print(M.reduce_by_row(INT.PLUS))
'
 0| 1
 1| .
 2| 5
 3| 4
'
Parameters
  • op_reduce: OpBinary. Binary operation to apply for reduction of matrix elements.

  • out: optional: Vector: default: None. Optional vector to store result of reduction.

  • init: optional: Scalar: default: 0. Optional neutral init value for reduction.

  • desc: optional: Descriptor. default: None. Optional descriptor object to configure the execution.

Returns

Vector with result.

def reduce_by_column(self, op_reduce, out=None, init=None, desc=None):
1182    def reduce_by_column(self, op_reduce, out=None, init=None, desc=None):
1183        """
1184        Reduce matrix elements by a column to a row vector.
1185
1186        >>> M = Matrix.from_lists([0, 1, 2, 3], [0, 3, 3, 2], [1, 2, 3, 4], (4, 4), INT)
1187        >>> print(M.reduce_by_column(INT.PLUS))
1188        '
1189         0| 1
1190         1| .
1191         2| 4
1192         3| 5
1193        '
1194
1195        :param op_reduce: OpBinary.
1196            Binary operation to apply for reduction of matrix elements.
1197
1198        :param out: optional: Vector: default: None.
1199            Optional vector to store result of reduction.
1200
1201        :param init: optional: Scalar: default: 0.
1202            Optional neutral init value for reduction.
1203
1204        :param desc: optional: Descriptor. default: None.
1205            Optional descriptor object to configure the execution.
1206
1207        :return: Vector with result.
1208        """
1209
1210        from .vector import Vector
1211
1212        if out is None:
1213            out = Vector(shape=self.n_cols, dtype=self.dtype)
1214        if init is None:
1215            init = Scalar(dtype=self.dtype, value=0)
1216
1217        assert out
1218        assert init
1219        assert out.n_rows == self.n_cols
1220        assert out.dtype == self.dtype
1221        assert init.dtype == self.dtype
1222
1223        check(backend().spla_Exec_m_reduce_by_column(out.hnd, self.hnd, op_reduce.hnd, init.hnd,
1224                                                     self._get_desc(desc), self._get_task(None)))
1225
1226        return out

Reduce matrix elements by a column to a row vector.

>>> M = Matrix.from_lists([0, 1, 2, 3], [0, 3, 3, 2], [1, 2, 3, 4], (4, 4), INT)
>>> print(M.reduce_by_column(INT.PLUS))
'
 0| 1
 1| .
 2| 4
 3| 5
'
Parameters
  • op_reduce: OpBinary. Binary operation to apply for reduction of matrix elements.

  • out: optional: Vector: default: None. Optional vector to store result of reduction.

  • init: optional: Scalar: default: 0. Optional neutral init value for reduction.

  • desc: optional: Descriptor. default: None. Optional descriptor object to configure the execution.

Returns

Vector with result.

def reduce(self, op_reduce, out=None, init=None, desc=None):
1228    def reduce(self, op_reduce, out=None, init=None, desc=None):
1229        """
1230        Reduce matrix elements.
1231
1232        >>> M = Matrix.from_lists([1, 2, 3, 3], [0, 1, 0, 3], [-1, -4, 4, 2], (4, 4), INT)
1233        >>> print(M.reduce(op_reduce=INT.MULT, init=Scalar(INT, 1)))
1234        '
1235            32
1236        '
1237
1238        :param op_reduce: OpBinary.
1239            Binary operation to apply for reduction of matrix elements.
1240
1241        :param out: optional: Scalar: default: 0.
1242            Optional scalar to store result of reduction.
1243
1244        :param init: optional: Scalar: default: 0.
1245            Optional neutral init value for reduction.
1246
1247        :param desc: optional: Descriptor. default: None.
1248            Optional descriptor object to configure the execution.
1249
1250        :return: Scalar value with result.
1251        """
1252
1253        if out is None:
1254            out = Scalar(dtype=self.dtype)
1255        if init is None:
1256            init = Scalar(dtype=self.dtype, value=0)
1257
1258        assert out.dtype == self.dtype
1259        assert init.dtype == self.dtype
1260
1261        check(backend().spla_Exec_m_reduce(out.hnd, init.hnd, self.hnd, op_reduce.hnd,
1262                                           self._get_desc(desc), self._get_task(None)))
1263
1264        return out

Reduce matrix elements.

>>> M = Matrix.from_lists([1, 2, 3, 3], [0, 1, 0, 3], [-1, -4, 4, 2], (4, 4), INT)
>>> print(M.reduce(op_reduce=INT.MULT, init=Scalar(INT, 1)))
'
    32
'
Parameters
  • op_reduce: OpBinary. Binary operation to apply for reduction of matrix elements.

  • out: optional: Scalar: default: 0. Optional scalar to store result of reduction.

  • init: optional: Scalar: default: 0. Optional neutral init value for reduction.

  • desc: optional: Descriptor. default: None. Optional descriptor object to configure the execution.

Returns

Scalar value with result.

def transpose(self, out=None, op_apply=None, desc=None):
1266    def transpose(self, out=None, op_apply=None, desc=None):
1267        """
1268        Transpose matrix.
1269
1270        Generate 3x4 matrix with int source data.
1271        >>> M = Matrix.from_lists([0, 1, 2], [3, 2, 0], [-5, 3, 9], (3, 4), INT)
1272        >>> print(M)
1273        '
1274            0 1 2 3
1275         0| . . .-5|  0
1276         1| . . 3 .|  1
1277         2| 9 . . .|  2
1278            0 1 2 3
1279        '
1280
1281        Transpose matrix `M` as usual and print result.
1282        >>> print(M.transpose())
1283        '
1284            0 1 2
1285         0| . . 9|  0
1286         1| . . .|  1
1287         2| . 3 .|  2
1288         3|-5 . .|  3
1289            0 1 2
1290        '
1291
1292        Transpose by map each value to `1`, discarding prev value.
1293        >>> print(M.transpose(op_apply=INT.UONE))
1294        '
1295            0 1 2
1296         0| . . 1|  0
1297         1| . . .|  1
1298         2| . 1 .|  2
1299         3| 1 . .|  3
1300            0 1 2
1301        '
1302
1303        Transpose and apply additive-inverse for each value effectively changing the sign of values.
1304        >>> print(M.transpose(op_apply=INT.AINV))
1305        '
1306            0 1 2
1307         0| . .-9|  0
1308         1| . . .|  1
1309         2| .-3 .|  2
1310         3| 5 . .|  3
1311            0 1 2
1312        '
1313
1314        :param out: optional: Matrix: default: none.
1315            Optional matrix to store result.
1316
1317        :param op_apply: optional: OpUnary. default: None.
1318            Optional unary function to apply on transposition.
1319
1320        :param desc: optional: Descriptor. default: None.
1321            Optional descriptor object to configure the execution.
1322
1323        :return: Transposed matrix.
1324        """
1325
1326        if out is None:
1327            out = Matrix(shape=(self.n_cols, self.n_rows), dtype=self.dtype)
1328        if op_apply is None:
1329            op_apply = self.dtype.IDENTITY
1330
1331        assert out
1332        assert op_apply
1333        assert out.n_rows == self.n_cols
1334        assert out.n_cols == self.n_rows
1335        assert out.dtype == self.dtype
1336
1337        check(backend().spla_Exec_m_transpose(out.hnd, self.hnd, op_apply.hnd,
1338                                              self._get_desc(desc), self._get_task(None)))
1339
1340        return out

Transpose matrix.

Generate 3x4 matrix with int source data.

>>> M = Matrix.from_lists([0, 1, 2], [3, 2, 0], [-5, 3, 9], (3, 4), INT)
>>> print(M)
'
    0 1 2 3
 0| . . .-5|  0
 1| . . 3 .|  1
 2| 9 . . .|  2
    0 1 2 3
'

Transpose matrix M as usual and print result.

>>> print(M.transpose())
'
    0 1 2
 0| . . 9|  0
 1| . . .|  1
 2| . 3 .|  2
 3|-5 . .|  3
    0 1 2
'

Transpose by map each value to 1, discarding prev value.

>>> print(M.transpose(op_apply=INT.UONE))
'
    0 1 2
 0| . . 1|  0
 1| . . .|  1
 2| . 1 .|  2
 3| 1 . .|  3
    0 1 2
'

Transpose and apply additive-inverse for each value effectively changing the sign of values.

>>> print(M.transpose(op_apply=INT.AINV))
'
    0 1 2
 0| . .-9|  0
 1| . . .|  1
 2| .-3 .|  2
 3| 5 . .|  3
    0 1 2
'
Parameters
  • out: optional: Matrix: default: none. Optional matrix to store result.

  • op_apply: optional: OpUnary. default: None. Optional unary function to apply on transposition.

  • desc: optional: Descriptor. default: None. Optional descriptor object to configure the execution.

Returns

Transposed matrix.

def extract_row(self, index, out=None, op_apply=None, desc=None):
1342    def extract_row(self, index, out=None, op_apply=None, desc=None):
1343        """
1344        Extract matrix row.
1345
1346        >>> M = Matrix.from_lists([0, 0, 1, 2], [1, 2, 3, 0], [-1, 1, 2, 3], (3, 4), INT)
1347        >>> print(M)
1348        '
1349            0 1 2 3
1350         0| .-1 1 .|  0
1351         1| . . . 2|  1
1352         2| 3 . . .|  2
1353            0 1 2 3
1354        '
1355
1356        >>> print(M.extract_row(0))
1357        '
1358         0| .
1359         1|-1
1360         2| 1
1361         3| .
1362        '
1363
1364        >>> print(M.extract_row(0, op_apply=INT.AINV))
1365        '
1366         0| .
1367         1| 1
1368         2|-1
1369         3| .
1370        '
1371
1372        :param index: int.
1373            Index of row to extract.
1374
1375        :param out: optional: Vector: default: none.
1376            Optional vector to store result.
1377
1378        :param op_apply: optional: OpUnary. default: None.
1379            Optional unary function to apply on extraction.
1380
1381        :param desc: optional: Descriptor. default: None.
1382            Optional descriptor object to configure the execution.
1383
1384        :return: Vector.
1385        """
1386
1387        from .vector import Vector
1388
1389        if out is None:
1390            out = Vector(shape=self.n_cols, dtype=self.dtype)
1391        if op_apply is None:
1392            op_apply = self.dtype.IDENTITY
1393
1394        assert out
1395        assert op_apply
1396        assert out.dtype == self.dtype
1397        assert out.n_rows == self.n_cols
1398        assert 0 <= index < self.n_rows
1399
1400        check(backend().spla_Exec_m_extract_row(out.hnd, self.hnd, ctypes.c_uint(index), op_apply.hnd,
1401                                                self._get_desc(desc), self._get_task(None)))
1402
1403        return out

Extract matrix row.

>>> M = Matrix.from_lists([0, 0, 1, 2], [1, 2, 3, 0], [-1, 1, 2, 3], (3, 4), INT)
>>> print(M)
'
    0 1 2 3
 0| .-1 1 .|  0
 1| . . . 2|  1
 2| 3 . . .|  2
    0 1 2 3
'
>>> print(M.extract_row(0))
'
 0| .
 1|-1
 2| 1
 3| .
'
>>> print(M.extract_row(0, op_apply=INT.AINV))
'
 0| .
 1| 1
 2|-1
 3| .
'
Parameters
  • index: int. Index of row to extract.

  • out: optional: Vector: default: none. Optional vector to store result.

  • op_apply: optional: OpUnary. default: None. Optional unary function to apply on extraction.

  • desc: optional: Descriptor. default: None. Optional descriptor object to configure the execution.

Returns

Vector.

def extract_column(self, index, out=None, op_apply=None, desc=None):
1405    def extract_column(self, index, out=None, op_apply=None, desc=None):
1406        """
1407        Extract matrix column.
1408
1409        >>> M = Matrix.from_lists([0, 1, 1, 2], [1, 0, 3, 1], [-1, 1, 2, 3], (3, 4), INT)
1410        >>> print(M)
1411        '
1412            0 1 2 3
1413         0| .-1 . .|  0
1414         1| 1 . . 2|  1
1415         2| . 3 . .|  2
1416            0 1 2 3
1417        '
1418
1419        >>> print(M.extract_column(1))
1420        '
1421         0|-1
1422         1| .
1423         2| 3
1424        '
1425
1426        >>> print(M.extract_column(1, op_apply=INT.AINV))
1427        '
1428         0| 1
1429         1| .
1430         2|-3
1431        '
1432
1433        :param index: int.
1434            Index of column to extract.
1435
1436        :param out: optional: Vector: default: none.
1437            Optional vector to store result.
1438
1439        :param op_apply: optional: OpUnary. default: None.
1440            Optional unary function to apply on extraction.
1441
1442        :param desc: optional: Descriptor. default: None.
1443            Optional descriptor object to configure the execution.
1444
1445        :return: Vector.
1446        """
1447
1448        from .vector import Vector
1449
1450        if out is None:
1451            out = Vector(shape=self.n_rows, dtype=self.dtype)
1452        if op_apply is None:
1453            op_apply = self.dtype.IDENTITY
1454
1455        assert out
1456        assert op_apply
1457        assert out.dtype == self.dtype
1458        assert out.n_rows == self.n_rows
1459        assert 0 <= index < self.n_cols
1460
1461        check(backend().spla_Exec_m_extract_column(out.hnd, self.hnd, ctypes.c_uint(index), op_apply.hnd,
1462                                                   self._get_desc(desc), self._get_task(None)))
1463
1464        return out

Extract matrix column.

>>> M = Matrix.from_lists([0, 1, 1, 2], [1, 0, 3, 1], [-1, 1, 2, 3], (3, 4), INT)
>>> print(M)
'
    0 1 2 3
 0| .-1 . .|  0
 1| 1 . . 2|  1
 2| . 3 . .|  2
    0 1 2 3
'
>>> print(M.extract_column(1))
'
 0|-1
 1| .
 2| 3
'
>>> print(M.extract_column(1, op_apply=INT.AINV))
'
 0| 1
 1| .
 2|-3
'
Parameters
  • index: int. Index of column to extract.

  • out: optional: Vector: default: none. Optional vector to store result.

  • op_apply: optional: OpUnary. default: None. Optional unary function to apply on extraction.

  • desc: optional: Descriptor. default: None. Optional descriptor object to configure the execution.

Returns

Vector.

Inherited Members
Object
hnd
label
class Vector(pyspla.Object):
 42class Vector(Object):
 43    """
 44    Generalized statically-typed sparse storage-invariant vector primitive.
 45
 46    Notes
 47    -----
 48
 49    Vector typical usage:
 50
 51    - Instantiate vector primitive
 52    - Build incrementally from yours data source
 53    - Vector usage in a sequence of math operations
 54    - Read-back vector data to python to analyse results
 55
 56    Steps (2) and (4) requires internal format transformations and possible transfer of data
 57    from acc (GPU) side if acceleration was employed in computations. These steps may be very
 58    intensive, so you have to avoid them in critical parts of computations. If you need faster
 59    data reads, prefer usage of batched reads, where all content of storage read at once.
 60
 61    Details
 62    -------
 63
 64    Vector class support all spla C API vector functions.
 65    It provides bind functionality as well as new functions/methods for better python user experience.
 66
 67    Vector internally manages optimal format of stored data. Use hints to
 68    force vector state and format changes.
 69
 70    Vector optional uses dedicated/integrated GPU to speedup computations
 71    using one of built-in OpenCL or CUDA accelerators.
 72    """
 73
 74    __slots__ = ["_dtype", "_shape"]
 75
 76    def __init__(self, shape, dtype=INT, hnd=None, label=None):
 77        """
 78        Creates new vector of specified type and shape.
 79
 80        >>> v = Vector(5, INT)
 81        >>> print(v)
 82        '
 83         0| .
 84         1| .
 85         2| .
 86         3| .
 87         4| .
 88        '
 89
 90        :param dtype: Type.
 91            Type parametrization of a storage.
 92
 93        :param shape: int.
 94            Vector size.
 95
 96        :param hnd: optional: ctypes.c_void_p. default: None.
 97            Optional native handle to retain.
 98
 99        :param label: optional: str. default: None.
100            Optional label to assign.
101        """
102
103        super().__init__(None, None)
104
105        assert dtype
106        assert shape
107        assert shape > 0
108        assert issubclass(dtype, Type)
109
110        self._dtype = dtype
111        self._shape = (shape, 1)
112
113        if not hnd:
114            hnd = ctypes.c_void_p(0)
115            check(backend().spla_Vector_make(ctypes.byref(hnd), ctypes.c_uint(shape), dtype._hnd))
116
117        super().__init__(label, hnd)
118
119    @property
120    def dtype(self):
121        """
122        Type used for storage parametrization of this container.
123
124        >>> v = Vector(5, INT)
125        >>> print(v.dtype)
126        '
127            <class 'pyspla.type.INT'>
128        '
129        """
130        return self._dtype
131
132    @property
133    def n_rows(self):
134        """
135        Number of rows in the vector.
136
137        >>> v = Vector(5, INT)
138        >>> print(v.n_rows)
139        '
140            5
141        '
142        """
143        return self._shape[0]
144
145    @property
146    def shape(self):
147        """
148        2-Tuple with shape of vector where second value is always 1.
149
150        >>> v = Vector(5, INT)
151        >>> print(v.shape)
152        '
153            (5, 1)
154        '
155        """
156
157        return self._shape
158
159    def set_format(self, fmt):
160        """
161        Instruct container to format internal data with desired storage format.
162        Multiple different formats may be set at same time, data will be duplicated in different formats.
163        If selected data already in a selected format, then nothing to do.
164
165        See `FormatVector` enumeration for all supported formats.
166
167        :param fmt: FormatVector.
168            One of built-in storage formats to set.
169        """
170
171        check(backend().spla_Vector_set_format(self.hnd, ctypes.c_int(fmt.value)))
172
173    def set(self, i, v):
174        """
175        Set value at specified index
176
177        >>> v = Vector(5, INT)
178        >>> v.set(1, 10)
179        >>> v.set(2, -1)
180        >>> v.set(4, 15)
181        >>> print(v)
182        '
183         0| .
184         1|10
185         2|-1
186         3| .
187         4|15
188        '
189
190        :param i: uint.
191            Row index to set.
192
193        :param v: any.
194            Value to set.
195        """
196
197        check(self._dtype._vector_set(self.hnd, ctypes.c_uint(i), self._dtype._c_type(v)))
198
199    def get(self, i):
200        """
201        Get value at specified index.
202
203        >>> v = Vector.from_lists([0, 1], [-2, -3], 5, INT)
204        >>> print(v.get(0))
205        '
206            -2
207        '
208
209        >>> v = Vector.from_lists([0, 1], [-2, -3], 5, INT)
210        >>> print(v.get(4))
211        '
212            0
213        '
214
215        :param i: uint.
216            Row index of value to get.
217
218        :return: Value.
219        """
220
221        c_value = self._dtype._c_type(0)
222        check(self._dtype._vector_get(self.hnd, ctypes.c_uint(i), ctypes.byref(c_value)))
223        return self._dtype.cast_value(c_value)
224
225    def build(self, view_I: MemView, view_V: MemView):
226        """
227        Builds vector content from a raw memory view resources.
228
229        :param view_I: MemView.
230            View to keys of vector to assign.
231
232        :param view_V: MemView.
233            View to actual values to store.
234        """
235
236        assert view_I
237        assert view_V
238
239        check(backend().spla_Vector_build(self.hnd, view_I.hnd, view_V.hnd))
240
241    def read(self):
242        """
243        Read the content of the vector as a MemView of keys and values.
244
245        :return: tuple (MemView, MemView) objects with view to the vector keys and vector values.
246        """
247
248        keys_view_hnd = ctypes.c_void_p(0)
249        values_view_hnd = ctypes.c_void_p(0)
250        check(backend().spla_Vector_read(self.hnd, ctypes.byref(keys_view_hnd), ctypes.byref(values_view_hnd)))
251        return MemView(hnd=keys_view_hnd, owner=self), MemView(hnd=values_view_hnd, owner=self)
252
253    def clear(self):
254        """
255        Clears vector removing all elements, so it has no values.
256        """
257
258        check(backend().spla_Vector_clear(self.hnd))
259
260    def to_lists(self):
261        """
262        Read vector data as a python lists of keys and values.
263
264        >>> v = Vector.from_lists([0, 1, 4], [-2, -3, 10], 5, INT)
265        >>> print(v.to_lists())
266        '
267            ([0, 1, 4], [-2, -3, 10])
268        '
269
270        :return: Tuple (List, List) with the vector keys and vector values.
271        """
272
273        I, V = self.read()
274        count = int(I.size / ctypes.sizeof(UINT._c_type))
275
276        buffer_I = (UINT._c_type * count)()
277        buffer_V = (self._dtype._c_type * count)()
278
279        check(backend().spla_MemView_read(I.hnd, ctypes.c_size_t(0), ctypes.sizeof(buffer_I), buffer_I))
280        check(backend().spla_MemView_read(V.hnd, ctypes.c_size_t(0), ctypes.sizeof(buffer_V), buffer_V))
281
282        return list(buffer_I), list(buffer_V)
283
284    def to_list(self):
285        """
286        Read vector data as a python lists of tuples where key and value stored together.
287
288        >>> v = Vector.from_lists([0, 1, 4], [-2, -3, 10], 5, INT)
289        >>> print(v.to_list())
290        '
291            [(0, -2), (1, -3), (4, 10)]
292        '
293
294        :return: List of vector entries.
295        """
296
297        I, V = self.to_lists()
298        return list(zip(I, V))
299
300    def to_string(self, format_string="{:>%s}", width=2, precision=2, skip_value=0):
301        """
302        Generate from a vector a pretty string for a display.
303
304        >>> v = Vector.from_lists([0, 1, 3], [-1, 7, 5], 4, INT)
305        >>> print(v)
306        '
307         0|-1
308         1| 7
309         2| .
310         3| 5
311        '
312
313        :param format_string: str.
314            How to format single value.
315
316        :param width: int.
317            Integral part length.
318
319        :param precision: int.
320            Fractional part length.
321
322        :param skip_value: any.
323            Value to skip and not display
324
325        :return: Pretty string with vector content.
326        """
327
328        format_string = format_string % width
329        result = ""
330
331        for row in range(self.n_rows):
332            value = self.get(row)
333            value = value if value != skip_value else "."
334            result += format_string.format(row) + "|"
335            result += format_string.format(self.dtype.format_value(value, width, precision)).rstrip()
336            if row < self.n_rows - 1:
337                result += "\n"
338
339        return result
340
341    @classmethod
342    def from_lists(cls, I: list, V: list, shape, dtype=INT):
343        """
344        Build vector from a list of sorted keys and associated values to store in vector.
345        List with keys `keys` must index entries from range [0, shape-1] and all keys must be sorted.
346
347        >>> v = Vector.from_lists([0, 1, 3], [-1, 7, 5], 4, INT)
348        >>> print(v)
349        '
350         0|-1
351         1| 7
352         2| .
353         3| 5
354        '
355
356        :param I: list[UINT].
357             List with integral keys of entries.
358
359        :param V: list[Type].
360             List with values to store in the vector.
361
362        :param shape: int.
363             Vector size.
364
365        :param dtype:
366             Type of storage parametrization for vector.
367
368        :return: Created vector filled with values.
369        """
370
371        assert len(I) == len(V)
372        assert shape > 0
373
374        if not I:
375            return Vector(shape, dtype)
376
377        count = len(I)
378
379        c_I = (UINT._c_type * count)(*I)
380        c_V = (dtype._c_type * count)(*V)
381
382        view_I = MemView(buffer=c_I, size=ctypes.sizeof(c_I), mutable=False)
383        view_V = MemView(buffer=c_V, size=ctypes.sizeof(c_V), mutable=False)
384
385        v = Vector(shape=shape, dtype=dtype)
386        v.build(view_I, view_V)
387
388        return v
389
390    @classmethod
391    def rand(cls, shape, dtype=INT, density=0.1, seed=None, dist=(0, 1)):
392        """
393        Creates new vector of desired type and shape and fills its content
394        with random values, generated using specified distribution.
395
396        >>> v = Vector.rand(shape=4, dtype=INT, density=0.5, dist=[1,10])
397        >>> print(v)
398        '
399         0| .
400         1| .
401         2| 5
402         3| .
403        '
404
405        :param shape: int.
406            Size of the vector.
407
408        :param dtype: optional: Type. default: INT.
409            Type of values vector will have.
410
411        :param density: optional: float. default: 0.1.
412            Density of vector or how many entries to generate.
413
414        :param seed: optional: int. default: None.
415            Optional seed to randomize generator.
416
417        :param dist: optional: tuple. default: [0,1].
418            Optional distribution for uniform generation of values.
419
420        :return: Created vector filled with values.
421        """
422
423        if seed is not None:
424            rnd.seed(seed)
425
426        I = sorted(list({rnd.randint(0, shape - 1) for _ in range(int(shape * density))}))
427        count = len(I)
428
429        if dtype is INT:
430            V = [rnd.randint(dist[0], dist[1]) for i in range(count)]
431        elif dtype is UINT:
432            V = [rnd.randint(dist[0], dist[1]) for i in range(count)]
433        elif dtype is FLOAT:
434            V = [rnd.uniform(dist[0], dist[1]) for i in range(count)]
435        else:
436            raise Exception("unknown type")
437
438        return cls.from_lists(I, V, shape=shape, dtype=dtype)
439
440    @classmethod
441    def dense(cls, shape, dtype=INT, fill_value=0):
442        """
443        Creates new dense vector of specified shape and fills with desired value.
444
445        >>> v = Vector.dense(5, INT, 4)
446        >>> print(v)
447        '
448         0| 4
449         1| 4
450         2| 4
451         3| 4
452         4| 4
453        '
454
455        :param shape: int.
456            Size of the vector.
457
458        :param dtype: optional: Type. default: INT.
459            Type of values vector will have.
460
461        :param fill_value: optional: any. default: 0.
462            Optional value to fill with.
463
464        :return: Vector filled with value.
465        """
466
467        from .bridge import FormatVector
468
469        v = Vector(shape, dtype)
470        v.set_format(FormatVector.CPU_DENSE)
471
472        for i in range(shape):
473            v.set(i, fill_value)
474
475        return v
476
477    def vxm(self, mask, M, op_mult, op_add, op_select, out=None, init=None, desc=None):
478        """
479        Masked sparse-vector by sparse-matrix product with dense mask.
480
481        >>> M = Matrix.from_lists([0, 1, 2, 2, 3], [1, 2, 0, 3, 2], [1, 2, 3, 4, 5], (4, 4), INT)
482        >>> v = Vector.from_lists([2], [1], 4, INT)
483        >>> mask = Vector.from_lists(list(range(4)), [1] * 4, 4, INT)
484        >>> print(v.vxm(mask, M, INT.LAND, INT.LOR, INT.GTZERO))
485        '
486         0| 1
487         1| .
488         2| .
489         3| 1
490        '
491
492        >>> M = Matrix.from_lists([0, 1, 2], [1, 2, 0], [1, 2, 3], (4, 4), INT)
493        >>> v = Vector.from_lists([0, 1, 2], [2, 3, 4], 4, INT)
494        >>> mask = Vector.from_lists(list(range(4)), [0] * 4, 4, INT)
495        >>> print(v.vxm(mask, M, INT.MULT, INT.PLUS, INT.EQZERO))
496        '
497         0|12
498         1| 2
499         2| 6
500         3| .
501        '
502
503        :param mask: Vector.
504            Vector to select for which values to compute product.
505
506        :param M: Matrix.
507            Matrix for a product.
508
509        :param op_mult: OpBinary.
510            Element-wise binary operator for matrix vector elements product.
511
512        :param op_add: OpBinary.
513            Element-wise binary operator for matrix vector products sum.
514
515        :param op_select: OpSelect.
516            Selection op to filter mask.
517
518        :param out: optional: Vector: default: None.
519            Optional vector to store result of product.
520
521        :param init: optional: Scalar: default: 0.
522            Optional neutral init value for reduction.
523
524        :param desc: optional: Descriptor. default: None.
525            Optional descriptor object to configure the execution.
526
527        :return: Vector with result.
528        """
529
530        if out is None:
531            out = Vector(shape=M.n_cols, dtype=self.dtype)
532        if init is None:
533            init = Scalar(dtype=self.dtype, value=0)
534
535        assert M
536        assert out
537        assert init
538        assert mask
539        assert out.dtype == self.dtype
540        assert M.dtype == self.dtype
541        assert mask.dtype == self.dtype
542        assert init.dtype == self.dtype
543        assert out.n_rows == M.n_cols
544        assert mask.n_rows == M.n_cols
545        assert M.n_rows == self.n_rows
546
547        check(backend().spla_Exec_vxm_masked(out.hnd, mask.hnd, self.hnd, M.hnd,
548                                             op_mult.hnd, op_add.hnd, op_select.hnd,
549                                             init.hnd, self._get_desc(desc), self._get_task(None)))
550
551        return out
552
553    def eadd(self, op_add, v, out=None, desc=None):
554        """
555        Element-wise add one vector to another and return result.
556
557        >>> u = Vector.from_lists([0, 1], [10, 20], 4, INT)
558        >>> v = Vector.from_lists([1, 3], [-5, 12], 4, INT)
559        >>> print(u.eadd(INT.PLUS, v))
560        '
561         0|10
562         1|15
563         2| .
564         3|12
565        '
566
567        :param op_add: OpBinary.
568            Binary operation to sum values.
569
570        :param v: Vector.
571            Other right vector to sum with this.
572
573        :param out: optional: Vector. default: None.
574            Optional vector to store result.
575
576        :param desc: optional: Descriptor. default: None.
577            Optional descriptor object to configure the execution.
578
579        :return: Vector with result.
580        """
581
582        if out is None:
583            out = Vector(shape=self.n_rows, dtype=self.dtype)
584
585        assert v
586        assert v.n_rows == self.n_rows
587        assert out.n_rows == self.n_rows
588        assert v.dtype == self.dtype
589        assert out.dtype == out.dtype
590        assert op_add
591
592        check(backend().spla_Exec_v_eadd(out.hnd, self.hnd, v.hnd, op_add.hnd,
593                                         self._get_desc(desc), self._get_task(None)))
594
595        return out
596
597    def emult(self, op_mult, v, out=None, desc=None):
598        """
599        Element-wise mult one vector to another and return result.
600
601        >>> u = Vector.from_lists([0, 1], [10, 20], 4, INT)
602        >>> v = Vector.from_lists([1, 3], [-5, 12], 4, INT)
603        >>> print(u.emult(INT.PLUS, v))
604        '
605         0| .
606         1|15
607         2| .
608         3| .
609        '
610
611        :param op_mult: OpBinary.
612            Binary operation to mult values.
613
614        :param v: Vector.
615            Other right vector to mult with this.
616
617        :param out: optional: Vector. default: None.
618            Optional vector to store result.
619
620        :param desc: optional: Descriptor. default: None.
621            Optional descriptor object to configure the execution.
622
623        :return: Vector with result.
624        """
625
626        if out is None:
627            out = Vector(shape=self.n_rows, dtype=self.dtype)
628
629        assert v
630        assert v.n_rows == self.n_rows
631        assert out.n_rows == self.n_rows
632        assert v.dtype == self.dtype
633        assert out.dtype == out.dtype
634        assert op_mult
635
636        check(backend().spla_Exec_v_emult(out.hnd, self.hnd, v.hnd, op_mult.hnd,
637                                          self._get_desc(desc), self._get_task(None)))
638
639        return out
640
641    def assign(self, mask, value, op_assign, op_select, desc=None):
642        """
643        Assign scalar value to a vector by mask.
644
645        >>> v = Vector(4, INT)
646        >>> m = Vector.from_lists([0, 1, 3], [1, 0, 1], 4, INT)
647        >>> s = Scalar(INT, 4)
648        >>> v.assign(mask=m, value=s, op_assign=INT.SECOND, op_select=INT.GTZERO)
649        >>> print(v)
650        '
651         0| 4
652         1| .
653         2| .
654         3| 4
655        '
656
657        :param mask: Vector.
658            Mask vector which structure will be used to select entries for assignment.
659
660        :param value: Scalar.
661            Value to assign.
662
663        :param op_assign: OpBinary.
664            Binary operation used to combine existing value in vector and scalar.
665
666        :param op_select: OpSelect.
667            Predicate to select entries in the mask to assign.
668
669        :param desc: optional: Descriptor. default: None.
670            Optional descriptor object to configure the execution.
671
672        :return: This vector.
673        """
674
675        assert mask
676        assert value
677        assert mask.n_rows == self.n_rows
678        assert op_assign
679        assert op_select
680
681        check(backend().spla_Exec_v_assign_masked(self.hnd, mask.hnd, value.hnd, op_assign.hnd, op_select.hnd,
682                                                  self._get_desc(desc), self._get_task(None)))
683
684        return self
685
686    def map(self, op_map, out=None, desc=None):
687        """
688        Map this vector by applying element-wise unary function to each element.
689
690        >>> v = Vector.from_lists([0, 1, 3], [5, -1, 3], 4, INT)
691        >>> print(v.map(INT.AINV))
692        '
693         0|-5
694         1| 1
695         2| .
696         3|-3
697        '
698
699        :param op_map: OpUnary.
700            Unary operation to apply to transform values.
701
702        :param out: optional: Vector. default: None.
703            Optional vector where to store result.
704
705        :param desc: optional: Descriptor. default: None.
706            Optional descriptor object to configure the execution.
707
708        :return: Result of a map as vector.
709        """
710
711        if out is None:
712            out = Vector(self.n_rows, self.dtype)
713
714        assert out
715        assert op_map
716        assert out.n_rows == self.n_rows
717        assert out.dtype == self.dtype
718
719        check(backend().spla_Exec_v_map(out.hnd, self.hnd, op_map.hnd,
720                                        self._get_desc(desc), self._get_task(None)))
721
722        return out
723
724    def reduce(self, op_reduce, out=None, init=None, desc=None):
725        """
726        Reduce vector elements.
727
728        >>> v = Vector.from_lists([0, 1, 2], [-1, 2, 5], 4, INT)
729        >>> print(v.reduce(op_reduce=INT.PLUS))
730        '
731            6
732        '
733
734        >>> v = Vector.from_lists([0, 1, 2], [-0.5, 4.0, 12.3], 4, FLOAT)
735        >>> print(v.reduce(op_reduce=FLOAT.MAX))
736        '
737            12.3
738        '
739
740        :param op_reduce: OpBinary.
741            Binary operation to apply for reduction of vector elements.
742
743        :param out: optional: Scalar: default: 0.
744            Optional scalar to store result of reduction.
745
746        :param init: optional: Scalar: default: 0.
747            Optional neutral init value for reduction.
748
749        :param desc: optional: Descriptor. default: None.
750            Optional descriptor object to configure the execution.
751
752        :return: Scalar value with result.
753        """
754
755        if out is None:
756            out = Scalar(dtype=self.dtype)
757        if init is None:
758            init = Scalar(dtype=self.dtype, value=0)
759
760        assert out.dtype == self.dtype
761        assert init.dtype == self.dtype
762
763        check(backend().spla_Exec_v_reduce(out.hnd, init.hnd, self.hnd, op_reduce.hnd,
764                                           self._get_desc(desc), self._get_task(None)))
765
766        return out
767
768    def __str__(self):
769        return self.to_string()
770
771    def __iter__(self):
772        I, V = self.to_lists()
773        return zip(I, V)
774
775    def _get_desc(self, desc: Descriptor):
776        return desc.hnd if desc else ctypes.c_void_p(0)
777
778    def _get_task(self, task):
779        return ctypes.POINTER(ctypes.c_void_p)()

Generalized statically-typed sparse storage-invariant vector primitive.

Notes

Vector typical usage:

  • Instantiate vector primitive
  • Build incrementally from yours data source
  • Vector usage in a sequence of math operations
  • Read-back vector data to python to analyse results

Steps (2) and (4) requires internal format transformations and possible transfer of data from acc (GPU) side if acceleration was employed in computations. These steps may be very intensive, so you have to avoid them in critical parts of computations. If you need faster data reads, prefer usage of batched reads, where all content of storage read at once.

Details

Vector class support all spla C API vector functions. It provides bind functionality as well as new functions/methods for better python user experience.

Vector internally manages optimal format of stored data. Use hints to force vector state and format changes.

Vector optional uses dedicated/integrated GPU to speedup computations using one of built-in OpenCL or CUDA accelerators.

Vector(shape, dtype=<class 'pyspla.INT'>, hnd=None, label=None)
 76    def __init__(self, shape, dtype=INT, hnd=None, label=None):
 77        """
 78        Creates new vector of specified type and shape.
 79
 80        >>> v = Vector(5, INT)
 81        >>> print(v)
 82        '
 83         0| .
 84         1| .
 85         2| .
 86         3| .
 87         4| .
 88        '
 89
 90        :param dtype: Type.
 91            Type parametrization of a storage.
 92
 93        :param shape: int.
 94            Vector size.
 95
 96        :param hnd: optional: ctypes.c_void_p. default: None.
 97            Optional native handle to retain.
 98
 99        :param label: optional: str. default: None.
100            Optional label to assign.
101        """
102
103        super().__init__(None, None)
104
105        assert dtype
106        assert shape
107        assert shape > 0
108        assert issubclass(dtype, Type)
109
110        self._dtype = dtype
111        self._shape = (shape, 1)
112
113        if not hnd:
114            hnd = ctypes.c_void_p(0)
115            check(backend().spla_Vector_make(ctypes.byref(hnd), ctypes.c_uint(shape), dtype._hnd))
116
117        super().__init__(label, hnd)

Creates new vector of specified type and shape.

>>> v = Vector(5, INT)
>>> print(v)
'
 0| .
 1| .
 2| .
 3| .
 4| .
'
Parameters
  • dtype: Type. Type parametrization of a storage.

  • shape: int. Vector size.

  • hnd: optional: ctypes.c_void_p. default: None. Optional native handle to retain.

  • label: optional: str. default: None. Optional label to assign.

dtype

Type used for storage parametrization of this container.

>>> v = Vector(5, INT)
>>> print(v.dtype)
'
    <class 'pyspla.INT'>
'
n_rows

Number of rows in the vector.

>>> v = Vector(5, INT)
>>> print(v.n_rows)
'
    5
'
shape

2-Tuple with shape of vector where second value is always 1.

>>> v = Vector(5, INT)
>>> print(v.shape)
'
    (5, 1)
'
def set_format(self, fmt):
159    def set_format(self, fmt):
160        """
161        Instruct container to format internal data with desired storage format.
162        Multiple different formats may be set at same time, data will be duplicated in different formats.
163        If selected data already in a selected format, then nothing to do.
164
165        See `FormatVector` enumeration for all supported formats.
166
167        :param fmt: FormatVector.
168            One of built-in storage formats to set.
169        """
170
171        check(backend().spla_Vector_set_format(self.hnd, ctypes.c_int(fmt.value)))

Instruct container to format internal data with desired storage format. Multiple different formats may be set at same time, data will be duplicated in different formats. If selected data already in a selected format, then nothing to do.

See FormatVector enumeration for all supported formats.

Parameters
  • fmt: FormatVector. One of built-in storage formats to set.
def set(self, i, v):
173    def set(self, i, v):
174        """
175        Set value at specified index
176
177        >>> v = Vector(5, INT)
178        >>> v.set(1, 10)
179        >>> v.set(2, -1)
180        >>> v.set(4, 15)
181        >>> print(v)
182        '
183         0| .
184         1|10
185         2|-1
186         3| .
187         4|15
188        '
189
190        :param i: uint.
191            Row index to set.
192
193        :param v: any.
194            Value to set.
195        """
196
197        check(self._dtype._vector_set(self.hnd, ctypes.c_uint(i), self._dtype._c_type(v)))

Set value at specified index

>>> v = Vector(5, INT)
>>> v.set(1, 10)
>>> v.set(2, -1)
>>> v.set(4, 15)
>>> print(v)
'
 0| .
 1|10
 2|-1
 3| .
 4|15
'
Parameters
  • i: uint. Row index to set.

  • v: any. Value to set.

def get(self, i):
199    def get(self, i):
200        """
201        Get value at specified index.
202
203        >>> v = Vector.from_lists([0, 1], [-2, -3], 5, INT)
204        >>> print(v.get(0))
205        '
206            -2
207        '
208
209        >>> v = Vector.from_lists([0, 1], [-2, -3], 5, INT)
210        >>> print(v.get(4))
211        '
212            0
213        '
214
215        :param i: uint.
216            Row index of value to get.
217
218        :return: Value.
219        """
220
221        c_value = self._dtype._c_type(0)
222        check(self._dtype._vector_get(self.hnd, ctypes.c_uint(i), ctypes.byref(c_value)))
223        return self._dtype.cast_value(c_value)

Get value at specified index.

>>> v = Vector.from_lists([0, 1], [-2, -3], 5, INT)
>>> print(v.get(0))
'
    -2
'
>>> v = Vector.from_lists([0, 1], [-2, -3], 5, INT)
>>> print(v.get(4))
'
    0
'
Parameters
  • i: uint. Row index of value to get.
Returns

Value.

def build(self, view_I: pyspla.MemView, view_V: pyspla.MemView):
225    def build(self, view_I: MemView, view_V: MemView):
226        """
227        Builds vector content from a raw memory view resources.
228
229        :param view_I: MemView.
230            View to keys of vector to assign.
231
232        :param view_V: MemView.
233            View to actual values to store.
234        """
235
236        assert view_I
237        assert view_V
238
239        check(backend().spla_Vector_build(self.hnd, view_I.hnd, view_V.hnd))

Builds vector content from a raw memory view resources.

Parameters
  • view_I: MemView. View to keys of vector to assign.

  • view_V: MemView. View to actual values to store.

def read(self):
241    def read(self):
242        """
243        Read the content of the vector as a MemView of keys and values.
244
245        :return: tuple (MemView, MemView) objects with view to the vector keys and vector values.
246        """
247
248        keys_view_hnd = ctypes.c_void_p(0)
249        values_view_hnd = ctypes.c_void_p(0)
250        check(backend().spla_Vector_read(self.hnd, ctypes.byref(keys_view_hnd), ctypes.byref(values_view_hnd)))
251        return MemView(hnd=keys_view_hnd, owner=self), MemView(hnd=values_view_hnd, owner=self)

Read the content of the vector as a MemView of keys and values.

Returns

tuple (MemView, MemView) objects with view to the vector keys and vector values.

def clear(self):
253    def clear(self):
254        """
255        Clears vector removing all elements, so it has no values.
256        """
257
258        check(backend().spla_Vector_clear(self.hnd))

Clears vector removing all elements, so it has no values.

def to_lists(self):
260    def to_lists(self):
261        """
262        Read vector data as a python lists of keys and values.
263
264        >>> v = Vector.from_lists([0, 1, 4], [-2, -3, 10], 5, INT)
265        >>> print(v.to_lists())
266        '
267            ([0, 1, 4], [-2, -3, 10])
268        '
269
270        :return: Tuple (List, List) with the vector keys and vector values.
271        """
272
273        I, V = self.read()
274        count = int(I.size / ctypes.sizeof(UINT._c_type))
275
276        buffer_I = (UINT._c_type * count)()
277        buffer_V = (self._dtype._c_type * count)()
278
279        check(backend().spla_MemView_read(I.hnd, ctypes.c_size_t(0), ctypes.sizeof(buffer_I), buffer_I))
280        check(backend().spla_MemView_read(V.hnd, ctypes.c_size_t(0), ctypes.sizeof(buffer_V), buffer_V))
281
282        return list(buffer_I), list(buffer_V)

Read vector data as a python lists of keys and values.

>>> v = Vector.from_lists([0, 1, 4], [-2, -3, 10], 5, INT)
>>> print(v.to_lists())
'
    ([0, 1, 4], [-2, -3, 10])
'
Returns

Tuple (List, List) with the vector keys and vector values.

def to_list(self):
284    def to_list(self):
285        """
286        Read vector data as a python lists of tuples where key and value stored together.
287
288        >>> v = Vector.from_lists([0, 1, 4], [-2, -3, 10], 5, INT)
289        >>> print(v.to_list())
290        '
291            [(0, -2), (1, -3), (4, 10)]
292        '
293
294        :return: List of vector entries.
295        """
296
297        I, V = self.to_lists()
298        return list(zip(I, V))

Read vector data as a python lists of tuples where key and value stored together.

>>> v = Vector.from_lists([0, 1, 4], [-2, -3, 10], 5, INT)
>>> print(v.to_list())
'
    [(0, -2), (1, -3), (4, 10)]
'
Returns

List of vector entries.

def to_string(self, format_string='{:>%s}', width=2, precision=2, skip_value=0):
300    def to_string(self, format_string="{:>%s}", width=2, precision=2, skip_value=0):
301        """
302        Generate from a vector a pretty string for a display.
303
304        >>> v = Vector.from_lists([0, 1, 3], [-1, 7, 5], 4, INT)
305        >>> print(v)
306        '
307         0|-1
308         1| 7
309         2| .
310         3| 5
311        '
312
313        :param format_string: str.
314            How to format single value.
315
316        :param width: int.
317            Integral part length.
318
319        :param precision: int.
320            Fractional part length.
321
322        :param skip_value: any.
323            Value to skip and not display
324
325        :return: Pretty string with vector content.
326        """
327
328        format_string = format_string % width
329        result = ""
330
331        for row in range(self.n_rows):
332            value = self.get(row)
333            value = value if value != skip_value else "."
334            result += format_string.format(row) + "|"
335            result += format_string.format(self.dtype.format_value(value, width, precision)).rstrip()
336            if row < self.n_rows - 1:
337                result += "\n"
338
339        return result

Generate from a vector a pretty string for a display.

>>> v = Vector.from_lists([0, 1, 3], [-1, 7, 5], 4, INT)
>>> print(v)
'
 0|-1
 1| 7
 2| .
 3| 5
'
Parameters
  • format_string: str. How to format single value.

  • width: int. Integral part length.

  • precision: int. Fractional part length.

  • skip_value: any. Value to skip and not display

Returns

Pretty string with vector content.

@classmethod
def from_lists(cls, I: list, V: list, shape, dtype=<class 'pyspla.INT'>):
341    @classmethod
342    def from_lists(cls, I: list, V: list, shape, dtype=INT):
343        """
344        Build vector from a list of sorted keys and associated values to store in vector.
345        List with keys `keys` must index entries from range [0, shape-1] and all keys must be sorted.
346
347        >>> v = Vector.from_lists([0, 1, 3], [-1, 7, 5], 4, INT)
348        >>> print(v)
349        '
350         0|-1
351         1| 7
352         2| .
353         3| 5
354        '
355
356        :param I: list[UINT].
357             List with integral keys of entries.
358
359        :param V: list[Type].
360             List with values to store in the vector.
361
362        :param shape: int.
363             Vector size.
364
365        :param dtype:
366             Type of storage parametrization for vector.
367
368        :return: Created vector filled with values.
369        """
370
371        assert len(I) == len(V)
372        assert shape > 0
373
374        if not I:
375            return Vector(shape, dtype)
376
377        count = len(I)
378
379        c_I = (UINT._c_type * count)(*I)
380        c_V = (dtype._c_type * count)(*V)
381
382        view_I = MemView(buffer=c_I, size=ctypes.sizeof(c_I), mutable=False)
383        view_V = MemView(buffer=c_V, size=ctypes.sizeof(c_V), mutable=False)
384
385        v = Vector(shape=shape, dtype=dtype)
386        v.build(view_I, view_V)
387
388        return v

Build vector from a list of sorted keys and associated values to store in vector. List with keys keys must index entries from range [0, shape-1] and all keys must be sorted.

>>> v = Vector.from_lists([0, 1, 3], [-1, 7, 5], 4, INT)
>>> print(v)
'
 0|-1
 1| 7
 2| .
 3| 5
'
Parameters
  • I: list[UINT]. List with integral keys of entries.

  • V: list[Type]. List with values to store in the vector.

  • shape: int. Vector size.

  • dtype: Type of storage parametrization for vector.

Returns

Created vector filled with values.

@classmethod
def rand( cls, shape, dtype=<class 'pyspla.INT'>, density=0.1, seed=None, dist=(0, 1)):
390    @classmethod
391    def rand(cls, shape, dtype=INT, density=0.1, seed=None, dist=(0, 1)):
392        """
393        Creates new vector of desired type and shape and fills its content
394        with random values, generated using specified distribution.
395
396        >>> v = Vector.rand(shape=4, dtype=INT, density=0.5, dist=[1,10])
397        >>> print(v)
398        '
399         0| .
400         1| .
401         2| 5
402         3| .
403        '
404
405        :param shape: int.
406            Size of the vector.
407
408        :param dtype: optional: Type. default: INT.
409            Type of values vector will have.
410
411        :param density: optional: float. default: 0.1.
412            Density of vector or how many entries to generate.
413
414        :param seed: optional: int. default: None.
415            Optional seed to randomize generator.
416
417        :param dist: optional: tuple. default: [0,1].
418            Optional distribution for uniform generation of values.
419
420        :return: Created vector filled with values.
421        """
422
423        if seed is not None:
424            rnd.seed(seed)
425
426        I = sorted(list({rnd.randint(0, shape - 1) for _ in range(int(shape * density))}))
427        count = len(I)
428
429        if dtype is INT:
430            V = [rnd.randint(dist[0], dist[1]) for i in range(count)]
431        elif dtype is UINT:
432            V = [rnd.randint(dist[0], dist[1]) for i in range(count)]
433        elif dtype is FLOAT:
434            V = [rnd.uniform(dist[0], dist[1]) for i in range(count)]
435        else:
436            raise Exception("unknown type")
437
438        return cls.from_lists(I, V, shape=shape, dtype=dtype)

Creates new vector of desired type and shape and fills its content with random values, generated using specified distribution.

>>> v = Vector.rand(shape=4, dtype=INT, density=0.5, dist=[1,10])
>>> print(v)
'
 0| .
 1| .
 2| 5
 3| .
'
Parameters
  • shape: int. Size of the vector.

  • dtype: optional: Type. default: INT. Type of values vector will have.

  • density: optional: float. default: 0.1. Density of vector or how many entries to generate.

  • seed: optional: int. default: None. Optional seed to randomize generator.

  • dist: optional: tuple. default: [0,1]. Optional distribution for uniform generation of values.

Returns

Created vector filled with values.

@classmethod
def dense(cls, shape, dtype=<class 'pyspla.INT'>, fill_value=0):
440    @classmethod
441    def dense(cls, shape, dtype=INT, fill_value=0):
442        """
443        Creates new dense vector of specified shape and fills with desired value.
444
445        >>> v = Vector.dense(5, INT, 4)
446        >>> print(v)
447        '
448         0| 4
449         1| 4
450         2| 4
451         3| 4
452         4| 4
453        '
454
455        :param shape: int.
456            Size of the vector.
457
458        :param dtype: optional: Type. default: INT.
459            Type of values vector will have.
460
461        :param fill_value: optional: any. default: 0.
462            Optional value to fill with.
463
464        :return: Vector filled with value.
465        """
466
467        from .bridge import FormatVector
468
469        v = Vector(shape, dtype)
470        v.set_format(FormatVector.CPU_DENSE)
471
472        for i in range(shape):
473            v.set(i, fill_value)
474
475        return v

Creates new dense vector of specified shape and fills with desired value.

>>> v = Vector.dense(5, INT, 4)
>>> print(v)
'
 0| 4
 1| 4
 2| 4
 3| 4
 4| 4
'
Parameters
  • shape: int. Size of the vector.

  • dtype: optional: Type. default: INT. Type of values vector will have.

  • fill_value: optional: any. default: 0. Optional value to fill with.

Returns

Vector filled with value.

def vxm( self, mask, M, op_mult, op_add, op_select, out=None, init=None, desc=None):
477    def vxm(self, mask, M, op_mult, op_add, op_select, out=None, init=None, desc=None):
478        """
479        Masked sparse-vector by sparse-matrix product with dense mask.
480
481        >>> M = Matrix.from_lists([0, 1, 2, 2, 3], [1, 2, 0, 3, 2], [1, 2, 3, 4, 5], (4, 4), INT)
482        >>> v = Vector.from_lists([2], [1], 4, INT)
483        >>> mask = Vector.from_lists(list(range(4)), [1] * 4, 4, INT)
484        >>> print(v.vxm(mask, M, INT.LAND, INT.LOR, INT.GTZERO))
485        '
486         0| 1
487         1| .
488         2| .
489         3| 1
490        '
491
492        >>> M = Matrix.from_lists([0, 1, 2], [1, 2, 0], [1, 2, 3], (4, 4), INT)
493        >>> v = Vector.from_lists([0, 1, 2], [2, 3, 4], 4, INT)
494        >>> mask = Vector.from_lists(list(range(4)), [0] * 4, 4, INT)
495        >>> print(v.vxm(mask, M, INT.MULT, INT.PLUS, INT.EQZERO))
496        '
497         0|12
498         1| 2
499         2| 6
500         3| .
501        '
502
503        :param mask: Vector.
504            Vector to select for which values to compute product.
505
506        :param M: Matrix.
507            Matrix for a product.
508
509        :param op_mult: OpBinary.
510            Element-wise binary operator for matrix vector elements product.
511
512        :param op_add: OpBinary.
513            Element-wise binary operator for matrix vector products sum.
514
515        :param op_select: OpSelect.
516            Selection op to filter mask.
517
518        :param out: optional: Vector: default: None.
519            Optional vector to store result of product.
520
521        :param init: optional: Scalar: default: 0.
522            Optional neutral init value for reduction.
523
524        :param desc: optional: Descriptor. default: None.
525            Optional descriptor object to configure the execution.
526
527        :return: Vector with result.
528        """
529
530        if out is None:
531            out = Vector(shape=M.n_cols, dtype=self.dtype)
532        if init is None:
533            init = Scalar(dtype=self.dtype, value=0)
534
535        assert M
536        assert out
537        assert init
538        assert mask
539        assert out.dtype == self.dtype
540        assert M.dtype == self.dtype
541        assert mask.dtype == self.dtype
542        assert init.dtype == self.dtype
543        assert out.n_rows == M.n_cols
544        assert mask.n_rows == M.n_cols
545        assert M.n_rows == self.n_rows
546
547        check(backend().spla_Exec_vxm_masked(out.hnd, mask.hnd, self.hnd, M.hnd,
548                                             op_mult.hnd, op_add.hnd, op_select.hnd,
549                                             init.hnd, self._get_desc(desc), self._get_task(None)))
550
551        return out

Masked sparse-vector by sparse-matrix product with dense mask.

>>> M = Matrix.from_lists([0, 1, 2, 2, 3], [1, 2, 0, 3, 2], [1, 2, 3, 4, 5], (4, 4), INT)
>>> v = Vector.from_lists([2], [1], 4, INT)
>>> mask = Vector.from_lists(list(range(4)), [1] * 4, 4, INT)
>>> print(v.vxm(mask, M, INT.LAND, INT.LOR, INT.GTZERO))
'
 0| 1
 1| .
 2| .
 3| 1
'
>>> M = Matrix.from_lists([0, 1, 2], [1, 2, 0], [1, 2, 3], (4, 4), INT)
>>> v = Vector.from_lists([0, 1, 2], [2, 3, 4], 4, INT)
>>> mask = Vector.from_lists(list(range(4)), [0] * 4, 4, INT)
>>> print(v.vxm(mask, M, INT.MULT, INT.PLUS, INT.EQZERO))
'
 0|12
 1| 2
 2| 6
 3| .
'
Parameters
  • mask: Vector. Vector to select for which values to compute product.

  • M: Matrix. Matrix for a product.

  • op_mult: OpBinary. Element-wise binary operator for matrix vector elements product.

  • op_add: OpBinary. Element-wise binary operator for matrix vector products sum.

  • op_select: OpSelect. Selection op to filter mask.

  • out: optional: Vector: default: None. Optional vector to store result of product.

  • init: optional: Scalar: default: 0. Optional neutral init value for reduction.

  • desc: optional: Descriptor. default: None. Optional descriptor object to configure the execution.

Returns

Vector with result.

def eadd(self, op_add, v, out=None, desc=None):
553    def eadd(self, op_add, v, out=None, desc=None):
554        """
555        Element-wise add one vector to another and return result.
556
557        >>> u = Vector.from_lists([0, 1], [10, 20], 4, INT)
558        >>> v = Vector.from_lists([1, 3], [-5, 12], 4, INT)
559        >>> print(u.eadd(INT.PLUS, v))
560        '
561         0|10
562         1|15
563         2| .
564         3|12
565        '
566
567        :param op_add: OpBinary.
568            Binary operation to sum values.
569
570        :param v: Vector.
571            Other right vector to sum with this.
572
573        :param out: optional: Vector. default: None.
574            Optional vector to store result.
575
576        :param desc: optional: Descriptor. default: None.
577            Optional descriptor object to configure the execution.
578
579        :return: Vector with result.
580        """
581
582        if out is None:
583            out = Vector(shape=self.n_rows, dtype=self.dtype)
584
585        assert v
586        assert v.n_rows == self.n_rows
587        assert out.n_rows == self.n_rows
588        assert v.dtype == self.dtype
589        assert out.dtype == out.dtype
590        assert op_add
591
592        check(backend().spla_Exec_v_eadd(out.hnd, self.hnd, v.hnd, op_add.hnd,
593                                         self._get_desc(desc), self._get_task(None)))
594
595        return out

Element-wise add one vector to another and return result.

>>> u = Vector.from_lists([0, 1], [10, 20], 4, INT)
>>> v = Vector.from_lists([1, 3], [-5, 12], 4, INT)
>>> print(u.eadd(INT.PLUS, v))
'
 0|10
 1|15
 2| .
 3|12
'
Parameters
  • op_add: OpBinary. Binary operation to sum values.

  • v: Vector. Other right vector to sum with this.

  • out: optional: Vector. default: None. Optional vector to store result.

  • desc: optional: Descriptor. default: None. Optional descriptor object to configure the execution.

Returns

Vector with result.

def emult(self, op_mult, v, out=None, desc=None):
597    def emult(self, op_mult, v, out=None, desc=None):
598        """
599        Element-wise mult one vector to another and return result.
600
601        >>> u = Vector.from_lists([0, 1], [10, 20], 4, INT)
602        >>> v = Vector.from_lists([1, 3], [-5, 12], 4, INT)
603        >>> print(u.emult(INT.PLUS, v))
604        '
605         0| .
606         1|15
607         2| .
608         3| .
609        '
610
611        :param op_mult: OpBinary.
612            Binary operation to mult values.
613
614        :param v: Vector.
615            Other right vector to mult with this.
616
617        :param out: optional: Vector. default: None.
618            Optional vector to store result.
619
620        :param desc: optional: Descriptor. default: None.
621            Optional descriptor object to configure the execution.
622
623        :return: Vector with result.
624        """
625
626        if out is None:
627            out = Vector(shape=self.n_rows, dtype=self.dtype)
628
629        assert v
630        assert v.n_rows == self.n_rows
631        assert out.n_rows == self.n_rows
632        assert v.dtype == self.dtype
633        assert out.dtype == out.dtype
634        assert op_mult
635
636        check(backend().spla_Exec_v_emult(out.hnd, self.hnd, v.hnd, op_mult.hnd,
637                                          self._get_desc(desc), self._get_task(None)))
638
639        return out

Element-wise mult one vector to another and return result.

>>> u = Vector.from_lists([0, 1], [10, 20], 4, INT)
>>> v = Vector.from_lists([1, 3], [-5, 12], 4, INT)
>>> print(u.emult(INT.PLUS, v))
'
 0| .
 1|15
 2| .
 3| .
'
Parameters
  • op_mult: OpBinary. Binary operation to mult values.

  • v: Vector. Other right vector to mult with this.

  • out: optional: Vector. default: None. Optional vector to store result.

  • desc: optional: Descriptor. default: None. Optional descriptor object to configure the execution.

Returns

Vector with result.

def assign(self, mask, value, op_assign, op_select, desc=None):
641    def assign(self, mask, value, op_assign, op_select, desc=None):
642        """
643        Assign scalar value to a vector by mask.
644
645        >>> v = Vector(4, INT)
646        >>> m = Vector.from_lists([0, 1, 3], [1, 0, 1], 4, INT)
647        >>> s = Scalar(INT, 4)
648        >>> v.assign(mask=m, value=s, op_assign=INT.SECOND, op_select=INT.GTZERO)
649        >>> print(v)
650        '
651         0| 4
652         1| .
653         2| .
654         3| 4
655        '
656
657        :param mask: Vector.
658            Mask vector which structure will be used to select entries for assignment.
659
660        :param value: Scalar.
661            Value to assign.
662
663        :param op_assign: OpBinary.
664            Binary operation used to combine existing value in vector and scalar.
665
666        :param op_select: OpSelect.
667            Predicate to select entries in the mask to assign.
668
669        :param desc: optional: Descriptor. default: None.
670            Optional descriptor object to configure the execution.
671
672        :return: This vector.
673        """
674
675        assert mask
676        assert value
677        assert mask.n_rows == self.n_rows
678        assert op_assign
679        assert op_select
680
681        check(backend().spla_Exec_v_assign_masked(self.hnd, mask.hnd, value.hnd, op_assign.hnd, op_select.hnd,
682                                                  self._get_desc(desc), self._get_task(None)))
683
684        return self

Assign scalar value to a vector by mask.

>>> v = Vector(4, INT)
>>> m = Vector.from_lists([0, 1, 3], [1, 0, 1], 4, INT)
>>> s = Scalar(INT, 4)
>>> v.assign(mask=m, value=s, op_assign=INT.SECOND, op_select=INT.GTZERO)
>>> print(v)
'
 0| 4
 1| .
 2| .
 3| 4
'
Parameters
  • mask: Vector. Mask vector which structure will be used to select entries for assignment.

  • value: Scalar. Value to assign.

  • op_assign: OpBinary. Binary operation used to combine existing value in vector and scalar.

  • op_select: OpSelect. Predicate to select entries in the mask to assign.

  • desc: optional: Descriptor. default: None. Optional descriptor object to configure the execution.

Returns

This vector.

def map(self, op_map, out=None, desc=None):
686    def map(self, op_map, out=None, desc=None):
687        """
688        Map this vector by applying element-wise unary function to each element.
689
690        >>> v = Vector.from_lists([0, 1, 3], [5, -1, 3], 4, INT)
691        >>> print(v.map(INT.AINV))
692        '
693         0|-5
694         1| 1
695         2| .
696         3|-3
697        '
698
699        :param op_map: OpUnary.
700            Unary operation to apply to transform values.
701
702        :param out: optional: Vector. default: None.
703            Optional vector where to store result.
704
705        :param desc: optional: Descriptor. default: None.
706            Optional descriptor object to configure the execution.
707
708        :return: Result of a map as vector.
709        """
710
711        if out is None:
712            out = Vector(self.n_rows, self.dtype)
713
714        assert out
715        assert op_map
716        assert out.n_rows == self.n_rows
717        assert out.dtype == self.dtype
718
719        check(backend().spla_Exec_v_map(out.hnd, self.hnd, op_map.hnd,
720                                        self._get_desc(desc), self._get_task(None)))
721
722        return out

Map this vector by applying element-wise unary function to each element.

>>> v = Vector.from_lists([0, 1, 3], [5, -1, 3], 4, INT)
>>> print(v.map(INT.AINV))
'
 0|-5
 1| 1
 2| .
 3|-3
'
Parameters
  • op_map: OpUnary. Unary operation to apply to transform values.

  • out: optional: Vector. default: None. Optional vector where to store result.

  • desc: optional: Descriptor. default: None. Optional descriptor object to configure the execution.

Returns

Result of a map as vector.

def reduce(self, op_reduce, out=None, init=None, desc=None):
724    def reduce(self, op_reduce, out=None, init=None, desc=None):
725        """
726        Reduce vector elements.
727
728        >>> v = Vector.from_lists([0, 1, 2], [-1, 2, 5], 4, INT)
729        >>> print(v.reduce(op_reduce=INT.PLUS))
730        '
731            6
732        '
733
734        >>> v = Vector.from_lists([0, 1, 2], [-0.5, 4.0, 12.3], 4, FLOAT)
735        >>> print(v.reduce(op_reduce=FLOAT.MAX))
736        '
737            12.3
738        '
739
740        :param op_reduce: OpBinary.
741            Binary operation to apply for reduction of vector elements.
742
743        :param out: optional: Scalar: default: 0.
744            Optional scalar to store result of reduction.
745
746        :param init: optional: Scalar: default: 0.
747            Optional neutral init value for reduction.
748
749        :param desc: optional: Descriptor. default: None.
750            Optional descriptor object to configure the execution.
751
752        :return: Scalar value with result.
753        """
754
755        if out is None:
756            out = Scalar(dtype=self.dtype)
757        if init is None:
758            init = Scalar(dtype=self.dtype, value=0)
759
760        assert out.dtype == self.dtype
761        assert init.dtype == self.dtype
762
763        check(backend().spla_Exec_v_reduce(out.hnd, init.hnd, self.hnd, op_reduce.hnd,
764                                           self._get_desc(desc), self._get_task(None)))
765
766        return out

Reduce vector elements.

>>> v = Vector.from_lists([0, 1, 2], [-1, 2, 5], 4, INT)
>>> print(v.reduce(op_reduce=INT.PLUS))
'
    6
'
>>> v = Vector.from_lists([0, 1, 2], [-0.5, 4.0, 12.3], 4, FLOAT)
>>> print(v.reduce(op_reduce=FLOAT.MAX))
'
    12.3
'
Parameters
  • op_reduce: OpBinary. Binary operation to apply for reduction of vector elements.

  • out: optional: Scalar: default: 0. Optional scalar to store result of reduction.

  • init: optional: Scalar: default: 0. Optional neutral init value for reduction.

  • desc: optional: Descriptor. default: None. Optional descriptor object to configure the execution.

Returns

Scalar value with result.

Inherited Members
Object
hnd
label
class Scalar(pyspla.Object):
 37class Scalar(Object):
 38    """
 39    Generalized statically-typed scalar primitive.
 40
 41    Notes
 42    -----
 43
 44    Scalar typical usage:
 45
 46    - Create scalar from python value
 47    - Pass scalar as argument to matrix/vector operation
 48    - Get scalar as a return value of some operation
 49    - Unpack value on python side
 50
 51    Avoid intensive creation of scalar values. Prefer python native types.
 52    Use scalars only if you want to parametrise matrix/vector operations.
 53
 54    Details
 55    -------
 56
 57    Scalar class support all spla C API scalar functions.
 58    It provides bind functionality as well as new functions/methods for better python user experience.
 59
 60    Scalar internally stored in the native format of the type it has.
 61    Meta-data additionally stored with each scalar value.
 62    """
 63
 64    __slots__ = ["_dtype"]
 65
 66    def __init__(self, dtype=INT, value=None, hnd=None, label=None):
 67        """
 68        Creates new scalar of desired type or retains existing C object.
 69
 70        >>> s = Scalar(INT, 10)
 71        >>> print(s)
 72        '
 73            10
 74        '
 75
 76        :param dtype: optional: Type. default: INT.
 77            Type of the scalar value.
 78
 79        :param value: optional: Any. default: None.
 80            Optional value to store in scalar on creation.
 81
 82        :param hnd: optional: ctypes.c_void_p. default: None.
 83            Optional handle to C object to retain in this scalar instance.
 84
 85        :param label: optional: str. default: None.
 86            Optional debug label of the scalar.
 87        """
 88
 89        super().__init__(None, None)
 90
 91        self._dtype = dtype
 92
 93        if hnd is None:
 94            hnd = ctypes.c_void_p(0)
 95            check(backend().spla_Scalar_make(ctypes.byref(hnd), dtype._hnd))
 96
 97        super().__init__(label, hnd)
 98        self.set(value)
 99
100    @property
101    def dtype(self):
102        """
103        Returns the type of stored value in the scalar.
104
105        >>> s = Scalar(INT)
106        >>> print(s.dtype)
107        '
108            <class 'pyspla.type.INT'>
109        '
110        """
111
112        return self._dtype
113
114    @property
115    def shape(self):
116        """
117        2-tuple shape of the storage. For scalar object it is always 1 by 1.
118
119        >>> s = Scalar(INT)
120        >>> print(s.shape)
121        '
122            (1, 1)
123        '
124        """
125
126        return 1, 1
127
128    @property
129    def n_vals(self):
130        """
131        Number of stored values in the scalar. Always 1.
132
133        >>> s = Scalar(INT)
134        >>> print(s.n_vals)
135        '
136            1
137        '
138        """
139
140        return 1
141
142    @classmethod
143    def from_value(cls, value):
144        """
145        Create scalar and infer type.
146
147        >>> s = Scalar.from_value(0.5)
148        >>> print(s.dtype)
149        '
150            <class 'pyspla.type.FLOAT'>
151        '
152
153        :param value: any.
154            Value to create scalar from.
155
156        :return: Scalar with value.
157        """
158
159        if isinstance(value, float):
160            return Scalar(dtype=FLOAT, value=value)
161        elif isinstance(value, int):
162            return Scalar(dtype=INT, value=value)
163        elif isinstance(value, bool):
164            return Scalar(dtype=INT, value=value)
165        else:
166            raise Exception("cannot infer type")
167
168    def set(self, value=None):
169        """
170        Set the value stored in the scalar. If no value passed the default value is set.
171
172        >>> s = Scalar(INT)
173        >>> s.set(10)
174        >>> print(s)
175        '
176            10
177        '
178
179        :param value: optional: Any. default: None.
180            Optional value to store in scalar.
181        """
182
183        check(self._dtype._scalar_set(self._hnd, self._dtype._c_type(value if value else 0)))
184
185    def get(self):
186        """
187        Read the value stored in the scalar.
188
189        >>> s = Scalar(INT, 10)
190        >>> print(s.get())
191        '
192            10
193        '
194
195        :return: Value from scalar.
196        """
197
198        value = self._dtype._c_type(0)
199        check(self._dtype._scalar_get(self._hnd, ctypes.byref(value)))
200        return self._dtype.cast_value(value)
201
202    def __str__(self):
203        return str(self.get())
204
205    def __iter__(self):
206        return iter([self.get()])
207
208    def __add__(self, other):
209        return Scalar(dtype=self.dtype, value=self.get() + Scalar._value(other))
210
211    def __sub__(self, other):
212        return Scalar(dtype=self.dtype, value=self.get() + Scalar._value(other))
213
214    def __mul__(self, other):
215        return Scalar(dtype=self.dtype, value=self.get() * Scalar._value(other))
216
217    def __truediv__(self, other):
218        return Scalar(dtype=self.dtype, value=self.get() / Scalar._value(other))
219
220    def __floordiv__(self, other):
221        return Scalar(dtype=self.dtype, value=self.get() // Scalar._value(other))
222
223    def __iadd__(self, other):
224        self.set(self.get() + Scalar._value(other))
225        return self
226
227    def __isub__(self, other):
228        self.set(self.get() - Scalar._value(other))
229        return self
230
231    def __imul__(self, other):
232        self.set(self.get() * Scalar._value(other))
233        return self
234
235    def __idiv__(self, other):
236        self.set(self.get() / Scalar._value(other))
237        return self
238
239    @classmethod
240    def _value(cls, other):
241        if isinstance(other, Scalar):
242            return other.get()
243        else:
244            return other

Generalized statically-typed scalar primitive.

Notes

Scalar typical usage:

  • Create scalar from python value
  • Pass scalar as argument to matrix/vector operation
  • Get scalar as a return value of some operation
  • Unpack value on python side

Avoid intensive creation of scalar values. Prefer python native types. Use scalars only if you want to parametrise matrix/vector operations.

Details

Scalar class support all spla C API scalar functions. It provides bind functionality as well as new functions/methods for better python user experience.

Scalar internally stored in the native format of the type it has. Meta-data additionally stored with each scalar value.

Scalar(dtype=<class 'pyspla.INT'>, value=None, hnd=None, label=None)
66    def __init__(self, dtype=INT, value=None, hnd=None, label=None):
67        """
68        Creates new scalar of desired type or retains existing C object.
69
70        >>> s = Scalar(INT, 10)
71        >>> print(s)
72        '
73            10
74        '
75
76        :param dtype: optional: Type. default: INT.
77            Type of the scalar value.
78
79        :param value: optional: Any. default: None.
80            Optional value to store in scalar on creation.
81
82        :param hnd: optional: ctypes.c_void_p. default: None.
83            Optional handle to C object to retain in this scalar instance.
84
85        :param label: optional: str. default: None.
86            Optional debug label of the scalar.
87        """
88
89        super().__init__(None, None)
90
91        self._dtype = dtype
92
93        if hnd is None:
94            hnd = ctypes.c_void_p(0)
95            check(backend().spla_Scalar_make(ctypes.byref(hnd), dtype._hnd))
96
97        super().__init__(label, hnd)
98        self.set(value)

Creates new scalar of desired type or retains existing C object.

>>> s = Scalar(INT, 10)
>>> print(s)
'
    10
'
Parameters
  • dtype: optional: Type. default: INT. Type of the scalar value.

  • value: optional: Any. default: None. Optional value to store in scalar on creation.

  • hnd: optional: ctypes.c_void_p. default: None. Optional handle to C object to retain in this scalar instance.

  • label: optional: str. default: None. Optional debug label of the scalar.

dtype

Returns the type of stored value in the scalar.

>>> s = Scalar(INT)
>>> print(s.dtype)
'
    <class 'pyspla.INT'>
'
shape

2-tuple shape of the storage. For scalar object it is always 1 by 1.

>>> s = Scalar(INT)
>>> print(s.shape)
'
    (1, 1)
'
n_vals

Number of stored values in the scalar. Always 1.

>>> s = Scalar(INT)
>>> print(s.n_vals)
'
    1
'
@classmethod
def from_value(cls, value):
142    @classmethod
143    def from_value(cls, value):
144        """
145        Create scalar and infer type.
146
147        >>> s = Scalar.from_value(0.5)
148        >>> print(s.dtype)
149        '
150            <class 'pyspla.type.FLOAT'>
151        '
152
153        :param value: any.
154            Value to create scalar from.
155
156        :return: Scalar with value.
157        """
158
159        if isinstance(value, float):
160            return Scalar(dtype=FLOAT, value=value)
161        elif isinstance(value, int):
162            return Scalar(dtype=INT, value=value)
163        elif isinstance(value, bool):
164            return Scalar(dtype=INT, value=value)
165        else:
166            raise Exception("cannot infer type")

Create scalar and infer type.

>>> s = Scalar.from_value(0.5)
>>> print(s.dtype)
'
    <class 'pyspla.FLOAT'>
'
Parameters
  • value: any. Value to create scalar from.
Returns

Scalar with value.

def set(self, value=None):
168    def set(self, value=None):
169        """
170        Set the value stored in the scalar. If no value passed the default value is set.
171
172        >>> s = Scalar(INT)
173        >>> s.set(10)
174        >>> print(s)
175        '
176            10
177        '
178
179        :param value: optional: Any. default: None.
180            Optional value to store in scalar.
181        """
182
183        check(self._dtype._scalar_set(self._hnd, self._dtype._c_type(value if value else 0)))

Set the value stored in the scalar. If no value passed the default value is set.

>>> s = Scalar(INT)
>>> s.set(10)
>>> print(s)
'
    10
'
Parameters
  • value: optional: Any. default: None. Optional value to store in scalar.
def get(self):
185    def get(self):
186        """
187        Read the value stored in the scalar.
188
189        >>> s = Scalar(INT, 10)
190        >>> print(s.get())
191        '
192            10
193        '
194
195        :return: Value from scalar.
196        """
197
198        value = self._dtype._c_type(0)
199        check(self._dtype._scalar_get(self._hnd, ctypes.byref(value)))
200        return self._dtype.cast_value(value)

Read the value stored in the scalar.

>>> s = Scalar(INT, 10)
>>> print(s.get())
'
    10
'
Returns

Value from scalar.

Inherited Members
Object
hnd
label
VERSIONS = ['0.0.0', '0.0.1', '0.0.2', '0.0.3', '0.0.4', '0.0.5']