使用Scipy的GF256中的快速稀疏矩阵点乘法

问题描述

我需要提高算法速度。该方法将两个矩阵作为参数并执行点乘法。唯一的问题是元素必须在GF(256)中作为八位字节相乘,然后作为XOR添加。 由于我要处理非常大的稀疏矩阵,因此性能令人恐惧。

ws.Range(d).Delete xlShiftUp

您可能会看到我尝试了lil类,但是性能仍然很差。

有什么有效的解决方案吗?

解决方法

由于 Python 是解释型的,众所周知,嵌套 for 循环的性能很差。而 C 中等效的 for 循环会很快。因此,最佳性能将来自已编译的代码。

出于这个原因,我编写了一个名为 galois 的 Python 库,它扩展了 NumPy 数组以在 Galois 字段中进行操作。我用 Python 编写代码,但 JIT 使用 Numba 编译它,因此 Galois 域算术与原生 NumPy 数组算术一样快或几乎一样快,请参阅此 performance comparison

该库支持使用标准二元运算符(+@ 等)和普通 NumPy 线性代数函数对 Galois 域矩阵进行线性代数。这些例程中的大多数也是为了速度而进行 JIT 编译的。

我相信您正在尝试对两个矩阵 ((M,N) x (N,K)) 进行矩阵乘法。这是在 galois 中执行此操作的示例。

In [1]: import galois                                                                                                                                                                          

# Create the GF(2^8) field using AES's irreducible polynomial -- your's may be different
In [2]: GF = galois.GF(2**8,irreducible_poly=0x11b)                                                                                                                                           

In [3]: print(GF.properties)                                                                                                                                                                   
GF(2^8):
  characteristic: 2
  degree: 8
  order: 256
  irreducible_poly: x^8 + x^4 + x^3 + x + 1
  is_primitive_poly: False
  primitive_element: x + 1

In [4]: A = GF.Random((3,4)); A                                                                                                                                                                
Out[4]: 
GF([[ 35,130,167,111],[ 58,161,194,200],[244,65,160,8]],order=2^8)

In [5]: B = GF.Random((4,5)); B                                                                                                                                                                
Out[5]: 
GF([[ 50,59,23,34,38],[ 16,162,80,250],[205,145,114,9,40],[212,250,210,72]],order=2^8)

In [6]: A @ B                                                                                                                                                                                  
Out[6]: 
GF([[144,236,142,90,89],[ 83,171,2,117],[192,1,20,208,127]],order=2^8)