Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I use my own Python class with numpy or some other matrix library?

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.

like image 691
Craig McQueen Avatar asked Apr 07 '11 08:04

Craig McQueen


People also ask

Is there a matrix library for Python?

matlib ) This module contains all functions in the numpy namespace, with the following replacement functions that return matrices instead of ndarrays . Interpret the input as a matrix.

Which Python library can be used for matrix representation?

Python matrix can be created using a nested list data type and by using the numpy library.

How do you create a matrix class in Python?

Create and Use the ModuleCreate a folder called Matrix . Put main.py and another file called linearAlgebra inside this folder. Put __init__.py file inside the linearAlgebra file. Use main.py to import and use our Matrix class.


2 Answers

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.

like image 87
Sven Marnach Avatar answered Sep 20 '22 01:09

Sven Marnach


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.

like image 39
Gareth McCaughan Avatar answered Sep 18 '22 01:09

Gareth McCaughan