Salta al contenuto
Guida di Varlig
Pagina iniziale di Varlig

Vettori e matrici

Un vettore è una lista semplice di numeri, per esempio per rappresentare una direzione nello spazio o un insieme di quantità. Una matrice è una lista di righe. Questa pagina tratta prodotto scalare e vettoriale, moltiplicazione tra matrici, determinanti e inverse, sistemi di equazioni lineari e strumenti numerici di algebra lineare: autovalori e decomposizioni QR, LU e ai valori singolari.

È utile per esercizi di algebra lineare, geometria e trasformazioni, o problemi con più incognite legate da equazioni lineari. Vettori e matrici sono normali liste: si applica quindi anche quanto descritto in Liste e statistiche, compreso l’accesso tramite indice.

Vettori

calc
dot([1, 2, 3], [4, 5, 6]) dà 32
dot([3, 4], [4, -3]) dà 0
cross([1, 0, 0], [0, 1, 0]) dà [0, 0, 1]
cross([1, 2, 3], [4, 5, 6]) dà [-3, 6, -3]
v = [3, 4]
sqrt(dot(v, v)) dà 5

dot moltiplica gli elementi corrispondenti e somma i prodotti. Un prodotto scalare nullo indica vettori perpendicolari, come [3, 4] e [4, -3]. cross restituisce un vettore perpendicolare a entrambi gli argomenti: il prodotto vettoriale della direzione x per la direzione y dà la direzione z. La lunghezza di un vettore è la radice quadrata del suo prodotto scalare con se stesso.

dot richiede due vettori della stessa lunghezza; cross due vettori con tre elementi ciascuno. Per sommare vettori o moltiplicarli per uno scalare, usa le normali operazioni sulle liste: [1, 2] + [3, 4] vale [4, 6] e 2 * [3, 4] vale [6, 8].

Scrittura e moltiplicazione di matrici

Scrivi una matrice come un elenco di righe, ogni riga tra parentesi quadre:

calc
shape([[1, 2, 3], [4, 5, 6]]) dà [2, 3]
transpose([[1, 2, 3], [4, 5, 6]]) dà [[1, 4], [2, 5], [3, 6]]
identity(3) dà [[1, 0, 0], [0, 1, 0], [0, 0, 1]]
[[1, 2], [3, 4]] * [[5, 6], [7, 8]] dà [[19, 22], [43, 50]]

shape restituisce [rows, columns]. transpose scambia righe e colonne. identity(n) è la matrice identità di dimensioni n per n, che lascia invariata una matrice quando la moltiplichi per essa.

* tra due matrici esegue la moltiplicazione matriciale: il numero di colonne della matrice a sinistra deve coincidere con il numero di righe di quella a destra. Per moltiplicare una matrice per un vettore, scrivi il vettore come colonna, con un elemento per riga:

calc
# Rotate the point (3, 1) by 90° anticlockwise
rotate = [[0, -1], [1, 0]]
rotate * [[3], [1]] dà [[-1], [3]]
rotate * rotate dà [[-1, 0], [0, -1]]

Due rotazioni di 90° producono mezzo giro: per questo rotate * rotate cambia entrambi i segni. Una lista semplice come [3, 1] non è accettata a destra di una matrice. Se hai assegnato un nome a una lista semplice, transpose([v]) la trasforma in una colonna.

Come le altre liste, matrici delle stesse dimensioni possono essere sommate o sottratte e moltiplicate o divise per un numero.

Queste regole valgono per tutte le operazioni sulle matrici:

  • Ogni riga deve avere lo stesso numero di elementi.
  • Gli elementi devono essere numeri senza unità. Unità di misura e importi monetari non sono accettati.
  • Una matrice può avere al massimo 32 righe e 32 colonne.
  • Non è supportata la forma abbreviata con punto e virgola. Scrivi [[1, 2], [3, 4]], non [1, 2; 3, 4].

Determinante, inversa, traccia e rango

calc
M = [[2, 1], [5, 3]]
det(M) dà 1
inverse(M) dà [[3, -1], [-5, 2]]
M * inverse(M) dà [[1, 0], [0, 1]]
trace(M) dà 5
inverse([[2, 1], [1, 3]]) dà [[0.6, -0.2], [-0.2, 0.4]]
det([[1, 2], [2, 4]]) dà 0
rank([[1, 2, 3], [2, 4, 6]]) dà 1

