6.13. Algebra lineare#
L’algebra lineare su una camera è lavoro su piccole matrici: una rotazione 3x3 che fonde un campione della IMU nel frame del mondo, una matrice di calibrazione che rettifica una lente, l’aggiornamento di stato-covarianza di un filtro di Kalman, un fit polinomiale le cui equazioni normali si riducono a una minuscola soluzione lineare. I sottomoduli numpy.linalg e scipy.linalg coprono esattamente questa scala.
Le funzioni risiedono in due moduli. Le operazioni di prodotto tra matrici si trovano al livello superiore di numpy; le decomposizioni e l’inversa di matrice sono sotto numpy.linalg; i risolutori dedicati di sistemi lineari sono sotto scipy.linalg. Una moltiplicazione di matrici 2-per-2, ad esempio:
from ulab import numpy as np
A = np.array([[1, 2], [3, 4]], dtype=np.float)
B = np.array([[5, 6], [7, 8]], dtype=np.float)
np.dot(A, B)
# array([[19.0, 22.0],
# [43.0, 50.0]])
6.13.1. Cosa è disponibile#
dot()– prodotto matriciale o vettoriale.cross()– prodotto vettoriale 3-D.trace()– somma della diagonale.inv()– inversa di matrice.det()– determinante.cholesky()– decomposizione di Cholesky (input simmetrico definito positivo).eig()– autovalori e autovettori di una matrice reale simmetrica.norm()– norma 2 di un vettore o di una matrice.qr()– decomposizione QR conmode='reduced'(predefinita) omode='complete'.solve_triangular()– risolveA @ x = bquandoAè triangolare.cho_solve()– risolveA @ x = bdato un fattore di Cholesky diA.
6.13.2. dot, cross, trace#
dot() è il modo in cui si scrive la moltiplicazione di matrici sulla camera. L’operatore @ che il numpy desktop fornisce per lo stesso scopo non è implementato su ndarray, quindi ogni prodotto matrice-vettore, matrice-matrice e prodotto scalare tra vettori passa per la chiamata dot()
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
np.dot(a, b) # 32.0 (scalar product)
np.cross(a, b) # array([-3.0, 6.0, -3.0])
m = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
np.dot(m, a) # matrix-vector product
np.dot(m, m) # matrix-matrix product
np.trace(m) # 1 + 5 + 9 = 15.0
Il risultato di dot() è sempre di dtype float. cross() è il prodotto vettoriale di due vettori a 3 componenti, trace() la somma della diagonale principale di una matrice quadrata.
6.13.3. inv e det#
m = np.array([[1, 2, 3, 4],
[4, 5, 6, 4],
[7, 9, 9, 4],
[3, 4, 5, 6]])
print(np.linalg.inv(m))
print(np.linalg.det(m))
L’inversa viene calcolata mediante eliminazione di Gauss-Jordan, quindi inv() solleva ValueError quando la matrice è singolare (un elemento diagonale diventa zero durante l’eliminazione). Il costo in RAM è all’incirca il doppio della dimensione dell’input.
Il determinante riutilizza la stessa eliminazione – il tempo di esecuzione è essenzialmente lo stesso dell’inversa.
Quando l’obiettivo dell’applicazione è risolvere un sistema lineare, non invertire e moltiplicare – preferisci i risolutori dedicati riportati sotto. Entrambi sono più veloci e numericamente più affidabili.
6.13.4. cholesky#
Per una matrice simmetrica definita positiva A, cholesky() restituisce una matrice triangolare inferiore L tale che A = L @ L.T
a = np.array([[25, 15, -5],
[15, 18, 0],
[-5, 0, 11]])
L = np.linalg.cholesky(a)
Se l’input non è definito positivo o non è simmetrico, viene sollevato ValueError.
Il fattore di Cholesky richiede metà del lavoro di una fattorizzazione LU ed è il punto di partenza giusto per qualsiasi problema la cui matrice sia nota essere simmetrica definita positiva (aggiornamenti di covarianza, equazioni normali da un fit ai minimi quadrati).
6.13.5. eig#
eig() funziona solo su matrici reali simmetriche. Le matrici non simmetriche sollevano ValueError. Restituisce una 2-tupla (eigenvalues, eigenvectors)
a = np.array([[1, 2, 1, 4],
[2, 5, 3, 5],
[1, 3, 6, 1],
[4, 5, 1, 7]], dtype=np.uint8)
x, y = np.linalg.eig(a)
Note:
Gli autovalori vengono restituiti senza un ordine particolare. Applica
sort()(e la stessa permutazione agli autovettori tramiteargsort()) quando l’ordinamento è importante.Un autovettore è univoco solo a meno di uno scalare non nullo, quindi il segno dei singoli autovettori non è definito in modo univoco. Due esecuzioni corrette possono produrre vettori di segno opposto; questo è innocuo.
6.13.6. norm#
La norma euclidea (di Frobenius) di un vettore o di una matrice:
v = np.array([1, 2, 3, 4, 5])
m = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
np.linalg.norm(v) # 7.416...
np.linalg.norm(m) # 16.881...
La parola chiave opzionale axis= calcola la norma lungo un singolo asse invece che sull’intero array.
6.13.7. qr#
qr() fattorizza una matrice rettangolare A (forma (M, N)) in una matrice ortonormale Q e una matrice triangolare superiore R tali che A == Q @ R
A = np.arange(6).reshape((3, 2))
q, r = np.linalg.qr(A)
# mode='reduced' (default): q is (3, 2), r is (2, 2)
q, r = np.linalg.qr(A, mode='complete')
# q is (3, 3), r is (3, 2)
La decomposizione è implementata tramite successive rotazioni di Givens. È la scelta giusta per problemi ai minimi quadrati in cui la matrice non è simmetrica.
6.13.8. Risolvere i sistemi#
I due risolutori dedicati sotto ulab.scipy.linalg sono entrambi più veloci e più accurati di np.dot(np.linalg.inv(A), b):
solve_triangular(a, b, lower=False)()– risolvea @ x = bassumendo cheasia triangolare:A = np.array([[3, 0, 0, 0], [2, 1, 0, 0], [1, 0, 1, 0], [1, 2, 1, 8]]) b = np.array([4, 2, 4, 2]) x = sp.linalg.solve_triangular(A, b, lower=True)
cho_solve(L, b)()– dato un fattore di CholeskyL, risolveA @ x = bdoveA = L @ L.TL = np.linalg.cholesky(A) x = sp.linalg.cho_solve(L, b)
Ricorri a questi invece di invertire ogni volta che la struttura di A lo consente – risparmiano lavoro di eliminazione e l’inversa esplicita.
6.13.9. Risolvere un piccolo sistema lineare#
A = np.array([[3, 0, 1, 1],
[0, 1, 0, 2],
[1, 0, 1, 1],
[1, 2, 1, 8]])
b = np.array([4, 2, 4, 2])
x = np.dot(np.linalg.inv(A), b)
print(x)
print(np.dot(A, x)) # should equal b
Lo stesso problema può essere espresso fattorizzando A e chiamando il risolutore appropriato – più veloce e più accurato quando A ha la struttura giusta.
Per il riferimento completo a livello di argomenti, vedi numpy.linalg — Routine di algebra lineare e scipy.linalg — Routine di algebra lineare.