Reputation: 141
I'm trying to solve an overdetermined system with QR decomposition and linalg.solve but the error I get is
LinAlgError: Last 2 dimensions of the array must be square.
This happens when the R array is not square, right? The code looks like this
import numpy as np
import math as ma
A = np.random.rand(2,3)
b = np.random.rand(2,1)
Q, R = np.linalg.qr(A)
Qb = np.matmul(Q.T,b)
x_qr = np.linalg.solve(R,Qb)
Is there a way to write this in a more efficient way for arbitrary A dimensions? If not, how do I make this code snippet work?
Upvotes: 1
Views: 4727
Reputation: 4963
For updated solution for the case solving multiple right hand sides for the same non square matrix:
import numpy as np
import scipy as sp
numRows = 500
numCols = 100
numIn = 1000 #<! Number of inputs
mA = np.random.randn(numRows, numCols)
mB = np.random.randn(numRows, numIn)
mX = np.zeros(shape = (numCols, numIn))
mQ, mR = sp.linalg.qr(mA, mode = 'economic')
for ii in range(numIn):
mX[:, ii] = sp.linalg.solve_triangular(mR, mQ.T @ mB[:, ii], check_finite = False)
This should be faster than calling higher level functions like solve()
or lstsq()
.
Upvotes: 0
Reputation: 589
You need to call QR with the flag mode='reduced'. The default Q R matrices are returned as M x M and M x N, so if M is greater than N then your matrix R will be nonsquare. If you choose reduced (economic) mode your matrices will be M x N and N x N, in which case the solve routine will work fine.
However, you also have equations/unknowns backwards for an overdetermined system. Your code snippet should be
import numpy as np
A = np.random.rand(3,2)
b = np.random.rand(3,1)
Q, R = np.linalg.qr(A, mode='reduced')
#print(Q.shape, R.shape)
Qb = np.matmul(Q.T,b)
x_qr = np.linalg.solve(R,Qb)
As noted by other contributors, you could also call lstsq directly, but sometimes it is more convenient to have Q and R directly (e.g. if you are also planning on computing projection matrix).
Upvotes: 2
Reputation: 829
The reason is indeed that the matrix R
is not square, probably because the system is overdetermined. You can try np.linalg.lstsq
instead, finding the solution which minimizes the squared error (which should yield the exact solution if it exists).
import numpy as np
A = np.random.rand(2, 3)
b = np.random.rand(2, 1)
x_qr = np.linalg.lstsq(A, b)[0]
Upvotes: 4
Reputation: 88236
As shown in the documentation of numpy.linalg.solve
:
Computes the “exact” solution, x, of the well-determined, i.e., full rank, linear matrix equation ax = b.
Your system of equations is underdetermined not overdetermined. Notice that you have 3 variables in it and 2 equations, thus fewer equations than unknowns.
Also notice how it also mentions that in numpy.linalg.solve(a,b)
, a
must be an MxM
matrix. The reason behind this is that solving the system of equations Ax=b
involves computing the inverse of A
, and only square matrices are invertible.
In these cases a common approach is to take the Moore-Penrose pseudoinverse, which will compute a best fit (least squares) solution of the system. So instead of trying to solve for the exact solution use numpy.linalg.lstsq
:
x_qr = np.linalg.lstsq(R,Qb)
Upvotes: 1