Vektoren und Matrizen
Ein Vektor ist eine flache Liste von Zahlen, etwa eine Richtung im Raum oder eine Reihe von Mengen. Eine Matrix ist eine Liste aus Zeilen. Auf dieser Seite geht es um Skalar- und Kreuzprodukte, Matrixmultiplikation, Determinanten und Inverse, das gleichzeitige Lösen mehrerer linearer Gleichungen und die numerischen Werkzeuge der linearen Algebra: Eigenwerte sowie QR-, LU- und Singulärwertzerlegung.
Das hilft dir bei Übungen zur linearen Algebra, bei Geometrie und Transformationen oder bei jedem Problem mit mehreren Unbekannten, die durch lineare Gleichungen verbunden sind. Vektoren und Matrizen sind gewöhnliche Listen, deshalb gilt alles aus Listen und Statistik, etwa das Indizieren, auch hier.
Vektoren
dot([1, 2, 3], [4, 5, 6]) ergibt 32dot([3, 4], [4, -3]) ergibt 0cross([1, 0, 0], [0, 1, 0]) ergibt [0, 0, 1]cross([1, 2, 3], [4, 5, 6]) ergibt [-3, 6, -3]v = [3, 4]sqrt(dot(v, v)) ergibt 5dot multipliziert zusammengehörige Elemente und addiert die Ergebnisse. Ein Skalarprodukt von null bedeutet, dass die beiden Vektoren im rechten Winkel zueinander stehen, wie [3, 4] und [4, -3]. cross liefert einen Vektor, der zu beiden Eingaben im rechten Winkel steht: Die x-Richtung gekreuzt mit der y-Richtung ergibt die z-Richtung. Die Länge eines Vektors ist die Quadratwurzel seines Skalarprodukts mit sich selbst.
dot braucht zwei Vektoren gleicher Länge, cross zwei Vektoren mit je drei Elementen. Um Vektoren zu addieren oder zu skalieren, nimm das normale Rechnen mit Listen: [1, 2] + [3, 4] ist [4, 6] und 2 * [3, 4] ist [6, 8].
Matrizen schreiben und multiplizieren
Schreib eine Matrix als Liste aus Zeilen, jede Zeile in ihren eigenen eckigen Klammern:
shape([[1, 2, 3], [4, 5, 6]]) ergibt [2, 3]transpose([[1, 2, 3], [4, 5, 6]]) ergibt [[1, 4], [2, 5], [3, 6]]identity(3) ergibt [[1, 0, 0], [0, 1, 0], [0, 0, 1]][[1, 2], [3, 4]] * [[5, 6], [7, 8]] ergibt [[19, 22], [43, 50]]shape liefert [Zeilen, Spalten]. transpose vertauscht Zeilen und Spalten. identity(n) ist die n×n-Matrix, die eine andere Matrix unverändert lässt, wenn du mit ihr multiplizierst.
* zwischen zwei Matrizen ist die Matrixmultiplikation. Dafür muss die linke Matrix so viele Spalten haben, wie die rechte Zeilen hat. Um eine Matrix mit einem Vektor zu multiplizieren, schreib den Vektor als Spalte, ein Element pro Zeile:
# Den Punkt (3, 1) um 90° gegen den Uhrzeigersinn drehenDrehung = [[0, -1], [1, 0]]Drehung * [[3], [1]] ergibt [[-1], [3]]Drehung * Drehung ergibt [[-1, 0], [0, -1]]Zweimal um 90° gedreht ergibt eine halbe Drehung, deshalb kehrt Drehung * Drehung beide Vorzeichen um. Eine flache Liste wie [3, 1] wird rechts von einer Matrix nicht akzeptiert. Steht eine flache Liste in einem Namen, macht transpose([v]) daraus eine Spalte.
Matrizen gleicher Form lassen sich addieren und subtrahieren und wie andere Listen mit einer Zahl multiplizieren oder durch sie teilen.
Für jede Matrixoperation gelten ein paar Regeln:
- Jede Zeile muss gleich viele Elemente haben.
- Elemente müssen reine Zahlen sein. Einheiten und Geldbeträge werden nicht akzeptiert.
- Eine Matrix kann höchstens 32 Zeilen und 32 Spalten haben.
- Es gibt keine Kurzschreibweise mit Semikolon. Schreib
[[1, 2], [3, 4]], nicht[1, 2; 3, 4].
Determinante, Inverse, Spur und Rang
M = [[2, 1], [5, 3]]det(M) ergibt 1inverse(M) ergibt [[3, -1], [-5, 2]]M * inverse(M) ergibt [[1, 0], [0, 1]]trace(M) ergibt 5inverse([[2, 1], [1, 3]]) ergibt [[0.6, -0.2], [-0.2, 0.4]]det([[1, 2], [2, 4]]) ergibt 0rank([[1, 2, 3], [2, 4, 6]]) ergibt 1det, inverse und trace (die Summe der Diagonale) brauchen eine quadratische Matrix. Eine Determinante von null bedeutet, dass die Matrix singulär ist: Ihre Zeilen sind nicht unabhängig, sie hat also keine Inverse, und inverse([[1, 2], [2, 4]]) ist ein Fehler. rank zählt, wie viele Zeilen unabhängig sind, und akzeptiert auch nicht quadratische Matrizen. In der letzten Zeile ist die zweite Zeile das Doppelte der ersten, der Rang ist also 1.
Diese vier rechnen mit exakten Brüchen statt mit Dezimalzahlen, deshalb ergibt M * inverse(M) exakt die Einheitsmatrix.
Ein lineares Gleichungssystem lösen
Angenommen, drei Kaffee und zwei Tee kosten 13,50 €, und ein Kaffee und vier Tee kosten 11,50 €. Schreib die Anzahl jedes Getränks als eine Zeile pro Gleichung, mit den Spalten in fester Reihenfolge (Kaffee, Tee), und die Summen in eine passende Liste:
solve_system([[3, 2], [1, 4]], [13.5, 11.5]) ergibt [3.1, 2.1]Das Ergebnis steht in derselben Reihenfolge wie die Spalten: Ein Kaffee kostet 3,10 € und ein Tee 2,10 €. Lass die Währungssymbole weg, denn Matrixelemente müssen reine Zahlen sein.
solve_system(A, b) löst A * x = b nach x auf. Es braucht eine quadratische Matrix mit einer Zeile pro Unbekannter und eine flache Liste mit ebenso vielen rechten Seiten. Es rechnet mit exakten Brüchen, das Ergebnis hat also keinen Rundungsfehler.
Legen die Gleichungen kein eindeutiges Ergebnis fest, erhältst du einen Fehler, dass das System keine eindeutige Lösung hat. So schlägt zum Beispiel solve_system([[1, 2], [2, 4]], [3, 6]) fehl, weil die zweite Gleichung das Doppelte der ersten ist. solve_system löst nur lineare Gleichungen; für eine Gleichung wie x^2 = 2 nimm solve aus Summen, Gleichungen lösen und Analysis.
Eigenwerte
eigenvalues([[2, 1], [1, 2]]) ergibt [1, 3]eigenvalues([[4, 1], [2, 3]]) ergibt [5, 2]eigenvalues([[0, -1], [1, 0]]) ergibt [i, -i]eigenvalues nimmt eine quadratische Matrix und gibt eine flache Liste zurück. Eine Drehung um 90° lässt keine Richtung unverändert, ihre Eigenwerte sind deshalb das komplexe Paar i und -i; siehe Komplexe Zahlen. Verlass dich nicht auf die Reihenfolge der Liste.
Zerlegungen: QR, LU und SVD
Jede Zerlegung gibt eine Liste von Matrizen zurück. Über Indizes holst du die Teile heraus:
A = [[3, 0], [4, 5]]Teile = qr(A)q = Teile[0] ergibt [[0.6, -0.8], [0.8, 0.6]]r = Teile[1] ergibt [[5, 4], [0, 3]]q * r ergibt [[3, 0], [4, 5]]Multiplizierst du die Faktoren wieder miteinander, erhältst du erneut A, so lässt sich eine Zerlegung auf einen Blick prüfen. Beim Rechnen mit binären Gleitkommazahlen bleiben winzige Rundungsreste von etwa 10⁻¹⁵ übrig, die Varlig in Listen und Matrizen als 0 anzeigt. Die gespeicherten Werte behalten alle Stellen, vergleiche Ergebnisse von Zerlegungen also mit bloßem Auge oder über die Differenz, nicht mit ==.
lu([[2, 1], [4, 3]]) ergibt [[[0, 1], [1, 0]], [[1, 0], [0.5, 1]], [[4, 3], [0, -0.5]]]lu gibt [P, L, U] zurück, wobei P alle Zeilenvertauschungen festhält und P * A gleich L * U ist. Hier wurden die Zeilen vertauscht, damit die größere Zahl, 4, zuerst verwendet wird.
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 ergibt [[3, 1], [4, 7]]svd([[3, 4]]) ergibt [[[1]], [5], [[0.6, 0.8]]]svd gibt [U, s, Vt] zurück, wobei s eine flache Liste der Singulärwerte ist, der größte zuerst. In Lehrbüchern ist B gleich U * diag(s) * Vt. Eine Funktion diag gibt es nicht, bau die Diagonalmatrix also selbst, wie in [[s[0], 0], [0, s[1]]].
| Funktion | Was sie braucht und zurückgibt |
|---|---|
identity(n) |
Die n×n-Einheitsmatrix |
shape(A) |
[Zeilen, Spalten] |
transpose(A) |
Zeilen und Spalten vertauscht |
det(A) |
Determinante einer quadratischen Matrix |
inverse(A) |
Inverse einer quadratischen Matrix mit Determinante ungleich null |
trace(A) |
Summe der Diagonale einer quadratischen Matrix |
rank(A) |
Anzahl unabhängiger Zeilen; beliebige rechteckige Matrix |
solve_system(A,b) |
Lösung von A * x = b für eine quadratische Matrix mit genau einer Lösung |
eigenvalues(A) |
Eigenwerte einer quadratischen Matrix, eventuell komplex, in beliebiger Reihenfolge |
qr(A) |
[Q, R] mit Q * R ungefähr gleich A; beliebige rechteckige Matrix |
lu(A) |
[P, L, U] mit P * A ungefähr gleich L * U; quadratische Matrix |
svd(A) |
[U, s, Vt], wobei s eine flache Liste ist; beliebige rechteckige Matrix |
Bei einer nicht quadratischen Matrix geben qr und svd reduzierte Faktoren zurück: Bei einer 3×2-Matrix ist Q ebenfalls 3×2 statt 3×3.
Algorithmen und Grenzen
det, inverse, rank und solve_system rechnen mit exakten Brüchen, innerhalb der Grenzen, die der Rechner für die Größe einer Zahl hat. eigenvalues, qr, lu und svd rechnen mit binären Gleitkommazahlen, ihre Ergebnisse sind also gute Näherungen. Ihre Iterationen enden nach 10.000 Schritten.
Matrizen, deren Zeilen fast abhängig sind, etwa [[1, 1], [1, 1.0000001]], heißen schlecht konditioniert. Kleine Rundungsfehler wachsen beim Rechnen mit ihnen stark an, deshalb können Zerlegungen und Eigenwerte solcher Matrizen an Genauigkeit verlieren, und sehr extreme Fälle können die numerischen Grenzen überschreiten und einen Fehler auslösen.
Die vollständigen Regeln stehen in der Referenz Höhere Mathematik: Möglichkeiten und Grenzen.
Alles zusammen
Drei Kassenbons von einem Marktstand führen auf, wie viele Äpfel, Bananen und Orangen gekauft wurden und was insgesamt bezahlt wurde, aber nicht die einzelnen Preise:
# Jede Zeile: Äpfel, Bananen, OrangenKörbe = [[2, 3, 1], [1, 2, 3], [4, 1, 2]]bezahlt = [2.15, 2.70, 3.05]det(Körbe) ergibt 25Preise = solve_system(Körbe, bezahlt) ergibt [0.4, 0.25, 0.6]# Preise mit jedem Kassenbon abgleichenKörbe * transpose([Preise]) ergibt [[2.15], [2.7], [3.05]]# Was kosten 5 Äpfel, 2 Bananen und 4 Orangen?dot([5, 2, 4], Preise) ergibt 4.9Die Determinante ungleich null bestätigt, dass die Kassenbons ausreichen, um genau einen Satz Preise zu finden: Äpfel zu 40 Cent, Bananen zu 25 Cent und Orangen zu 60 Cent. Multiplizierst du die Körbe mit den Preisen als Spalte, erhältst du wieder die Summen, und dot berechnet für einen neuen Korb 4,90 €.