操作#

矩阵乘法#

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
A#

0

1

2

3

0

2.0

5.0

1

1.5

4.25

2

0.5

3

B#

0

1

2

0

3.0

2.0

1

9.0

6.0

2

3.0

1.0

3

0.0

5.0

C << min_plus(A @ B)#

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
A#

0

1

2

3

0

2.0

5.0

1

1.5

4.25

2

0.5

3

v#

0

1

2

3

10.0

20.0

40.0

w << plus_times(A @ v)#

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
v#

0

1

2

3

10.0

20.0

40.0

B#

0

1

2

0

3.0

2.0

1

9.0

6.0

2

3.0

1.0

3

0.0

5.0

u << plus_plus(v @ B)#

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
A#

0

1

2

0

2.0

5.0

1

1.5

4.0

2

0.5

B#

0

1

2

0

3.0

-2.0

1

0.0

6.0

2

3.0

1.0

C << min(A & B)#

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_defaultright_default参数,用于指定当只有一个值时缺失值应该是什么。

    如果我们设置left_default=0right_default=0,那么

    • 7 - 3 = 4

    • 7 - missing = 7 - 0 = 7

    • missing - 7 = 0 - 7 = -7 <– 这给出了预期的答案

函数语法使用Python的并集符号|来表示两种方法。要指定ewise_union应与函数语法一起使用,需要使用left_defaultright_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
A#

0

1

2

0

9.0

2.0

5.0

1

1.5

4.0

2

B#

0

1

2

0

4.0

0.0

-2.0

1

2

6.0

3.0

1.0

C << A.ewise_add(B, ‘minus’)#

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
A#

0

1

2

0

9.0

2.0

5.0

1

1.5

4.0

2

B#

0

1

2

0

4.0

0.0

-2.0

1

2

6.0

3.0

1.0

C << A.ewise_union(B, ‘minus’, 0, 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]
v#

0

1

2

3

4

5

6

10.0

2.0

40.0

-5.0

24.0

w << v[:4]#

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], :]
A#

0

1

2

0

2.0

5.0

1

1.5

4.0

2

0.5

-7.0

C << A[[0, 2], :]#

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
A#

0

1

2

0

2.0

5.0

1

1.5

4.0

2

0.5

-7.0

B#

0

1

0

-99.0

-98.0

1

-97.0

-96.0

A[::2, ::2] << B#

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
A#

0

1

2

0

2.0

5.0

1

1.5

4.0

2

0.5

-7.0

v#

0

1

2

-99.0

A[1, :] << v#

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
v#

0

1

2

3

4

5

6

10

2

40

-5

24

v[:4] << 99#

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)
v#

0

1

2

3

10.0

20.0

40.0

w << minv(v)#

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)
v#

0

1

2

3

10.0

20.0

40.0

w << index(v)#

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
v#

0

1

2

3

10.0

20.0

40.0

w << v.apply(‘minus’, right=15)#

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)
A#

0

1

2

0

2.0

5.0

1

1.5

4.0

2

0.5

-7.0

C << select.triu(A)#

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)
v#

0

1

2

3

4

5

6

10.0

2.0

40.0

-5.0

24.0

w << select.value(v >= 5)#

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")
A#

0

1

2

3

0

2.0

5.0

1

1.5

4.0

2

0.5

-7.0

w << A.reduce_columnwise(‘times’)#

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")
A#

0

1

2

3

0

2.0

5.0

1

1.5

4.0

2

0.5

-7.0

s << A.reduce_scalar(‘max’)#

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)
v#

0

1

2

3

4

5

6

10.0

2.0

40.0

-5.0

24.0

s << argmin(v)#

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
A#

0

1

2

3

0

2.0

5.0

1

1.5

4.0

2

0.5

-7.0

C << A.T#

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")
A#

0

1

0

1.0

-2.0

1

3.0

B#

0

1

2

0

2.0

5.0

1

1.5

4.0

2

0.5

-7.0

C << A.kronecker(B, ‘times’)#

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