I'm trying to implement the following equation in Python.
It's an equation for computing the matrix exponential for a given matrix A and scalar x. My code doesn't seem to work, when I'm comparing it to the Python expm from scipy.
import math
import numpy as np
from scipy.linalg import expm
# Scalar x (will later on be for user input)
x = 1
matrix = np.array([[-5, 2, 3], [2, -6, 4], [4, 5, -9]])
# Using scipy to compute the matrix exponential (for comparison)
B = expm(matrix)
print(B)
# Defining the equation
def equation(n):
y = ((pow(x, n) * np.linalg.matrix_power(matrix, n)) / int(math.factorial(n)))
return y
# Summing the equation with finite iterations
result = sum([equation(n) for n in range(0, 1000)])
print(result)
I have defined the matrix matrix = np.array([[-5, 2, 3], [2, -6, 4], [4, 5, -9]])
and with the expm function from scipy I get the output:
[[0.3659571 0.35453832 0.27950458]
[0.36527461 0.35510049 0.27962489]
[0.36551524 0.35489926 0.27958549]]
But my implementation of the equations gives me:
[[282.7927229097503 439.9138578271309 2167.1107527813792]
[548.8430305150805 -1876.4510112837029 1328.9683527937962]
[1753.0719360816013 3838.501983853133 -5590.574633487889]]
I've been staring at my code for hours, but I just recently picked up Python so my skills are very limited.
This is because of lost of precision. It turns out, doing matrix exponential needs too many terms to converge (around 35 in this case) and the matrix M^35 already exploded your integer. Using the same algorithm, let's see how Julia can do it:
From the above, you see the big difference for
M^20
when the matrix is in Int64 vs Int128. Indeed, it silently overflow the integer without throwing exceptions. That's the same reason you got the answer wrong if you sum the terms up.Unfortunately, numpy does not have int128 type as Julia. But we do have float128. So let's modify your code to use float128 instead:
Same here, you see the difference of matrix
M
raise to 20th power when the data type are different. You lost some precision by using float, but you don't overflow to early and get your answer right, at least for this particular matrix.Lesson learned: Do not implement your own function if scipy provide one for you. There is a reason people implement it in a library.