std.decomp — Matrixzerlegungen
Echte SVD nach einseitigem Jacobi, Pseudoinverse, Rang-k-Näherung, polare Zerlegung und allgemeine Eigenwerte über QR-Iteration.
→ Mathematik-Units · std.linalg · std.sparse
import std.decomp;
Schicht 1, hängt an std.linalg, std.math und std.alloc. 14 Funktionen — die kleinste Schnittstelle der Sammlung bei 913 Zeilen Umsetzung. Alle Beispiele mit lyxc 1.0.21A übersetzt und ausgeführt.
Verhältnis zu ''std.linalg''
std.decomp ist die Fortsetzung von std.linalg, nicht dessen Ersatz. Die Trennung verläuft entlang „Lösen„ gegen „Zerlegen“:
| Aufgabe | Unit |
|---|---|
| Quadratisches System lösen, Determinante, Inverse | std.linalg |
| Symmetrische Eigenwerte (Jacobi) | std.linalg |
| SVD, Pseudoinverse, Rang-k-Näherung | std.decomp |
| Allgemeine (nicht symmetrische) Eigenwerte | std.decomp |
Beides zusammen wären über 2000 Zeilen in einer Unit. Getrennt bleibt die Aufteilung verständlich, und wer nur Gleichungssysteme löst, zieht die schwerere Unit nicht mit.
SVD und was daraus folgt
unit main;
import std.io;
import std.string;
import std.alloc;
import std.linalg;
import std.decomp;
fn ZF(t: pchar, v: f64): void { Print(t); PrintF64(v); }
fn ZI(t: pchar, v: int64): void { Print(t); PrintLn(IntToStr(v)); }
fn main(): int64 {
var m: int64 := 3; var n: int64 := 2;
var a: int64 := alloc(m * n * 8);
LinSet(a, n, 0,0, 1.0); LinSet(a, n, 0,1, 2.0);
LinSet(a, n, 1,0, 3.0); LinSet(a, n, 1,1, 4.0);
LinSet(a, n, 2,0, 5.0); LinSet(a, n, 2,1, 6.0);
var s: int64 := alloc(n * 8);
DecompSvdValues(a, m, n, s);
ZF("Singulaerwert 0 : ", peekf64(s));
ZF("Singulaerwert 1 : ", peekf64(s + 8));
ZF("Norm2 : ", DecompNorm2(a, m, n));
ZF("Cond2 : ", DecompCond2(a, m, n));
ZI("Rank : ", DecompRank(a, m, n, DecompEpsilon()));
var b: int64 := alloc(m * 8);
pokef64(b, 1.0); pokef64(b + 8, 2.0); pokef64(b + 16, 3.0);
var x: int64 := alloc(n * 8);
var ok: bool := DecompLstSq(a, m, n, b, DecompEpsilon(), x);
Print("LstSq ok="); Print(IntToStr(ok as int64)); PrintLn("");
ZF("x0 : ", peekf64(x));
ZF("x1 : ", peekf64(x + 8));
var c: int64 := alloc(4 * 8);
LinSet(c, 2, 0,0, 4.0); LinSet(c, 2, 0,1, 1.0);
LinSet(c, 2, 1,0, 2.0); LinSet(c, 2, 1,1, 3.0);
ZF("Spektralradius : ", DecompSpectralRadius(c, 2));
var evr: int64 := alloc(2 * 8);
var evi: int64 := alloc(2 * 8);
DecompEigenGeneral(c, 2, evr, evi);
ZF("Eigenwert 0 Re : ", peekf64(evr));
ZF("Eigenwert 1 Re : ", peekf64(evr + 8));
return 0;
}
Singulaerwert 0 : 9.525518
Singulaerwert 1 : 0.514300
Norm2 : 9.525518
Cond2 : 18.521305
Rank : 2
LstSq ok=1
x0 : 0.000000
x1 : 0.499999
Spektralradius : 5.000000
Eigenwert 0 Re : 5.000000
Eigenwert 1 Re : 2.000000
Sämtliche Werte stimmen mit der Referenzrechnung überein.
Drei Größen fallen mit den Singulärwerten ab, ohne dass man sie einzeln rechnen müsste:
DecompNorm2ist der größte Singulärwert (9,525518).DecompCond2ist das Verhältnis von größtem zu kleinstem (9,525518 / 0,514300 = 18,52).DecompRankist die Anzahl der Singulärwerte oberhalb der Toleranz.
Rang ist eine Frage der Toleranz
<WRAP alert>
DecompRank braucht ein tol, und die Wahl ist eine Entscheidung. In exakter Arithmetik ist der Rang eindeutig; in f64 ist ein Singulärwert von 1e−16 nicht von null zu unterscheiden. DecompEpsilon() liefert 1e−15 als Vorgabe.
Bei gemessenen Daten ist die richtige Schwelle größer: dort trennt sie Signal von Rauschen, und ein Singulärwert unterhalb der Messgenauigkeit ist keine echte Dimension. Wer die Vorgabe nimmt, bekommt bei verrauschten Daten regelmäßig vollen Rang — mathematisch korrekt, sachlich nutzlos. </WRAP>
Pseudoinverse und Ausgleichsrechnung
| Funktion | Zweck |
|---|---|
DecompPseudoInverse(a, m, n, tol, out) | Moore-Penrose-Inverse |
DecompLstSq(a, m, n, b, tol, x) | überbestimmtes System, kleinste Quadrate |
DecompLowRank(a, m, n, k, out) | beste Näherung vom Rang k |
Die Pseudoinverse gibt es auch für nicht quadratische und singuläre Matrizen, wo LinInverse scheitert. Für ein überbestimmtes System liefert DecompLstSq die Lösung mit dem kleinsten Fehlerquadrat — oben x = (0, 0.5) für drei Gleichungen mit zwei Unbekannten.
outdarf nicht aufazeigen.DecompPseudoInverseundDecompPolarprüfen das und gebenfalsezurück; verlassen sollte man sich darauf nicht, sondern getrennte Puffer verwenden.DecompPseudoInversesetzt außerdemm >= nvoraus.
DecompLowRank ist die Grundlage von Kompression und Entrauschen über die SVD: die k größten Singulärwerte tragen den Hauptteil der Information, der Rest ist oft Rauschen.
Eigenwerte allgemeiner Matrizen
| Funktion | Zweck |
|---|---|
DecompHessenberg(a, n, h, q) | Vorbereitung für die QR-Iteration |
DecompEigenGeneral(a, n, evRe, evIm) | Eigenwerte, komplex |
DecompEigenVector(a, n, lambda, vec) | Eigenvektor zu einem bekannten Eigenwert |
DecompSpectralRadius(a, n) | größter Betrag aller Eigenwerte |
DecompPolar(a, n, q, p) | polare Zerlegung A = Q·P |
Die Eigenwerte kommen in zwei Feldern — Real- und Imaginärteil. Eine nicht symmetrische reelle Matrix kann komplexe Eigenwerte haben, und zwar immer paarweise konjugiert. Wer nurevReliest, bekommt bei einer Drehmatrix zwei gleiche Zahlen und übersieht, dass die eigentliche Information im Imaginärteil steckt.
Für symmetrische Matrizen istLinEigenSymaus std.linalg die bessere Wahl: dort sind alle Eigenwerte reell, das Jacobi-Verfahren ist stabiler und liefert die Eigenvektoren gleich mit.
DecompSpectralRadius beantwortet die Frage, ob eine Iteration x ← A·x konvergiert: unter 1 ja, darüber nicht.
Letzte Aktualisierung: 2026-08-16 · alle Beispiele mit lyxc 1.0.21A übersetzt und ausgeführt; Singulärwerte, Kondition, Rang, Ausgleichslösung und Eigenwerte gegen eine unabhängige Referenzrechnung geprüft.
