GraphBLAS的Python接口
项目描述
grblas
已弃用: grblas
已重命名。请使用 python-graphblas
(PyPI) (github)。
GraphBLAS的Python包装器
安装,请使用 conda install -c conda-forge grblas
或 pip install grblas
。这将还会安装SuiteSparse graphblas
编译的C库。
目前与 SuiteSparse:GraphBLAS 兼容,但目标是使其与所有GraphBLAS规范的实现兼容。
本库采用的方法是尽可能遵循C-API规范,同时在允许的Python语法范围内进行改进。因为规范总是传递要写入的输出对象,所以我们遵循同样的方法,这与Python通常的操作方式非常不同。实际上,熟悉其他Python数据库(如numpy、pandas等)的人会发现,对于每次调用都不创建新对象感到很奇怪。
在最高层面,目标是把输出、掩码和累加器放在赋值运算符=
的左侧,把计算放在右侧。不幸的是,这种方法并不总是与Python处理赋值的方式很好地结合,所以我们(滥用)左移<<
的符号来赋予相同的赋值感觉。这打开了许多美好的可能性。
这是一个说明映射如何工作的例子
// C call
GrB_Matrix_mxm(M, mask, GrB_PLUS_INT64, GrB_MIN_PLUS_INT64, A, B, NULL)
# Python call
M(mask.V, accum=binary.plus) << A.mxm(B, semiring.min_plus)
右侧的表达式A.mxm(B)
创建一个延迟对象,它不会进行计算。一旦它被用于与M
一起的<<
表达式中,整个表达式就会被翻译成等价的GraphBLAS调用。
延迟对象还有一个.new()
方法,可以用来强制计算并返回一个新的对象。这很方便,而且通常很合适,但如果在循环中使用,将会创建许多不必要的对象。它还失去了使用现有结果进行累加的能力。为了获得最佳性能,遵循GraphBLAS的标准方法(1)在循环外创建对象和(2)在每次循环中重复使用对象,即使这并不符合Python的风格,也是一个更好的方法。
在适当元素上设置描述符标志,以保持逻辑与它所影响的内容紧密相关。以下是设置描述符位相同的调用。ttcsr
表示转置第一和第二矩阵,补充掩码的结构,并在输出上进行替换。
// C call
GrB_Matrix_mxm(M, mask, GrB_PLUS_INT64, GrB_MIN_PLUS_INT64, A, B, desc.ttcsr)
# Python call
M(~mask.S, accum=binary.plus, replace=True) << A.T.mxm(B.T, semiring.min_plus)
接收标志操作的对象(如A.T、~mask等)也是延迟对象。它们保持状态但不进行计算,允许在单个GraphBLAS调用中设置正确的描述符位。
如果没有使用掩码或累加器,调用看起来像这样:
M << A.mxm(B, semiring.min_plus)
使用<<
来表示更新实际上只是真实.update()
方法的语法糖。上面的表达式可以写成
M.update(A.mxm(B, semiring.min_plus))
操作
M(mask, accum) << A.mxm(B, semiring) # mxm
w(mask, accum) << A.mxv(v, semiring) # mxv
w(mask, accum) << v.vxm(B, semiring) # vxm
M(mask, accum) << A.ewise_add(B, binaryop) # eWiseAdd
M(mask, accum) << A.ewise_mult(B, binaryop) # eWiseMult
M(mask, accum) << A.kronecker(B, binaryop) # kronecker
M(mask, accum) << A.T # transpose
提取
M(mask, accum) << A[rows, cols] # rows and cols are a list or a slice
w(mask, accum) << A[rows, col_index] # extract column
w(mask, accum) << A[row_index, cols] # extract row
s = A[row_index, col_index].value # extract single element
分配
M(mask, accum)[rows, cols] << A # rows and cols are a list or a slice
M(mask, accum)[rows, col_index] << v # assign column
M(mask, accum)[row_index, cols] << v # assign row
M(mask, accum)[rows, cols] << s # assign scalar to many elements
M[row_index, col_index] << s # assign scalar to single element
# (mask and accum not allowed)
del M[row_index, col_index] # remove single element
应用
M(mask, accum) << A.apply(unaryop)
M(mask, accum) << A.apply(binaryop, left=s) # bind-first
M(mask, accum) << A.apply(binaryop, right=s) # bind-second
归约
v(mask, accum) << A.reduce_rowwise(op) # reduce row-wise
v(mask, accum) << A.reduce_columnwise(op) # reduce column-wise
s(accum) << A.reduce_scalar(op)
s(accum) << v.reduce(op)
创建新的向量/矩阵
A = Matrix.new(dtype, num_rows, num_cols) # new_type
B = A.dup() # dup
A = Matrix.from_values([row_indices], [col_indices], [values]) # build
从延迟创建
延迟对象可以用于使用.new()
方法创建新对象
C = A.mxm(B, semiring).new()
属性
size = v.size # size
nrows = M.nrows # nrows
ncols = M.ncols # ncols
nvals = M.nvals # nvals
rindices, cindices, vals = M.to_values() # extractTuples
初始化
存在一种机制,可以在使用之前使用上下文初始化grblas
。这允许设置要使用的后端以及阻塞/非阻塞模式。如果没有初始化上下文,将自动执行默认初始化。
import grblas as gb
# Context initialization must happen before any other imports
gb.init('suitesparse', blocking=True)
# Now we can import other items from grblas
from grblas import binary, semiring
from grblas import Matrix, Vector, Scalar
高效的用户定义函数
grblas
需要numba
,这可以使用户定义的Python函数编译成原生C,以便在GraphBLAS中使用。
示例自定义一元运算符
from grblas import unary
from grblas.operator import UnaryOp
def force_odd_func(x):
if x % 2 == 0:
return x + 1
return x
UnaryOp.register_new('force_odd', force_odd_func)
v = Vector.from_values([0, 1, 3], [1, 2, 3])
w = v.apply(unary.force_odd).new()
w # indexes=[0, 1, 3], values=[1, 3, 3]
类似的函数也存在于二元运算符、幺半群和半环。
导入/导出连接到Python生态系统
grblas.io
包含用于转换到和从的功能
import grblas as gb
# numpy arrays
# 1-D array becomes Vector, 2-D array becomes Matrix
A = gb.io.from_numpy(m)
m = gb.io.to_numpy(A)
# scipy.sparse matrices
A = gb.io.from_scipy_sparse_matrix(m)
m = gb.io.to_scipy_sparse_matrix(m, format='csr')
# networkx graphs
A = gb.io.from_networkx(g)
g = gb.io.to_networkx(A)
归属
这个库借鉴了pygraphblas的一些优秀想法,特别是在解析SuiteSparse运算符名称和关于标量(后端实现不需要了解)的概念。
grblas-2022.4.0.1.tar.gz的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | c4b3233538fa7e30e277fb7bca5f0871bfcacafb02262ed09b1598a5de86de76 |
|
MD5 | a7cfe4860ca8b6974a528cb84b0785bf |
|
BLAKE2b-256 | 480f5d8d58e3f709ef233b6b1a373393e424e576c0f4b4c5709c0da677217bfd |
grblas-2022.4.0.1-py3-none-any.whl的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | d3f8ce4fa524ac090bbdf0e3c7a2338f983fcded71719e6d8123adf7bea58da9 |
|
MD5 | 07f980620dc9c94ab372c63f5e0449f9 |
|
BLAKE2b-256 | da8a254820e1c3c76de164d51e3ab6e31678e6e6a553f65612b7d002ffb5defc |