I need to solve a system of linear equations Lx=b, where x is always a vector (3x1 array), L is an Nx3 array, and b is an Nx1 vector. N usually ranges from 4 to something like 10. I have no problems solving this using
scipy.linalg.lstsq(L,b)
However, I need to do this many times (something like 200x200=40000 times) as x is actually something associated with each pixel in an image. So x is actually stored in an PxQx3 array where P and Q is something like 200-300, and the last number '3' refers to the vector x. Right now I just loop through each column and row and solve the equation one-by-one .How do I solve those 40000 different overdetermined systems of linear equations efficiently, probably using some vectorization techniques or other special methods?
thanks
There is one solution for each pair of linear equations: for the first and second equations (0.2, −1.4), for the first and third (−2/3, 1/3), and for the second and third (1.5, 2.5).
If a set of vectors is linearly independent, then it corresponds to a system which is overdetermined or which has the same number of variables as equations. If a system is underdetermined, then it corresponds to a set of vectors which are linearly dependent.
In general, an overdetermined system is generally not consistent, an underdetermined system is general consistent, a square system is generally consistent has one solution. Definition: A system of linear equations is said to be homogeneous if the constants on the right-hand side are all zero.
Overdetermined systems Suppose the matrix A has dimensions m by n and the right hand side vector b has dimension m. Then the solution x, if it exists, has to have dimension n. If m > n, i.e. we have more equations than unknowns, the system is overdetermined.
You can gain some speed by making use of the stack of matrices feature of numpy.linalg
routines. This doesn't yet work for numpy.linalg.lstsq
, but numpy.linalg.svd does, so you can implement lstsq yourself:
import numpy as np
def stacked_lstsq(L, b, rcond=1e-10):
"""
Solve L x = b, via SVD least squares cutting of small singular values
L is an array of shape (..., M, N) and b of shape (..., M).
Returns x of shape (..., N)
"""
u, s, v = np.linalg.svd(L, full_matrices=False)
s_max = s.max(axis=-1, keepdims=True)
s_min = rcond*s_max
inv_s = np.zeros_like(s)
inv_s[s >= s_min] = 1/s[s>=s_min]
x = np.einsum('...ji,...j->...i', v,
inv_s * np.einsum('...ji,...j->...i', u, b.conj()))
return np.conj(x, x)
def slow_lstsq(L, b):
return np.array([np.linalg.lstsq(L[k], b[k])[0]
for k in range(L.shape[0])])
def test_it():
b = np.random.rand(1234, 3)
L = np.random.rand(1234, 3, 6)
x = stacked_lstsq(L, b)
x2 = slow_lstsq(L, b)
# Check
print(x.shape, x2.shape)
diff = abs(x - x2).max()
print("difference: ", diff)
assert diff < 1e-13
test_it()
Some timing suggests the stacked version is around 6x faster here, for that problem size. Whether it's worth the trouble depends on the problem.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With