Reputation: 3347
I have a matrix of size 128x128. Each entry is a binary field element (in my use case, only 0 and 1). I try to invert this matrix in matlab. I find some functions in matlab that does finite field matrix inversion here http://www.mathworks.com/help/comm/galois-field-computations.html.
However, these built-in functions only support matrix size upto 16x16. Any other methods that can overcome this limit? I an open to other tools such as python or C/C++.
If you would like to try out your method, here are the test matrix and its inverse.
Matrix A [0,0,0,1,0,0,1,0;1,1,1,0,1,0,1,1;1,1,1,0,1,1,0,1;0,1,0,0,0,0,1,0;0,1,1,1,1,1,1,0;1,0,1,1,0,0,1,0;0,0,1,0,0,0,1,0;0,0,0,0,0,1,0,0]
Matrix A^-1 [1,1,1,0,0,1,1,1;0,1,1,1,0,0,0,1;0,1,1,0,0,0,1,1;1,1,1,0,0,0,0,1;1,0,0,1,1,0,1,1;0,0,0,0,0,0,0,1;0,1,1,0,0,0,0,1;0,1,0,0,1,1,1,1]
Upvotes: 2
Views: 2304
Reputation: 580
Inverting a matrix over a Galois field can be accomplished by performing Gaussian elimination (with all arithmetic performed in the Galois field) on [A | I]
, which results in [I | A^-1]
.
Here is some pseudocode to perform the Gaussian elimination (row reduction).
def row_reduce(A):
A_rre = A.copy()
p = 0 # The pivot
for j in range(A.shape[1]):
# Find a pivot in column `j` at or below row `p`
idxs = np.nonzero(A_rre[p:,j])[0]
if idxs.size == 0:
continue
i = p + idxs[0] # Row with a pivot
# Swap row `p` and `i`. The pivot is now located at row `p`.
A_rre[[p,i],:] = A_rre[[i,p],:]
# Force pivot value to be 1
A_rre[p,:] /= A_rre[p,j]
# Force zeros above and below the pivot
idxs = np.nonzero(A_rre[:,j])[0].tolist()
idxs.remove(p)
A_rre[idxs,:] -= np.multiply.outer(A_rre[idxs,j], A_rre[p,:])
p += 1
if p == A_rre.shape[0]:
break
return A_rre
I had this use case, and couldn't find a Python library that accomplished this. So I created a Python package galois that extends NumPy arrays over Galois fields. It supports linear algebra using the normal np.linalg
functions.
Here is an example using your test matrices.
In [1]: import numpy as np
In [2]: import galois
In [3]: GF = galois.GF(2)
In [4]: A = GF([[0,0,0,1,0,0,1,0],[1,1,1,0,1,0,1,1],[1,1,1,0,1,1,0,1],[0,1,0,0,0,0,1,0],[0,1,1,1,1,1,1,0
...: ],[1,0,1,1,0,0,1,0],[0,0,1,0,0,0,1,0],[0,0,0,0,0,1,0,0]]); A
Out[4]:
GF([[0, 0, 0, 1, 0, 0, 1, 0],
[1, 1, 1, 0, 1, 0, 1, 1],
[1, 1, 1, 0, 1, 1, 0, 1],
[0, 1, 0, 0, 0, 0, 1, 0],
[0, 1, 1, 1, 1, 1, 1, 0],
[1, 0, 1, 1, 0, 0, 1, 0],
[0, 0, 1, 0, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 1, 0, 0]], order=2)
In [5]: A_inv = np.linalg.inv(A); A_inv
Out[5]:
GF([[1, 1, 1, 0, 0, 1, 1, 1],
[0, 1, 1, 1, 0, 0, 0, 1],
[0, 1, 1, 0, 0, 0, 1, 1],
[1, 1, 1, 0, 0, 0, 0, 1],
[1, 0, 0, 1, 1, 0, 1, 1],
[0, 0, 0, 0, 0, 0, 0, 1],
[0, 1, 1, 0, 0, 0, 0, 1],
[0, 1, 0, 0, 1, 1, 1, 1]], order=2)
In [6]: A @ A_inv
Out[6]:
GF([[1, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 0, 0, 1]], order=2)
Upvotes: 3