GraphBLAS的Python库:用于可扩展图分析的高性能稀疏线性代数
项目描述
Python GraphBLAS 库:用于可扩展图分析的高性能稀疏线性代数。有关算法,请参阅 graphblas-algorithms
。
- 文档: https://python-graphblas.readthedocs.io/
- 常见问题解答: https://python-graphblas.readthedocs.io/en/stable/getting_started/faq.html
- GraphBLAS C API: https://graphblas.org/docs/GraphBLAS_API_C_v2.0.0.pdf
- SuiteSparse:GraphBLAS 用户指南: https://github.com/DrTimothyAldenDavis/GraphBLAS/raw/stable/Doc/GraphBLAS_UserGuide.pdf
- 源代码: https://github.com/python-graphblas/python-graphblas
- 错误报告: https://github.com/python-graphblas/python-graphblas/issues
- Github 讨论区: https://github.com/python-graphblas/python-graphblas/discussions
- 每周社区会议: python-graphblas#247 或 https://scientific-python.cn/calendars/
- 通过 Discord 聊天: https://discord.com/invite/vur45CbwMz 在 #graphblas 通道
安装
通过 conda 安装 Python-graphblas 的最新版本
$ conda install -c conda-forge python-graphblas
或 pip
$ pip install python-graphblas[default]
这将还会安装 SuiteSparse:GraphBLAS 编译的 C 库。我们目前支持 GraphBLAS C API 2.0 规范。
可选依赖
以下不是 python-graphblas 所必需的,但可能对于某些功能的正常工作可能是必要的。
pandas
– 需要更好的__repr__
;matplotlib
– 需要基本的图形绘制;scipy
– 在io
模块中用于读取/写入scipy.sparse
格式;networkx
– 在io
模块中用于与networkx
图交互;fast-matrix-market
- 用于使用gb.io.mmread
和gb.io.mmwrite
快速读取/写入 Matrix Market 文件。
描述
目前与 SuiteSparse:GraphBLAS 兼容,但目标是使其与 GraphBLAS 规范的所有实现兼容。
本库采用的方法是尽可能遵循 C-API 2.0 规范,同时在 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_coo([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_coo() # extractTuples
初始化
存在一种机制在使用之前初始化graphblas
的上下文。这允许设置要使用的后端以及阻塞/非阻塞模式。如果没有初始化上下文,将自动执行默认初始化。
import graphblas as gb
# Context initialization must happen before any other imports
gb.init("suitesparse", blocking=True)
# Now we can import other items from graphblas
from graphblas import binary, semiring
from graphblas import Matrix, Vector, Scalar
高效的用户自定义函数
Python-graphblas需要numba
,它可以将用户定义的Python函数编译为原生C以用于GraphBLAS。
示例自定义一元运算符
from graphblas import unary
def force_odd_func(x):
if x % 2 == 0:
return x + 1
return x
unary.register_new("force_odd", force_odd_func)
v = Vector.from_coo([0, 1, 3], [1, 2, 3])
w = v.apply(unary.force_odd).new()
w # indexes=[0, 1, 3], values=[1, 3, 3]
对于二元运算符、幺半群和半环也存在类似的方法。
与其他网络分析库的关系
Python-graphblas旨在通过线性代数提供高效的图形操作的统一表达。这允许开发现有和新图形算法的高性能实现(也请参阅graphblas-algorithms
)。
虽然可以使用python-graphblas
进行端到端分析,但用户可能会发现Python生态系统中的其他库提供了更方便的高级接口进行数据预处理和转换(例如pandas
、scipy.sparse
),可视化(例如networkx
、igraph
),交互式探索和分析(例如networkx
、igraph
),或者对于尚未在graphblas-algorithms
中实现的算法(例如networkx
、igraph
、scipy.sparse.csgraph
)。为了方便与其他库通信,graphblas.io
包含多个连接器,请参阅以下部分。
导入/导出连接到Python生态系统
graphblas.io
包含用于转换到和从的功能
import graphblas as gb
# scipy.sparse matrices
A = gb.io.from_scipy_sparse(m)
m = gb.io.to_scipy_sparse(m, format="csr")
# networkx graphs
A = gb.io.from_networkx(g)
g = gb.io.to_networkx(A)
# numpy arrays can use `from_dense` and `to_dense` on Vector and Matrix
v = gb.Vector.from_dense(m)
m = v.to_dense()
A = gb.Matrix.from_dense(m, missing_value=0)
m = A.to_dense(fill_value=0)
项目详情
下载文件
下载适合您平台的文件。如果您不确定选择哪一个,请了解有关 安装包 的更多信息。