我可以将自己的Python类与numpy或其他矩阵库一起使用吗?
我想用一个Python类来进行矩阵运算,类里面的元素是简单的伽罗瓦域实现。这个类实现了必要的__add__
、__mul__
、__sub__
等方法。
起初,我以为可以通过numpy数组来实现,使用dtype
参数,但根据dtype文档,似乎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逆S盒仿射变换矩阵中获取正向S盒仿射变换矩阵。
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只是把矩阵转换成浮点数,然后用普通的实数进行求逆。
5 个回答
关于你提到的矩阵求逆的问题:用NumPy来对伽罗瓦域的矩阵进行求逆是行不通的。NumPy实际上把矩阵求逆的工作交给了一个叫做LAPACK的库,这个库是用Fortran语言写的线性代数库。LAPACK完全不知道Python的类和操作符,所以它无法调用你自己定义的Galois
类的方法。此外,他们的矩阵求逆算法使用了一些比较操作符(比如<
和>
),而这些在伽罗瓦域的元素上是没有意义的。
所以你有两个选择:要么自己实现矩阵求逆,要么使用现成的实现。例如,SymPy对伽罗瓦域有一些有限的支持。PARI/GP则支持伽罗瓦域,并且有一些Python的绑定。
这里是如何用另一个数组来创建和初始化一个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
你可以把 object
作为 dtype
,这样就可以让你放入任意的 Python 对象。我觉得没有办法让 numpy 数组只接受某一种特定类型的 Python 对象。