操作#
矩阵乘法#
GraphBLAS 规范包含三种矩阵乘法方法,具体取决于输入是矩阵还是向量。
mxm – 矩阵-矩阵乘法
mxv – 矩阵-向量乘法
vxm – 向量-矩阵乘法
这三种方法存在于python-graphblas集合中,但首选方法是使用@
符号,该符号在Python中表示矩阵乘法。
矩阵乘法的默认半环是 plus_times
,但可以使用任何半环代替。
向量没有自然的行或列方向。然而,当在矩阵的左侧相乘时,向量被视为1xn的行矩阵。当在矩阵的右侧相乘时,向量被视为nx1的列矩阵。
矩阵-矩阵 乘法示例:
A = gb.Matrix.from_coo(
[0, 0, 1, 1, 2],
[1, 2, 2, 3, 3],
[2., 5., 1.5, 4.25, 0.5],
nrows=4,
ncols=4
)
B = gb.Matrix.from_coo(
[0, 0, 1, 1, 2, 2, 3, 3],
[1, 2, 0, 1, 1, 2, 0, 1],
[3., 2., 9., 6., 3., 1., 0., 5.]
)
C = gb.Matrix(float, A.nrows, B.ncols)
# These are equivalent
C << A.mxm(B, op="min_plus") # method style
C << gb.semiring.min_plus(A @ B) # functional style
0 |
1 |
2 |
3 |
|
---|---|---|---|---|
0 |
2.0 |
5.0 |
||
1 |
1.5 |
4.25 |
||
2 |
0.5 |
|||
3 |
0 |
1 |
2 |
|
---|---|---|---|
0 |
3.0 |
2.0 |
|
1 |
9.0 |
6.0 |
|
2 |
3.0 |
1.0 |
|
3 |
0.0 |
5.0 |
0 |
1 |
2 |
|
---|---|---|---|
0 |
11.0 |
8.0 |
6.0 |
1 |
4.25 |
4.5 |
2.5 |
2 |
0.5 |
5.0 |
|
3 |
矩阵-向量 乘法示例:
A = gb.Matrix.from_coo(
[0, 0, 1, 1, 2],
[1, 2, 2, 3, 3],
[2., 5., 1.5, 4.25, 0.5],
nrows=4,
ncols=4
)
v = gb.Vector.from_coo([0, 1, 3], [10., 20., 40.])
w = gb.Vector(float, A.nrows)
# These are equivalent
w << A.mxv(v, op="plus_times") # method style
w << gb.semiring.plus_times(A @ v) # functional style
0 |
1 |
2 |
3 |
|
---|---|---|---|---|
0 |
2.0 |
5.0 |
||
1 |
1.5 |
4.25 |
||
2 |
0.5 |
|||
3 |
0 |
1 |
2 |
3 |
---|---|---|---|
10.0 |
20.0 |
40.0 |
0 |
1 |
2 |
3 |
---|---|---|---|
40.0 |
170.0 |
20.0 |
向量-矩阵 乘法示例:
v = gb.Vector.from_coo([0, 1, 3], [10., 20., 40.])
B = gb.Matrix.from_coo(
[0, 0, 1, 1, 2, 2, 3, 3],
[1, 2, 0, 1, 1, 2, 0, 1],
[3., 2., 9., 6., 3., 1., 0., 5.]
)
u = gb.Vector(float, B.ncols)
# These are equivalent
u << v.vxm(B, op="plus_plus") # method style
u << gb.semiring.plus_plus(v @ B) # functional style
0 |
1 |
2 |
3 |
---|---|---|---|
10.0 |
20.0 |
40.0 |
0 |
1 |
2 |
|
---|---|---|---|
0 |
3.0 |
2.0 |
|
1 |
9.0 |
6.0 |
|
2 |
3.0 |
1.0 |
|
3 |
0.0 |
5.0 |
0 |
1 |
2 |
---|---|---|
69.0 |
84.0 |
12.0 |
元素级交集#
两个形状相同的集合可以逐元素相交。在两个集合中只有一个集合包含值的位置将在输出中缺失。
GraphBLAS 规范将此操作称为 eWiseMult
,因为当缺失值被视为零时,它具有与稀疏乘法相同的行为。因此,binary.times
是元素级交集的默认操作符。
该方法被命名为ewise_mult
,遵循规范。函数语法使用Python的交集符号&
。
示例用法:
A = gb.Matrix.from_coo(
[0, 0, 1, 1, 2],
[1, 2, 0, 2, 1],
[2., 5., 1.5, 4., 0.5]
)
B = gb.Matrix.from_coo(
[0, 0, 1, 1, 2, 2],
[1, 2, 0, 1, 1, 2],
[3., -2., 0., 6., 3., 1.]
)
C = gb.Matrix(float, A.nrows, A.ncols)
# These are equivalent
C << A.ewise_mult(B, op="min") # method style
C << gb.binary.min(A & B) # functional style
0 |
1 |
2 |
|
---|---|---|---|
0 |
2.0 |
5.0 |
|
1 |
1.5 |
4.0 |
|
2 |
0.5 |
0 |
1 |
2 |
|
---|---|---|---|
0 |
3.0 |
-2.0 |
|
1 |
0.0 |
6.0 |
|
2 |
3.0 |
1.0 |
0 |
1 |
2 |
|
---|---|---|---|
0 |
2.0 |
-2.0 |
|
1 |
0.0 |
||
2 |
0.5 |
元素级联合#
两个形状相同的集合可以逐元素进行并集操作。在两个集合中只有一个包含值的位置,输出中将包含该值。在它们重叠的地方,操作符将计算结果。
GraphBLAS 规范将此操作称为 eWiseAdd
,因为当缺失值被视为零时,它具有与稀疏加法相同的行为。因此,binary.plus
是元素级联合的默认操作符。
在python-graphblas中有两种方法用于元素级别的联合。
ewise_add
这是基于规范的官方方法。它遵循规范,在没有重叠时直接使用单个值。对于关联的二元操作(加、与、最小等),ewise_add 总是给出正确的答案。然而,当操作不关联时(减、除等),ewise_add 可能会有令人惊讶的结果。
7 - 3 = 4
7 - missing = 7
missing - 7 = 7
<– 这可能看起来出乎意料,但它是正确的
ewise_union
这是由SuiteSparse:GraphBLAS提供的扩展。它添加了一个
left_default
和right_default
参数,用于指定当只有一个值时缺失值应该是什么。如果我们设置
left_default=0
和right_default=0
,那么
7 - 3 = 4
7 - missing = 7 - 0 = 7
missing - 7 = 0 - 7 = -7
<– 这给出了预期的答案
函数语法使用Python的并集符号|
来表示两种方法。要指定ewise_union
应与函数语法一起使用,需要使用left_default
和right_default
关键字。
eWiseAdd 示例:
A = gb.Matrix.from_coo(
[0, 0, 0, 1, 1],
[0, 1, 2, 0, 2],
[9., 2., 5., 1.5, 4.],
nrows=3
)
B = gb.Matrix.from_coo(
[0, 0, 0, 2, 2, 2],
[0, 1, 2, 0, 1, 2],
[4., 0., -2., 6., 3., 1.]
)
C = gb.Matrix(float, A.nrows, A.ncols)
# These are equivalent
C << A.ewise_add(B, op="minus") # method style
C << gb.binary.minus(A | B) # functional style
0 |
1 |
2 |
|
---|---|---|---|
0 |
9.0 |
2.0 |
5.0 |
1 |
1.5 |
4.0 |
|
2 |
0 |
1 |
2 |
|
---|---|---|---|
0 |
4.0 |
0.0 |
-2.0 |
1 |
|||
2 |
6.0 |
3.0 |
1.0 |
0 |
1 |
2 |
||
---|---|---|---|---|
0 |
5.0 |
2.0 |
7.0 |
|
1 |
1.5 |
4.0 |
||
2 |
6.0 |
3.0 |
1.0 |
eWiseUnion 示例:
A = gb.Matrix.from_coo(
[0, 0, 0, 1, 1],
[0, 1, 2, 0, 2],
[9., 2., 5., 1.5, 4.],
nrows=3
)
B = gb.Matrix.from_coo(
[0, 0, 0, 2, 2, 2],
[0, 1, 2, 0, 1, 2],
[4., 0., -2., 6., 3., 1.]
)
C = gb.Matrix(float, A.nrows, A.ncols)
# These are equivalent
C << A.ewise_union(B, op="minus", left_default=0, right_default=0) # method style
C << gb.binary.minus(A | B, left_default=0, right_default=0) # functional style
0 |
1 |
2 |
|
---|---|---|---|
0 |
9.0 |
2.0 |
5.0 |
1 |
1.5 |
4.0 |
|
2 |
0 |
1 |
2 |
|
---|---|---|---|
0 |
4.0 |
0.0 |
-2.0 |
1 |
|||
2 |
6.0 |
3.0 |
1.0 |
0 |
1 |
2 |
||
---|---|---|---|---|
0 |
5.0 |
2.0 |
7.0 |
|
1 |
1.5 |
4.0 |
||
2 |
-6.0 |
-3.0 |
-1.0 |
提取#
提取是GraphBLAS根据一组索引获取向量或矩阵的子集。 提取使用普通的Python切片语法。
提取操作不是形状保持操作,因此在此过程中索引可能会被重新映射。例如,提取索引 [1, 3, 5] 将生成一个索引为 [0, 1, 2] 的对象。
如果索引是一个索引列表或切片,则该维度将被保留。如果索引是一个整数,则该维度将被折叠。
Matrix[列表/切片, 列表/切片] -> Matrix
Matrix[列表/切片, 整数] -> 向量
Matrix[int, list/slice] -> Vector
矩阵[整数, 整数] -> 标量
Vector[列表/切片] -> Vector
向量[整数] -> 标量
向量切片示例:
v = gb.Vector.from_coo([0, 1, 3, 4, 6], [10., 2., 40., -5., 24.])
w = gb.Vector(float, 4)
w << v[:4]
0 |
1 |
2 |
3 |
4 |
5 |
6 |
---|---|---|---|---|---|---|
10.0 |
2.0 |
40.0 |
-5.0 |
24.0 |
0 |
1 |
2 |
3 |
---|---|---|---|
10.0 |
2.0 |
40.0 |
矩阵列表示例:
A = gb.Matrix.from_coo(
[0, 0, 1, 1, 2, 2],
[1, 2, 0, 1, 0, 2],
[2., 5., 1.5, 4., 0.5, -7.]
)
C = gb.Matrix(float, 2, A.ncols)
C << A[[0, 2], :]
0 |
1 |
2 |
|
---|---|---|---|
0 |
2.0 |
5.0 |
|
1 |
1.5 |
4.0 |
|
2 |
0.5 |
-7.0 |
0 |
1 |
2 |
|
---|---|---|---|
0 |
2.0 |
5.0 |
|
1 |
0.5 |
-7.0 |
分配#
在GraphBLAS中,赋值操作将一个较小的集合根据定义的索引扩展为一个较大的集合。可以将其视为提取操作的逆操作。索引的数量必须与输入集合的形状相匹配。然而,实际的索引位置指的是输出对象中的位置。
赋值使用普通的Python切片语法。
如果索引是整数而不是列表或切片,则可以分配较小等级的对象。 例如,如果行索引或列索引是整数,则可以将向量分配到矩阵中。
对于整数、列表或切片索引的任何组合,也可以分配标量。
矩阵-矩阵赋值示例:
A = gb.Matrix.from_coo(
[0, 0, 1, 1, 2, 2],
[1, 2, 0, 1, 0, 2],
[2., 5., 1.5, 4., 0.5, -7.]
)
B = gb.Matrix.from_coo(
[0, 0, 1, 1],
[0, 1, 0, 1],
[-99., -98., -97., -96.]
)
A[::2, ::2] << B
0 |
1 |
2 |
|
---|---|---|---|
0 |
2.0 |
5.0 |
|
1 |
1.5 |
4.0 |
|
2 |
0.5 |
-7.0 |
0 |
1 |
|
---|---|---|
0 |
-99.0 |
-98.0 |
1 |
-97.0 |
-96.0 |
0 |
1 |
2 |
|
---|---|---|---|
0 |
-99.0 |
2.0 |
-98.0 |
1 |
1.5 |
4.0 |
|
2 |
-97.0 |
-96.0 |
矩阵-向量赋值示例:
A = gb.Matrix.from_coo(
[0, 0, 1, 1, 2, 2],
[1, 2, 0, 1, 0, 2],
[2., 5., 1.5, 4., 0.5, -7.]
)
v = gb.Vector.from_coo([2], [-99.])
A[1, :] << v
0 |
1 |
2 |
|
---|---|---|---|
0 |
2.0 |
5.0 |
|
1 |
1.5 |
4.0 |
|
2 |
0.5 |
-7.0 |
0 |
1 |
2 |
---|---|---|
-99.0 |
0 |
1 |
2 |
|
---|---|---|---|
0 |
2.0 |
5.0 |
|
1 |
-99.0 |
||
2 |
0.5 |
-7.0 |
向量-标量赋值示例:
v = gb.Vector.from_coo([0, 1, 3, 4, 6], [10, 2, 40, -5, 24])
v[:4] << 99
0 |
1 |
2 |
3 |
4 |
5 |
6 |
---|---|---|---|---|---|---|
10 |
2 |
40 |
-5 |
24 |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
---|---|---|---|---|---|---|
99 |
99 |
99 |
99 |
-5 |
24 |
应用#
Apply 接受一个操作符并将其应用于集合中的每个非空元素。 操作符可以是一元的、索引一元的或二元的。
对于二元情况,必须提供一个额外的标量参数作为左参数或右参数,另一个参数由集合元素提供。
方法名是 apply
,函数形式只是将操作符作为调用函数,并将集合作为参数。
一元 应用示例:
v = gb.Vector.from_coo([0, 1, 3], [10., 20., 40.])
w = gb.Vector(float, v.size)
# These are equivalent
w << v.apply(gb.unary.minv)
w << gb.unary.minv(v)
0 |
1 |
2 |
3 |
---|---|---|---|
10.0 |
20.0 |
40.0 |
0 |
1 |
2 |
3 |
---|---|---|---|
0.1 |
0.05 |
0.025 |
IndexUnary 应用示例:
v = gb.Vector.from_coo([0, 1, 3], [10., 20., 40.])
w = gb.Vector(int, v.size)
# These are equivalent
w << v.apply(gb.indexunary.index)
w << gb.indexunary.index(v)
0 |
1 |
2 |
3 |
---|---|---|---|
10.0 |
20.0 |
40.0 |
0 |
1 |
2 |
3 |
---|---|---|---|
0 |
1 |
3 |
二进制 应用示例:
v = gb.Vector.from_coo([0, 1, 3], [10., 20., 40.])
w = gb.Vector(float, v.size)
# These are all equivalent
w << v.apply("minus", right=15)
w << gb.binary.minus(v, right=15)
w << v - 15
0 |
1 |
2 |
3 |
---|---|---|---|
10.0 |
20.0 |
40.0 |
0 |
1 |
2 |
3 |
|
---|---|---|---|---|
-5.0 |
5.0 |
25.0 |
选择#
Select 接受一个一元索引操作符,并将其应用于集合中的每个非缺失元素。 如果结果为 True,则该元素保留在输出中。如果结果为 False,则该元素 在结果中变为缺失。因此,输出是原始集合的过滤版本。
上三角示例:
A = gb.Matrix.from_coo(
[0, 0, 1, 1, 2, 2],
[1, 2, 0, 2, 1, 2],
[2., 5., 1.5, 4., 0.5, -7.]
)
C = gb.Matrix(float, A.nrows, A.ncols)
# These are equivalent
C << A.select("triu")
C << gb.select.triu(A)
0 |
1 |
2 |
|
---|---|---|---|
0 |
2.0 |
5.0 |
|
1 |
1.5 |
4.0 |
|
2 |
0.5 |
-7.0 |
0 |
1 |
2 |
|
---|---|---|---|
0 |
2.0 |
5.0 |
|
1 |
4.0 |
||
2 |
-7.0 |
按值选择示例:
v = gb.Vector.from_coo([0, 1, 3, 4, 6], [10., 2., 40., -5., 24.])
w = gb.Vector(float, v.size)
# These are equivalent
w << v.select(">=", 5)
w << gb.select.value(v >= 5)
0 |
1 |
2 |
3 |
4 |
5 |
6 |
---|---|---|---|---|---|---|
10.0 |
2.0 |
40.0 |
-5.0 |
24.0 |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
---|---|---|---|---|---|---|
10.0 |
40.0 |
24.0 |
Reduce#
降维减少了集合的维度数量。一个矩阵可以变成一个向量,而一个矩阵或向量可以降维成一个标量。
当将矩阵简化为向量时,可以按行或按列进行简化。
一个幺半群或聚合器用于执行归约操作。
矩阵到向量 列向示例:
A = gb.Matrix.from_coo(
[0, 0, 1, 1, 2, 2],
[1, 3, 0, 1, 0, 1],
[2., 5., 1.5, 4., 0.5, -7.]
)
w = gb.Vector(float, A.ncols)
w << A.reduce_columnwise("times")
0 |
1 |
2 |
3 |
|
---|---|---|---|---|
0 |
2.0 |
5.0 |
||
1 |
1.5 |
4.0 |
||
2 |
0.5 |
-7.0 |
0 |
1 |
2 |
3 |
|
---|---|---|---|---|
0.75 |
-56.0 |
5.0 |
矩阵到标量 示例:
A = gb.Matrix.from_coo(
[0, 0, 1, 1, 2, 2],
[1, 3, 0, 1, 0, 1],
[2., 5., 1.5, 4., 0.5, -7.]
)
s = gb.Scalar(float)
s << A.reduce_scalar("max")
0 |
1 |
2 |
3 |
|
---|---|---|---|---|
0 |
2.0 |
5.0 |
||
1 |
1.5 |
4.0 |
||
2 |
0.5 |
-7.0 |
5.0 |
向量到标量 聚合器示例:
v = gb.Vector.from_coo([0, 1, 3, 4, 6], [10., 2., 40., -5., 24.])
s = gb.Scalar(int)
# These are equivalent
s << v.reduce("argmin")
s << gb.agg.argmin(v)
0 |
1 |
2 |
3 |
4 |
5 |
6 |
---|---|---|---|---|---|---|
10.0 |
2.0 |
40.0 |
-5.0 |
24.0 |
4 |
转置#
转置可以是设置在计算输入上的描述符标志,也可以是最终计算本身。
要强制单独计算转置,请将其单独用作计算的右侧。
A = gb.Matrix.from_coo(
[0, 0, 1, 1, 2, 2],
[1, 3, 0, 1, 0, 2],
[2., 5., 1.5, 4., 0.5, -7.]
)
C = gb.Matrix(float, A.ncols, A.nrows)
C << A.T
0 |
1 |
2 |
3 |
|
---|---|---|---|---|
0 |
2.0 |
5.0 |
||
1 |
1.5 |
4.0 |
||
2 |
0.5 |
-7.0 |
0 |
1 |
2 |
|
---|---|---|---|
0 |
1.5 |
0.5 |
|
1 |
2.0 |
4.0 |
|
2 |
-7.0 |
||
3 |
5.0 |
克罗内克#
两个矩阵的Kronecker积将A(m×n)的每个元素与B(p×q)的每个元素相乘,以创建一个pm×qn的分块矩阵。
克罗内克积使用二元运算符。
A = gb.Matrix.from_coo(
[0, 0, 1],
[0, 1, 0],
[1., -2., 3.]
)
B = gb.Matrix.from_coo(
[0, 0, 1, 1, 2, 2],
[1, 2, 0, 1, 0, 2],
[2., 5., 1.5, 4., 0.5, -7.]
)
C = gb.Matrix(float, A.nrows * B.nrows, A.ncols * B.ncols)
C << A.kronecker(B, "times")
0 |
1 |
|
---|---|---|
0 |
1.0 |
-2.0 |
1 |
3.0 |
0 |
1 |
2 |
|
---|---|---|---|
0 |
2.0 |
5.0 |
|
1 |
1.5 |
4.0 |
|
2 |
0.5 |
-7.0 |
0 |
1 |
2 |
3 |
4 |
5 |
|
---|---|---|---|---|---|---|
0 |
2.0 |
5.0 |
-4.0 |
-10.0 |
||
1 |
1.5 |
4.0 |
-3.0 |
-8.0 |
||
2 |
0.5 |
-7.0 |
-1.0 |
14.0 |
||
3 |
6.0 |
15.0 |
||||
4 |
4.5 |
12.0 |
||||
5 |
1.5 |
-21.0 |