Skip to content

Instantly share code, notes, and snippets.

@vxgmichel
Created June 27, 2018 10:01
Show Gist options
  • Save vxgmichel/a31b5a13b64899c32c12efaf217415b0 to your computer and use it in GitHub Desktop.
Save vxgmichel/a31b5a13b64899c32c12efaf217415b0 to your computer and use it in GitHub Desktop.
A benchmark comparing sympy and a pure python implementation of the Bareiss algorithm
import sys
import time
import hashlib
from fractions import Fraction
from contextlib import contextmanager
from sympy import Matrix
# https://gist.github.com/vxgmichel/080e9999a1020711f27cd60b5c2d14de
from bareiss import adjugate
def bitstring(i, n=256):
name = '{}\0'.format(i).encode()
h = hashlib.sha256(name).digest()
i = int.from_bytes(h, 'big')
g = map(int, '{:0256b}'.format(i))
return list(g)[:n]
@contextmanager
def timeit(*labels):
start = time.time()
yield
delta = time.time() - start
label = '[' + ', '.join(labels) + ']'
print('{:<25} >>> {:.3f} seconds'.format(label, delta))
def benchmark(n=256):
a = [bitstring(i, n) for i in range(n)]
m1 = list(map(list, zip(*a)))
m2 = Matrix(m1)
sympy_inverse = n <= 25
sympy_adjugate = n <= 15
print('Using n={}:'.format(n))
for row in m1:
print('│', *row, '│', sep='')
# Bareiss
with timeit('Bareiss', 'Determinant'):
det, adj = adjugate(m1)
r11 = det
with timeit('Bareiss', 'Adjugate'):
det, adj = adjugate(m1)
r12 = adj
with timeit('Bareiss', 'Inverse'):
det, adj = adjugate(m1)
r13 = [[Fraction(v, det) for v in row] for row in adj]
# Sympy
with timeit('Sympy', 'Determinant'):
r21 = m2.det()
if sympy_adjugate:
with timeit('Sympy', 'Adjugate'):
r22 = m2.adjugate()
if sympy_inverse:
with timeit('Sympy', 'Inverse'):
r23 = m2.inv()
# Check
assert r11 == r21
if sympy_adjugate:
assert Matrix(r12) == r22
if sympy_inverse:
assert Matrix(r13) == r23
# Determinant
print('(determinant = ', r11, ')', sep='')
if __name__ == '__main__':
try:
n = int(sys.argv[1])
except:
benchmark()
else:
benchmark(n)
@vxgmichel
Copy link
Author

Typical results:

Using n=15:
[Bareiss, Determinant]    >>> 0.002 seconds
[Bareiss, Adjugate]       >>> 0.002 seconds
[Bareiss, Inverse]        >>> 0.002 seconds
[Sympy, Determinant]      >>> 0.028 seconds
[Sympy, Adjugate]         >>> 8.364 seconds
[Sympy, Inverse]          >>> 0.027 seconds

Using n=25:
[Bareiss, Determinant]    >>> 0.009 seconds
[Bareiss, Adjugate]       >>> 0.009 seconds
[Bareiss, Inverse]        >>> 0.011 seconds
[Sympy, Determinant]      >>> 0.122 seconds
[Sympy, Inverse]          >>> 3.635 seconds

Using n=50:
[Bareiss, Determinant]    >>> 0.084 seconds
[Bareiss, Adjugate]       >>> 0.085 seconds
[Bareiss, Inverse]        >>> 0.090 seconds
[Sympy, Determinant]      >>> 1.022 seconds

Using n=100:
[Bareiss, Determinant]    >>> 0.731 seconds
[Bareiss, Adjugate]       >>> 0.736 seconds
[Bareiss, Inverse]        >>> 0.759 seconds
[Sympy, Determinant]      >>> 10.388 seconds

Using n=256:
[Bareiss, Determinant]    >>> 19.633 seconds
[Bareiss, Adjugate]       >>> 19.222 seconds
[Bareiss, Inverse]        >>> 20.007 seconds

@vxgmichel
Copy link
Author

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