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:
- Package page: https://pypi.org/project/pyspla
- Package page (test): https://test.pypi.org/project/pyspla
- Source code: https://github.com/SparseLinearAlgebra/spla
- Contributing: https://github.com/SparseLinearAlgebra/spla/CONTRIBUTING.md
- Development: https://github.com/SparseLinearAlgebra/spla/DEVELOPMENT.md
- Examples: https://github.com/SparseLinearAlgebra/spla/EXAMPLES.md
- C/C++ API Reference: https://SparseLinearAlgebra.github.io/spla/docs-cpp
- Bug report: https://github.com/SparseLinearAlgebra/spla/issues
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
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
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
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]
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 |
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.
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.
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.
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.
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.
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.
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.
Transforms native C value into python value.
Parameters
- value: any. Ctypes value to unpack to python value.
Returns
Transformed value.
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.
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 |
Inherited Members
- enum.Enum
- name
- value
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 |
Inherited Members
- enum.Enum
- name
- value
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
Type used for storage parametrization of this container.
>>> M = Matrix((4, 5), INT)
>>> print(M.dtype)
'
<class 'pyspla.INT'>
'
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.
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.
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.
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.
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.
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.
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.
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).
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.
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.
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.
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.
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.
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.
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.
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.
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 usedmult
.
Returns
Kronecker power of a matrix.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
Type used for storage parametrization of this container.
>>> v = Vector(5, INT)
>>> print(v.dtype)
'
<class 'pyspla.INT'>
'
2-Tuple with shape of vector where second value is always 1.
>>> v = Vector(5, INT)
>>> print(v.shape)
'
(5, 1)
'
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
Returns the type of stored value in the scalar.
>>> s = Scalar(INT)
>>> print(s.dtype)
'
<class 'pyspla.INT'>
'
2-tuple shape of the storage. For scalar object it is always 1 by 1.
>>> s = Scalar(INT)
>>> print(s.shape)
'
(1, 1)
'
Number of stored values in the scalar. Always 1.
>>> s = Scalar(INT)
>>> print(s.n_vals)
'
1
'
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.
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.
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.