5.4.11 · D3Scientific Computing (Python)

Worked examples — scipy.linalg — more stable than numpy.linalg, lu, qr, schur

3,683 words17 min readBack to topic

This page is a practice range. The parent topic note told you what LU, QR, and Schur are. Here we fire every kind of situation at those tools — nice square systems, singular matrices, tall skinny least-squares, defective eigenvalues, symmetric-positive-definite shortcuts, and a couple of exam traps — and work each one by hand, then check it.

Before we start, four pieces of notation we lean on constantly:


The scenario matrix

Every problem this topic throws at you falls into one of these cells. The worked examples below are labelled with the cell they cover, so by the end you have hit every box.

# Cell (case class) Tool What makes it tricky
C1 Square system, needs a row swap LU pivot on largest entry, track
C2 Zero pivot forces a swap LU naive → divide-by-zero
C3 Singular / degenerate matrix LU has a zero on diagonal → no unique solution
C4 Symmetric positive definite Cholesky skip pivoting, half the work
C5 Tall skinny (overdetermined), least squares QR avoid normal equations
C6 Sign/quadrant of the fit — negative slope QR/lstsq make sure signs come out right
C7 Defective matrix (eig would break) Schur eigenvectors don't span
C8 Complex-eigenvalue rotation (real Schur block) Schur block on diagonal
C9 Word problem (real world) LU translate story →
C10 Exam twist: scipy's convention LU vs trap

Prereqs we reuse: Gaussian Elimination, Gram-Schmidt Orthogonalization, Eigenvalues and Eigenvectors, Cholesky Decomposition, Least Squares, Condition Number, LAPACK and BLAS, and the plain numpy.linalg for contrast.


C1 · LU with a genuine row swap

from scipy.linalg import lu, solve
import numpy as np
A = np.array([[1.,2,2],[4,4,2],[4,6,4]]); b=np.array([3.,6,10])
print(solve(A,b))   # -> [-1.  3. -1.]

C2 · A zero pivot: why the naive formula divides by zero


C3 · A truly singular matrix — no unique solution

from scipy.linalg import lstsq
import numpy as np
A=np.array([[1.,2],[2,4]]); b=np.array([3.,6])
x,res,rank,sv = lstsq(A,b)
print(rank)          # 1  (< 2  => rank-deficient => not unique)

C4 · Symmetric positive definite → use Cholesky, skip pivoting

from scipy.linalg import cho_factor, cho_solve
import numpy as np
A=np.array([[4.,2],[2,3]]); b=np.array([2.,5])
c=cho_factor(A); print(cho_solve(c,b))   # [-0.5  2. ]

C5 · Tall skinny least squares via QR

This one is geometric — look at the picture as you read. In the figure, the magenta dots are the data, the violet line is the fit we are about to derive, and the orange dashed arrows are the residuals whose total length QR minimises.

Figure — scipy.linalg — more stable than numpy.linalg, lu, qr, schur

C6 · Sign check — a negative slope


C7 · Defective matrix — why eig breaks and Schur doesn't


C8 · Real Schur with a complex-eigenvalue block

This is a rotation — see the figure: solid arrows are input vectors , dashed arrows are their images , and no solid/dashed pair is parallel.

Figure — scipy.linalg — more stable than numpy.linalg, lu, qr, schur

C9 · Word problem — mixing two solutions


C10 · Exam twist — scipy's permutation convention

from scipy.linalg import lu
import numpy as np
# 2x2: single swap, P == P.T, both forms agree (does NOT expose the trap)
A2=np.array([[2.,1],[6,5]]); P,L,U=lu(A2)
print(np.allclose(A2, P@L@U), np.allclose(A2, P.T@L@U))   # True True
 
# 3x3 cyclic: P != P.T, only the scipy convention works
A3=np.array([[0.,1,0],[0,0,1],[2,0,0]]); P,L,U=lu(A3)
print(np.allclose(A3, P@L@U))     # True  <- scipy convention
print(np.allclose(A3, P.T@L@U))   # False <- textbook PA=LU form differs here

Recall Scenario checklist — can you name the tool for each?

Row swap needed ::: LU with partial pivoting (track ). Pivot is 0 but matrix is fine ::: swap rows, still LU. Whole row of is 0 ::: singular → no unique solution (use lstsq for min-norm). Symmetric positive definite ::: Cholesky , no pivoting. More equations than unknowns ::: QR least squares (avoid normal equations). Eigenvectors don't span (defective) ::: Schur, not diagonalization. Complex eigenvalues in a real matrix ::: real (quasi-triangular) Schur block. scipy lu reconstruction ::: , not .