det, inverse e trace, la somma degli elementi della diagonale, richiedono una matrice quadrata. Un determinante nullo indica una matrice singolare: le righe non sono linearmente indipendenti e la matrice non ha inversa. inverse([[1, 2], [2, 4]]) genera quindi un errore. rank conta le righe linearmente indipendenti e accetta anche matrici non quadrate. Nell’ultima riga, la seconda riga della matrice è il doppio della prima: il rango è quindi 1.

Queste quattro funzioni usano frazioni esatte anziché decimali: per questo M * inverse(M) restituisce esattamente la matrice identità.

Risolvere un sistema lineare

Supponi che tre caffè e due tè costino £13,50 e che un caffè e quattro tè costino £11,50. Scrivi le quantità di bevande su una riga per ogni equazione, mantenendo fisso l’ordine delle colonne (caffè, tè), e inserisci i totali in una lista corrispondente:

calc
solve_system([[3, 2], [1, 4]], [13.5, 11.5]) dà [3.1, 2.1]

Il risultato segue l’ordine delle colonne: un caffè costa £3,10 e un tè £2,10. Ometti i simboli di valuta, perché gli elementi delle matrici devono essere numeri senza unità.

solve_system(A, b) risolve A * x = b rispetto a x. Richiede una matrice quadrata con una riga per incognita e una lista semplice dei termini noti della stessa lunghezza. Usa frazioni esatte, quindi il risultato non contiene errori di arrotondamento.

Se le equazioni non determinano una soluzione unica, viene segnalato un errore. Per esempio solve_system([[1, 2], [2, 4]], [3, 6]) fallisce perché la seconda equazione è il doppio della prima. solve_system gestisce soltanto equazioni lineari; per un’equazione come x^2 = 2, usa solve, descritto in Sommatorie, equazioni e analisi matematica.

Autovalori

calc
eigenvalues([[2, 1], [1, 2]]) dà [1, 3]
eigenvalues([[4, 1], [2, 3]]) dà [5, 2]
eigenvalues([[0, -1], [1, 0]]) dà [i, -i]

eigenvalues riceve una matrice quadrata e restituisce una lista semplice. Una rotazione di 90° non conserva alcuna direzione, quindi ha gli autovalori complessi i e -i: vedi Numeri complessi. Non fare affidamento sull’ordine della lista.

Scomposizioni: QR, LU e SVD

Ogni decomposizione restituisce un elenco di matrici. Usa gli indici per estrarre le parti:

calc
A = [[3, 0], [4, 5]]
parts = qr(A)
q = parts[0] dà [[0.6, -0.8], [0.8, 0.6]]
r = parts[1] dà [[5, 4], [0, 3]]
q * r dà [[3, 0], [4, 5]]

Moltiplicando nuovamente i fattori ottieni A, così puoi verificare la decomposizione. La virgola mobile binaria introduce piccoli residui di arrotondamento, dell’ordine di 10⁻¹⁵, che Varlig visualizza come 0 nelle liste e nelle matrici. I valori memorizzati conservano tutte le cifre: confronta i risultati visivamente o esaminandone la differenza, senza usare ==.

calc
lu([[2, 1], [4, 3]]) dà [[[0, 1], [1, 0]], [[1, 0], [0.5, 1]], [[4, 3], [0, -0.5]]]

lu restituisce [P, L, U], dove P registra eventuali scambi di riga e P * A è uguale a L * U. Qui le righe sono state scambiate in modo che il numero più grande, 4, venga usato per primo.

calc
B = [[3, 1], [4, 7]]
f = svd(B)
u = f[0]
s = f[1]
vt = f[2]
u * [[s[0], 0], [0, s[1]]] * vt dà [[3, 1], [4, 7]]
svd([[3, 4]]) dà [[[1]], [5], [[0.6, 0.8]]]

svd restituisce [U, s, Vt], dove s è un elenco piatto di valori singolari, prima il più grande. Nei libri di testo B è uguale a U * diag(s) * Vt. Non esiste una funzione diag, quindi costruisci tu stesso la matrice diagonale, come in [[s[0], 0], [0, s[1]]].

Funzione Argomenti richiesti e risultato restituito
identity(n) La matrice identità di dimensione n × n
shape(A) [rows, columns]
transpose(A) Righe e colonne scambiate
det(A) Determinante di una matrice quadrata
inverse(A) Inversa di una matrice quadrata con determinante diverso da zero
trace(A) Somma degli elementi diagonali di una matrice quadrata
rank(A) Numero di righe indipendenti; qualsiasi matrice rettangolare
solve_system(A,b) Soluzione di A * x = b per una matrice quadrata con una singola soluzione
eigenvalues(A) Autovalori, eventualmente complessi, di una matrice quadrata, senza un ordine specifico
qr(A) [Q, R] con Q * R approssimativamente A; qualsiasi matrice rettangolare
lu(A) [P, L, U] con P * A approssimativamente L * U; matrice quadrata
svd(A) [U, s, Vt], dove s è una lista piatta; qualsiasi matrice rettangolare

