我可以将自己的Python类与numpy或其他矩阵库一起使用吗?

时间:2011-04-07 08:33:11

标签: python matrix numpy

我希望能够使用Python类作为元素进行矩阵操作 - 在本例中是一个简单的Galois field实现。它实现了必要的__add____mul____sub__等。

首先,我认为numpy arrays使用dtype参数可以实现这一点,但是the dtype documentationdtype似乎不能随意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只是将矩阵转换为浮点数,然后使用普通实数进行反演。

5 个答案:

答案 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