I was writing a tool to solve specific recurrence equations with SymPy, and found that one of the steps that involved a matrix multiplication was taking an extraordinarily long time. For instance, if I try the following in the iPython console,
In [1]: from sympy import *
In [2]: A = Matrix(500, 500, lambda i,j: 2 + abs(i-j) if i-j in [-1, 0, 1] else 0)
In [3]: A[0:7, 0:7]
Out[3]:
Matrix([
[2, 3, 0, 0, 0, 0, 0],
[3, 2, 3, 0, 0, 0, 0],
[0, 3, 2, 3, 0, 0, 0],
[0, 0, 3, 2, 3, 0, 0],
[0, 0, 0, 3, 2, 3, 0],
[0, 0, 0, 0, 3, 2, 3],
[0, 0, 0, 0, 0, 3, 2]])
In [4]: A * A
...
I've never waited long enough for it to finish.
I appreciate that symbolic manipulation considerably slower than numerical evaluation, but this seems pretty ridiculous. Using Octave or other linear algebra packages can perform this calculation in a fraction of a second.
Does anyone have experience using SymPy's matrix class for rows & columns ~ 1000, with Rational entries?
Arbitrary-precision as a must, speed as a nice-to-have
There are a few pythonic classes for such purpose, that may interest your arbitrary precision calculi
decimal.Decimal()
fractions.Fraction( numerator = 0, denominator = 1 )
These are indispensable for precise calculations, be it for large-scale astronomy, DEP-simulations or other fields, where precision must not degrade alongside the computation strategy progress over long scales of time / events / recursion and similar threats to standard number-representations.
Personally I worked with
decimal.Decimal()
( for up to 5.000.000 digits precision in crypto-sequence randomness analyses ) but was not focused on having 'em "inside"numpy
matrix.Numpy can bear these types in it's matrix-dataStructures (
dtype = decimal.Decimal
syntax et al), however testing is needed, to verify it's vectorised functions operations and the overall speed once handling these lovely pythonic classes' instances.Performance
As an initial observation on numpy speed on a standard ("dense" sounds funny for this scale ) 2x2
decimal.Decimal
-s:While the same on
dtype = numpy.float96
tookFor a 500 x 500 fully-populated
dtype = fractions.Fraction
For a 500 x 500 fully-populated dense
dtype = decimal.Decimal
May expectations for a Tri-diagonal matrix 1000x1000 go under 50 msec?
as there are 3,000 non-zero ( sparse-representation ) elements, as opposed to 250,000 cells in fully-populated 500x500 matrices tested above, there is a huge performance jump for using these pythonic classes for your arbitrary precision computations. Fraction has a more space once the engine may use an advantage of
numerator
/denominator
construction for MUL / DIV operations over Decimal, however exact performance envelopes shall be tested in-vivo, on real cases your computing approach is using.Sympy syntax for
SparseMatrix
& tests on 1000x1000 Tri-Diagonalsa real test on 1000x1000
SparseMatrix
, as proposed by @tmyklebu, took a bit longer to get elaborated due to installaton troubles, however may give you some further insight into real-world implementation Projects:I haven't used
sympy
for matrix operations, but I can repro the slowness you are experiencing with this code. It seems that the matrix operations in sympy are not that great.I will recommend you to use
numpy
, which has great matrix operations and is very fast. Here is a copy of your code in numpy, which does the multiplication in under 1 sec on my laptop:Why not use sympy's sparse matrices instead of dense matrices? The matrices that arise when solving (linear) recurrences are typically sparse; one technique gives you a matrix with 1's on the first superdiagonal and zeroes everywhere else except the bottom row, where the recurrence coefficients go.