Per una matrice non quadrata, qr e svd restituiscono fattori in forma ridotta: se la matrice è 3 per 2, anche Q è 3 per 2, anziché 3 per 3.

Cosa è esatto e cosa viene rifiutato

Somma, sottrazione e moltiplicazione tra matrici, moltiplicazione per uno scalare, transpose, det e inverse usano frazioni esatte per tutte le matrici accettate da Varlig. Non viene applicato alcun arrotondamento né agli argomenti né ai risultati riutilizzati in altri calcoli: una matrice moltiplicata per la propria inversa dà quindi esattamente la matrice identità.

calc
[[1, 2], [3, 4]] + [[10, 20], [30, 40]] dà [[11, 22], [33, 44]]
[[1, 2], [3, 4]] - [[1, 1], [1, 1]] dà [[0, 1], [2, 3]]
3 * [[1, 2], [3, 4]] dà [[3, 6], [9, 12]]
[[1, 2], [3, 4]] * [[0, 1], [1, 0]] dà [[2, 1], [4, 3]]
det([[1, 2], [3, 4]]) dà -2
inverse([[1, 2], [3, 4]]) dà [[-2, 1], [1.5, -0.5]]
inverse([[1, 2], [3, 4]]) * [[1, 2], [3, 4]] dà [[1, 0], [0, 1]]

Ogni condizione viene verificata prima di mostrare un risultato; il messaggio indica quale non è stata soddisfatta.

calc
det([[1, 2, 3], [4, 5, 6]]) dà Unsupported: Expected a square matrix
inverse([[1, 2], [2, 4]]) dà Unsupported: Singular matrix has no inverse
[[1, 2], [3, 4]] + [[1, 2, 3], [4, 5, 6]] dà Unsupported: List dimensions do not match
[[1, 2, 3], [4, 5, 6]] * [[1, 2], [3, 4]] dà Unsupported: Matrix inner dimensions do not match

Gli elementi delle matrici devono essere numeri senza unità. La presenza di un’unità, un importo monetario o un valore complesso interrompe il calcolo, perché le operazioni sulle matrici non ne garantiscono la conservazione.

calc
det([[1 kg, 2], [3, 4]]) dà Unsupported: Matrix entries must be plain numbers; units, money and complex values are not supported

Solo una lista di righe viene interpretata come matrice. Una lista semplice conserva il proprio significato: [1, 2] + [3, 4] esegue ancora la somma elemento per elemento, ottenendo [4, 6]; [1, 2] * [3, 4] genera ancora un errore che rimanda a dot.

Le regole di esattezza per equazioni, matrici e statistiche sono raccolte in Garanzie del motore di calcolo.

Algoritmi e limiti

det, inverse, rank e solve_system usano frazioni esatte, entro i limiti del calcolatore sulla dimensione dei numeri. eigenvalues, qr, lu e svd usano la virgola mobile binaria e restituiscono approssimazioni accurate. Le iterazioni si interrompono dopo 10.000 passaggi.

Matrici con righe quasi linearmente dipendenti, come [[1, 1], [1, 1.0000001]], si dicono mal condizionate. Piccoli errori di arrotondamento possono amplificarsi molto: decomposizioni e autovalori possono quindi perdere precisione. Nei casi estremi si possono superare i limiti numerici, ottenendo un errore.

Le regole complete sono nella documentazione di riferimento sulla matematica avanzata.

Un esempio completo

Tre ricevute da una bancarella di mercato elencano quante mele, banane e arance sono state acquistate e il totale pagato, ma non i singoli prezzi:

calc
# Each row: apples, bananas, oranges
baskets = [[2, 3, 1], [1, 2, 3], [4, 1, 2]]
paid = [2.15, 2.70, 3.05]
det(baskets) dà 25
prices = solve_system(baskets, paid) dà [0.4, 0.25, 0.6]
# Check the prices against every receipt
baskets * transpose([prices]) dà [[2.15], [2.7], [3.05]]
# What would 5 apples, 2 bananas and 4 oranges cost?
dot([5, 2, 4], prices) dà 4.9

Il determinante non nullo conferma che gli scontrini permettono di ricavare un unico insieme di prezzi: mele a 40p, banane a 25p e arance a 60p. Moltiplicando la matrice dei carrelli per la colonna dei prezzi si ritrovano i totali; dot calcola £4,90 per un nuovo carrello.