对于我当前的项目,我需要能够使用GF(2)中的条目来计算64 * 64矩阵的等级。我想知道是否有人有一个好的解决方案。
为此,我一直在使用pyfinite,但由于它是纯python实现,所以速度相当慢。我还尝试将我一直在使用的代码进行cythonise,但是由于依赖pyfinite而出现了问题。
我的下一个想法是用cython编写我自己的课程,但这似乎对我所需要的有些过大。
我需要以下功能
matrix = GF2Matrix(size=64) # creating a 64*64 matrix
matrix.setRow(i, [1,0,1....,1]) # set row using list
matrix += matrix2 # addition of matrices
rank(matrix) # then computing the rank
感谢任何想法。
答案 0 :(得分:1)
有效表示GF(2)上的矩阵的一种方法是将行存储为整数,将每个整数解释为位字符串。例如4×4矩阵
[0 1 1 0]
[1 0 1 1]
[0 0 1 0]
[1 0 0 1]
(具有3级)可以表示为整数列表[6, 13, 4, 9]
。在这里,我认为第一列与整数的最低有效位相对应,而最后一列与最高有效位相对应,但是相反的约定也适用。
使用这种表示形式,可以使用Python的按位整数运算有效地执行行运算:^
用于加法,&
用于乘法。
然后,您可以使用标准的高斯消去方法来计算等级。
这是一些相当有效的代码。给定如上所述表示矩阵的非负整数的集合rows
,我们重复删除列表中的最后一行,然后使用该行从该列中消除所有1
条目,这些列对应于其最低有效位。如果该行为零,则它没有最低有效位,也不会影响排名,因此我们只需要丢弃它并继续前进即可。
def gf2_rank(rows):
"""
Find rank of a matrix over GF2.
The rows of the matrix are given as nonnegative integers, thought
of as bit-strings.
This function modifies the input list. Use gf2_rank(rows.copy())
instead of gf2_rank(rows) to avoid modifying rows.
"""
rank = 0
while rows:
pivot_row = rows.pop()
if pivot_row:
rank += 1
lsb = pivot_row & -pivot_row
for index, row in enumerate(rows):
if row & lsb:
rows[index] = row ^ pivot_row
return rank
让我们对GF2上的随机64 x 64矩阵进行一些计时。 random_matrices
是用于创建随机的64 x 64矩阵集合的函数:
import random
def random_matrix():
return [random.getrandbits(64) for row in range(64)]
def random_matrices(count):
return [random_matrix() for _ in range(count)]
这是计时代码:
import timeit
count = 1000
number = 10
timer = timeit.Timer(
setup="ms = random_matrices({})".format(count),
stmt="[gf2_rank(m.copy()) for m in ms]",
globals=globals())
print(min(timer.repeat(number=number)) / count / number)
在我的机器(2.7 GHz Intel Core i7,macOS 10.14.5,Python 3.7)上打印的结果是0.0001984686384
,因此对于单级计算而言,这是不到200µs的时间。
200µs对于纯Python等级计算而言是相当可观的,但是如果这还不够快,我们可以按照您的建议使用Cython。这是一个Cython函数,该函数采用dtype np.uint64
的1d NumPy数组,再次将数组的每个元素都视为GF2上64×64矩阵的一行,并返回该矩阵的秩。 >
# cython: language_level=3, boundscheck=False
from libc.stdint cimport uint64_t, int64_t
def gf2_rank(uint64_t[:] rows):
"""
Find rank of a matrix over GF2.
The matrix can have no more than 64 columns, and is represented
as a 1d NumPy array of dtype `np.uint64`. As before, each integer
in the array is thought of as a bit-string to give a row of the
matrix over GF2.
This function modifies the input array.
"""
cdef size_t i, j, nrows, rank
cdef uint64_t pivot_row, row, lsb
nrows = rows.shape[0]
rank = 0
for i in range(nrows):
pivot_row = rows[i]
if pivot_row:
rank += 1
lsb = pivot_row & -pivot_row
for j in range(i + 1, nrows):
row = rows[j]
if row & lsb:
rows[j] = row ^ pivot_row
return rank
运行64 x 64矩阵的等效时序,现在表示为dtype np.uint64
和形状(64,)
的NumPy数组,我得到的平均秩计算时间为7.56µs,快了25倍比纯Python版本要好。