Skip to content

Instantly share code, notes, and snippets.

@vxgmichel
Last active March 2, 2021 14:47
Show Gist options
  • Save vxgmichel/080e9999a1020711f27cd60b5c2d14de to your computer and use it in GitHub Desktop.
Save vxgmichel/080e9999a1020711f27cd60b5c2d14de to your computer and use it in GitHub Desktop.
Pure python implementation of the Bareiss algorithm
def adjugate(a, m=None):
# Initialize
sign = 1
previous = pivot = 1
# Bareiss formula
def do_pivot(a, b, c, d, e):
x = a * d - b * c
if m is None:
q, r = divmod(x, e)
assert r == 0
return q
q = x * pow(e, -1, m)
return q % m
# Assert square matrix
n = len(a)
assert all(len(row) == n for row in a)
# Build augmented matrix
am = [
list(map(int, row)) + [0] * i + [1] + [0] * (n - i - 1)
for i, row in enumerate(a)
]
# Iterate diagonally
for c in range(n):
# Test pivot
if am[c][c] == 0:
# Find pivot
for i in range(c, n):
if am[i][c] != 0:
break
# Non-invertible detection
else:
return 0, [[0] * n for _ in range(n)]
# Switch rows
am[c], am[i] = am[i], am[c]
sign *= -1
# Get pivot
previous, pivot = pivot, am[c][c]
# Set zeros
for i, row in enumerate(am):
if i == c:
continue
am[i] = [
do_pivot(pivot, y, row[c], x, previous) for x, y in zip(row, am[c])
]
# Determinant
determinant = sign * pivot
if m is not None:
determinant %= m
# Return
return determinant, [row[n:] for row in am]
@orah29
Copy link

orah29 commented Feb 28, 2021

Hi Michel,
Could you confirm that 'm' is the size of a finite field?
Thank you

@vxgmichel
Copy link
Author

@orah29 Yes, every time the matrix is updated the result is taken modulo m. I used it mostly with m=2 since the addition in Z/2 corresponds to the XOR operation over bits.

@orah29
Copy link

orah29 commented Mar 1, 2021

With A = np.eye(9) + np.arange(9) there is no pb when I test adjugate(A) (=equal to np.linalg.det(A) * np.linalg.inv(A)) but adjugate(A, 256) stop on an AssertionError (r != 0). I have to deal with the ff Z/2^8. Obviously, detA % 256 != 0. I translated your code in numpy, but the pb is the same. Could you help me? Thank you per advance.

@orah29
Copy link

orah29 commented Mar 2, 2021

Sorry I confused Z/p with Z/p^n ... I going to use an irreducible polynomial to calculate on Z/256

@vxgmichel
Copy link
Author

@orah29 Oh right I made a mistake.

When m is provided, the new values should be computed not as (a * d - b * c) // e but as (a * d - b * c) * modinv(e, m) where modinv is the modular multiplicative inverse. Still, it requires that e and m are coprime, meaning m should be prime.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment