我希望能够使用Python类作为元素进行矩阵操作 - 在本例中是一个简单的Galois field实现。它实现了必要的__add__
,__mul__
,__sub__
等。
首先,我认为numpy arrays使用dtype
参数可以实现这一点,但是the dtype
documentation,dtype
似乎不能随意Python类。例如,我有一个类Galois
,它以模2运算:
>>> from galois import Galois
>>> Galois(1) + Galois(0)
Galois(1)
>>> Galois(1) + Galois(1)
Galois(0)
我可以尝试在numpy中使用它:
>>> import numpy as np
>>> a = np.identity(4, Galois)
>>> a
array([[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]], dtype=object)
但是如果我对矩阵进行操作,那么元素就不会遵循我的类的方法:
>>> b = np.identity(4, Galois)
>>> a+b
array([[2, 0, 0, 0],
[0, 2, 0, 0],
[0, 0, 2, 0],
[0, 0, 0, 2]], dtype=object)
有没有办法让这项工作与numpy一起使用?
是否还有其他Python矩阵库可以在类似任意数字的类上进行矩阵运算(包括反转)?
感谢目前为止的答案。但我仍然无法像我希望的那样真正使用它。加法和乘法似乎很好,但不是矩阵求逆。例如,让我们尝试从AES inverse S-box affine transform matrix获取forward S-box affine transform matrix。
class Galois(object):
MODULO = 2
def __init__(self, val):
self.val = int(val) % self.MODULO
def __add__(self, val):
return self.__class__((self.val + int(val)) % self.MODULO)
def __sub__(self, val):
return self.__class__((self.val - int(val)) % self.MODULO)
def __mul__(self, val):
return self.__class__((self.val * int(val)) % self.MODULO)
def __int__(self):
return self.val
def __repr__(self):
return "%s(%d)" % (self.__class__.__name__, self.val)
def __float__(self):
return float(self.val)
if __name__ == "__main__":
import numpy as np
Gv = np.vectorize(Galois)
a = Gv(np.identity(8)) + Gv(np.eye(8,8,-1)) + Gv(np.eye(8,8,-2)) + Gv(np.eye(8,8,-3)) + Gv(np.eye(8,8,-4)) + Gv(np.eye(8,8,4)) + Gv(np.eye(8,8,5)) + Gv(np.eye(8,8,6)) + Gv(np.eye(8,8,7))
print np.matrix(a)
print np.matrix(a).I
结果:
[[Galois(1) Galois(0) Galois(0) Galois(0) Galois(1) Galois(1) Galois(1)
Galois(1)]
[Galois(1) Galois(1) Galois(0) Galois(0) Galois(0) Galois(1) Galois(1)
Galois(1)]
[Galois(1) Galois(1) Galois(1) Galois(0) Galois(0) Galois(0) Galois(1)
Galois(1)]
[Galois(1) Galois(1) Galois(1) Galois(1) Galois(0) Galois(0) Galois(0)
Galois(1)]
[Galois(1) Galois(1) Galois(1) Galois(1) Galois(1) Galois(0) Galois(0)
Galois(0)]
[Galois(0) Galois(1) Galois(1) Galois(1) Galois(1) Galois(1) Galois(0)
Galois(0)]
[Galois(0) Galois(0) Galois(1) Galois(1) Galois(1) Galois(1) Galois(1)
Galois(0)]
[Galois(0) Galois(0) Galois(0) Galois(1) Galois(1) Galois(1) Galois(1)
Galois(1)]]
[[ 0.4 0.4 -0.6 0.4 0.4 -0.6 0.4 -0.6]
[-0.6 0.4 0.4 -0.6 0.4 0.4 -0.6 0.4]
[ 0.4 -0.6 0.4 0.4 -0.6 0.4 0.4 -0.6]
[-0.6 0.4 -0.6 0.4 0.4 -0.6 0.4 0.4]
[ 0.4 -0.6 0.4 -0.6 0.4 0.4 -0.6 0.4]
[ 0.4 0.4 -0.6 0.4 -0.6 0.4 0.4 -0.6]
[-0.6 0.4 0.4 -0.6 0.4 -0.6 0.4 0.4]
[ 0.4 -0.6 0.4 0.4 -0.6 0.4 -0.6 0.4]]
不是我希望的结果。似乎对于矩阵求逆,numpy只是将矩阵转换为浮点数,然后使用普通实数进行反演。
答案 0 :(得分:8)
您可以使用object
作为dtype
,这将允许任意Python对象。我认为没有任何方法可以将numpy数组专门化为仅接受一个特定类的Python对象。
答案 1 :(得分:2)
以下是如何使用另一个数组创建和初始化Numpy对象数组:
import numpy as np
class G:
def __init__(self, x):
self.x = x
I = np.identity(5)
Gv = np.vectorize(G)
GG = Gv(I)
print GG[0,0].x
print GG[0,1].x
答案 2 :(得分:1)
您是否签出了sage,特别是galois_group。
似乎你正在重新发明轮子。但如果你坚持这样做,你可以考虑subclass ndarray。
答案 3 :(得分:1)
关于矩阵求逆的更新:使用NumPy矩阵求逆来反转Galois域上的矩阵是行不通的。 NumPy将实际反转矩阵的任务委托给LAPACK,这是一个用Fortran编写的线性代数库。 LAPACK当然完全没有意识到Python类和运算符,并且永远无法在Galois
类上调用方法。此外,它们的矩阵求逆算法使用了比较运算符(如<
和>
),这对于Galois域的元素没有意义。
因此,您可以选择自己实现矩阵求逆或使用其中一个可用的实现。例如,SymPy对Galois字段的支持有限。 PARI/GP支持Galois字段和some Python bindings。
答案 4 :(得分:-1)
我不知道有一种方法可以让矩阵元素按照任意Python类运行。但是,可以全局更改某些操作的行为,如以下示例所示,
import numpy as np
from numpy import set_numeric_ops
from numpy import poly1d as poly
from numpy import identity as idt
def gfadd(x,y):
return np.add(x,y) % 2
set_numeric_ops(add=gfadd)
a = idt(4,np.int)
print a+a
产生
[[0 0 0 0]
[0 0 0 0]
[0 0 0 0]
[0 0 0 0]]
和
p = poly([1,0,1])
print p+p
给出,
0
但是,您可能希望继承ndarray
。