5.4.11Scientific Computing (Python)

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

1,958 words9 min readdifficulty · medium

WHY scipy.linalg over numpy.linalg

WHY "more stable"? It's not magic — both call LAPACK. The practical differences:

  1. scipy.linalg is always compiled against an optimized, complete LAPACK/BLAS; numpy may fall back to slower/less-complete routines depending on build.
  2. scipy lets you pick the stable algorithm explicitly (e.g. solve via LU with partial pivoting, or via Cholesky if SPD) instead of a one-size-fits-all path.
  3. Never compute inv(A) @ b — that's the real instability. Use solve/factorizations.

The three core factorizations

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

1. LU — for solving Ax=bAx=b

import numpy as np
from scipy.linalg import lu, lu_factor, lu_solve, solve
A = np.array([[2.,1.],[6.,5.]]); b = np.array([3.,17.])
P, L, U = lu(A)                 # SciPy convention: P @ A = L @ U  (so A = P.T @ L @ U)
x = solve(A, b)                 # the right way to solve  -> x = [-0.5, 4.]
lu_piv = lu_factor(A)           # reuse factorization for many b's
x2 = lu_solve(lu_piv, b)

2. QR — for least squares & orthogonalization

from scipy.linalg import qr, lstsq
Q, R = qr(A, mode='economic')   # economic: Q is m×n, R is n×n
x, res, rank, sv = lstsq(A, b)  # robust least squares (uses SVD/QR internally)

3. Schur — for eigenvalues & matrix functions

from scipy.linalg import schur, eig
T, Z = schur(A)                 # A = Z @ T @ Z.conj().T
w, vl, vr = eig(A, left=True)   # scipy gives left+right eigenvectors
# generalized eigenproblem A x = λ B x  (numpy can't do this!):
w_gen = eig(A, b=np.eye(len(A)))

Recall Feynman: explain to a 12-year-old

Imagine a tangled machine that twists arrows around. It's hard to understand the tangle directly. So we break the machine into simple pieces: one piece only stretches (triangular), one piece only spins without stretching (orthogonal/unitary). Once it's in simple pieces, answering questions like "which arrow comes out as itself?" (eigenvalues) or "undo the machine to get back the original arrow" (solve Ax=bAx=b) becomes easy. scipy.linalg is the box of tools that does these clean breaks carefully so tiny rounding mistakes don't blow up.

Why use scipy.linalg over numpy.linalg?
Full LAPACK interface (lu, qr, schur, cho_factor, generalized eig), always linked to optimized LAPACK/BLAS, and lets you pick the stable algorithm explicitly.
What is the LU factorization with pivoting?
PA=LUPA=LU — P permutation (row swaps for stability), L unit-lower-triangular (elimination multipliers), U upper triangular.
How do you solve Ax=b once you have PA=LU?
Forward-solve Ly=PbLy=Pb, then back-solve Ux=yUx=y.
Why never compute inv(A)@b?
~3× more flops and amplifies rounding error; use solve()/factorizations instead.
What convention does scipy.linalg.lu return?
P, L, U with P @ A = L @ U (equivalently A = P.T @ L @ U), NOT A = P @ L @ U.
Define QR factorization.
A=QRA=QR with Q orthogonal (QTQ=IQ^TQ=I) and R upper triangular.
Why does QR solve least squares stably?
Orthogonal Q preserves length, so min reduces to Rx=QTbRx=Q^Tb; avoids normal equations which square the condition number.
What sits on the diagonal of T in the Schur form A=ZTZHA=ZTZ^H?
The eigenvalues of A.
Why prefer Schur over diagonalization numerically?
Schur always exists and uses unitary Z (condition number 1), even for defective/non-diagonalizable matrices.
Which scipy feature does numpy.linalg lack for eigenproblems?
The generalized eigenproblem Ax=λBxAx=\lambda Bx via eig(A, b=B).
Relationship between κ(A) and the normal equations?
Normal equations have condition number κ(A)2\kappa(A)^2, making them less accurate than QR.

Connections

Concept Map

wraps

wraps subset of

exposes more than

provides

enables

preferred over

amplifies rounding error

gives

uses partial pivoting for

LAPACK Fortran

scipy.linalg

numpy.linalg

Matrix factorizations

LU: PA = LU

QR factorization

Schur factorization

solve Ax=b

Compute inv A then multiply

More stable and accurate

Hinglish (regional understanding)

Intuition Hinglish mein samjho

Dekho, matrix ek "machine" hai jo vectors ko transform karti hai. Seedha-seedha is machine ke saath kaam karna mushkil hota hai, isliye hum use simple pieces me todte hain — yahi "factorization" kehlata hai. scipy.linalg me yeh saare tools available hain, aur numpy.linalg se zyada complete hai: isme lu, qr, schur, generalized eigenvalues sab milte hain.

Teen main factorizations yaad rakho. LU (PA=LUPA=LU) = Gaussian elimination ko record karna, jise hum Ax=bAx=b solve karne ke liye use karte hain — pehle Ly=PbLy=Pb (forward), phir Ux=yUx=y (back). QR (A=QRA=QR) me Q orthogonal hota hai (length preserve karta hai), isliye least-squares problem Axb\|Ax-b\| minimize karna easy ho jaata hai bina normal equations (ATAA^TA) use kiye — kyunki normal equations condition number ko square kar dete hain, accuracy gir jaati hai. Schur (A=ZTZHA=ZTZ^H) me eigenvalues T ke diagonal pe baith jaate hain, aur yeh hamesha exist karta hai even jab matrix diagonalize nahi hoti — kyunki Z unitary hai (perfectly conditioned).

Sabse important practical baat: kabhi inv(A)@b mat likho. Yeh slow bhi hai aur rounding error ko badhata hai. Hamesha solve(A,b) use karo. Note: scipy.linalg.lu(A) ka convention hai P@A=L@UP @ A = L @ U (yaani A=PT@L@UA = P^T @ L @ U), galti se A=P@L@UA=P@L@U mat samajhna. Mnemonic: "LU Solves, QR Squares, Schur Spectra." Bas yeh ek line yaad rahi toh poora chapter ka 80% cover ho gaya.

Go deeper — visual, from zero

Test yourself — Scientific Computing (Python)

Connections