问题
I'd like to be able to do matrix operations using a Python class as the elements—in this case, a simple Galois field implementation. It implements the necessary __add__
, __mul__
, __sub__
etc.
At first, I thought this should be possible with numpy arrays, using the dtype
parameter, but from the dtype documentation, it seems that dtype
can't be an arbitrary Python class. For example, I have a class Galois
which does operations modulo 2:
>>> from galois import Galois
>>> Galois(1) + Galois(0)
Galois(1)
>>> Galois(1) + Galois(1)
Galois(0)
I can try to use this in 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)
But if I do operations on the matrices, the elements aren't following the methods of my class:
>>> 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)
Is there any way to make this work with numpy?
Is there any other Python matrix library that can do matrix operations (including inversion) on an arbitrary number-like class?
Update
Thanks for the answers so far. But I'm still not able to really use it as I hoped. Adds and multiplies seem good, but not matrix inversion. For example, let's try to get the AES inverse S-box affine transform matrix from the 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
The result:
[[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]]
Not the result I hoped for. It seems that for the matrix inversion, numpy just converts the matrix to floats, then does the inversion with plain real numbers.
回答1:
You can use object
as the dtype
, which will allow arbitrary Python objects. I don't think there's any way of specializing a numpy array to accept only one particular class of Python object.
回答2:
Here is how you can create and initialize a Numpy object array with another array:
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
回答3:
Have you checked out sage and specifically galois_group.
It seems that you are reinventing the wheel. But if you insist doing that you may consider to subclass ndarray.
回答4:
Regarding your update on matrix inversion: Using NumPy matrix inversion to invert matrices over Galois fields won't work. NumPy delegates the task of actually inverting the matrix to LAPACK, which is a linear algebra library written in Fortran. LAPACK is of course completely unaware of Python classes and operators, and will never be able to call methods on your Galois
class. Additionally, their matrix inversion algorithm makes use of comparison operators (like <
and >
), which do not make sense for elements of Galois fields.
So your options are either to implement the matrix inversion yourself or to use one of the available implementations. For example, SymPy has a limited support for Galois fields. PARI/GP has support for Galois fields and some Python bindings.
回答5:
I am not aware of a way to have matrix elements behave according to an arbitrary Python class. It is however possible to globally change the behaviour of certain operations, as the following examples show,
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
produces,
[[0 0 0 0]
[0 0 0 0]
[0 0 0 0]
[0 0 0 0]]
and,
p = poly([1,0,1])
print p+p
gives,
0
However, you probably want to subclass ndarray
.
来源:https://stackoverflow.com/questions/5578172/can-i-use-my-own-python-class-with-numpy-or-some-other-matrix-library