std.linalg — dichte lineare Algebra

Matrizen in f64: LU, QR, Cholesky, Gleichungssysteme lösen, Determinante, Inverse, Rang, Ausgleichsrechnung und symmetrische Eigenwerte nach Jacobi.

Mathematik-Units · std.decomp · std.sparse · std.vector

import std.linalg;

Schicht 0, hängt an std.math und std.alloc. 35 Funktionen. Alle Beispiele mit lyxc 1.0.21A übersetzt und ausgeführt und gegen eine unabhängige Referenzrechnung geprüft.


Darstellung

Eine m×n-Matrix ist ein Speicherblock aus m·n f64-Werten, zeilenweise abgelegt. Der Zugriff läuft über LinGet/LinSet, die die Spaltenzahl als Argument bekommen:

var n: int64 := 3;
var a: int64 := alloc(n * n * 8);
LinSet(a, n, 0, 1, -2.0);        // Zeile 0, Spalte 1
var v: f64 := LinGet(a, n, 0, 1);

 
Die Spaltenzahl wird nicht mitgeführt. LinGet(a, cols, i, j) rechnet a + (i·cols + j)·8 und prüft nichts. Ein falsches cols liest stillschweigend an der falschen Stelle — kein Fehler, nur falsche Zahlen. Bei nicht-quadratischen Matrizen ist das die häufigste Fehlerquelle; die Maße gehören neben die Matrix.

Ein vollständiges Beispiel

unit main;
import std.io;
import std.string;
import std.alloc;
import std.linalg;

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 n: int64 := 3;
    var a: int64 := alloc(n * n * 8);
    LinSet(a, n, 0,0,  4.0); LinSet(a, n, 0,1, -2.0); LinSet(a, n, 0,2,  1.0);
    LinSet(a, n, 1,0, -2.0); LinSet(a, n, 1,1,  4.0); LinSet(a, n, 1,2, -2.0);
    LinSet(a, n, 2,0,  1.0); LinSet(a, n, 2,1, -2.0); LinSet(a, n, 2,2,  4.0);

    ZF("Det         : ", LinDet(a, n));
    ZF("Trace       : ", LinTrace(a, n));
    ZI("Rank        : ", LinRank(a, n, n));
    ZI("IsSymmetric : ", LinIsSymmetric(a, n, LinEpsilon()) as int64);
    ZI("IsPosDef    : ", LinIsPosDef(a, n) as int64);
    ZF("NormFro     : ", LinNormFro(a, n, n));
    ZF("Cond2       : ", LinCond2(a, n, n));

    var b: int64 := alloc(n * 8);
    pokef64(b, 1.0); pokef64(b + 8, 2.0); pokef64(b + 16, 3.0);
    var x: int64 := alloc(n * 8);
    var ok: bool := LinSolve(a, n, b, x);
    Print("Solve ok="); Print(IntToStr(ok as int64)); PrintLn("");
    ZF("x0          : ", peekf64(x));
    ZF("x1          : ", peekf64(x + 8));
    ZF("x2          : ", peekf64(x + 16));

    var ev: int64 := alloc(n * 8);
    var evec: int64 := alloc(n * n * 8);
    var ok2: bool := LinEigenSym(a, n, ev, evec);
    LinEigenSortDesc(ev, evec, n);
    Print("Eigen ok="); Print(IntToStr(ok2 as int64)); PrintLn("");
    ZF("lambda0     : ", peekf64(ev));
    ZF("lambda1     : ", peekf64(ev + 8));
    ZF("lambda2     : ", peekf64(ev + 16));
    return 0;
}

Det         : 36.000000
Trace       : 12.000000
Rank        : 3
IsSymmetric : 1
IsPosDef    : 1
NormFro     : 8.124038
Cond2       : 4.529210
Solve ok=1
x0          : 0.666666
x1          : 1.500000
x2          : 1.333333
Eigen ok=1
lambda0     : 7.372281
lambda1     : 2.999999
lambda2     : 1.627718

Sämtliche Werte stimmen mit der Referenzrechnung überein. lambda1 erscheint als 2.999999 statt 3: das Jacobi-Verfahren ist iterativ und endet an einer Schwelle, nicht exakt. Für Eigenwerte gilt daher immer ein Vergleich mit Toleranz (→ std.feq), nie ==.


Gleichungssysteme

Weg Voraussetzung Wann
LinSolve(a, n, b, x) quadratisch, regulär der Normalfall, ein System
LinLuDecompose + LinLuSolve dasselbe mehrere rechte Seiten zur selben Matrix
LinCholesky + LinCholeskySolve symmetrisch positiv definit rund doppelt so schnell
LinLstSq(a, m, n, b, x) überbestimmt (m > n) Ausgleichsrechnung

Die Zerlegung einmal, das Lösen mehrfach. LinSolve zerlegt bei jedem Aufruf neu; wer dasselbe a mit zehn verschiedenen b löst, ruft einmal LinLuDecompose und danach zehnmal LinLuSolve. LinLuDecompose schreibt in die Matrix hinein und braucht zusätzlich ein Permutationsfeld (n Einträge) sowie eine Adresse für das Vorzeichen — wer a danach noch braucht, kopiert vorher mit LinCopy.

LinIsPosDef beantwortet vorab, ob der Cholesky-Weg überhaupt gangbar ist.


Zustand einer Matrix

Funktion Liefert
LinDet(a, n) Determinante über die LU-Zerlegung
LinRank(a, m, n) Rang
LinRref(a, m, n) reduzierte Zeilenstufenform, verändert a
LinCond2(a, m, n) Konditionszahl
LinNormFro · LinNormOne · LinNormInf Normen
LinTrace · LinIsSymmetric · LinEquals Spur, Symmetrie, Vergleich mit eps
 
LinCond2 ist die Frage „darf ich dem Ergebnis trauen?„ Die Konditionszahl sagt, um welchen Faktor sich ein Fehler in den Eingabedaten im Ergebnis verstärkt. Oben ist sie 4,5 — unkritisch. Bei 1e12 bleiben von 16 Stellen noch vier; bei 1e16 ist das Ergebnis wertlos, obwohl LinSolve brav true zurückgibt. Eine erfolgreiche Rückgabe ist keine Aussage über die Genauigkeit.

LinEquals nimmt ein eps, weil ein Vergleich zweier gerechneter Matrizen mit == praktisch immer scheitert. LinEpsilon() liefert den Vorgabewert 1e−12.


Zerlegungen und Eigenwerte

Funktion Ergebnis
LinLuDecompose LU mit Zeilentausch
LinQr(a, m, n, q, r) orthogonales Q, obere Dreiecksmatrix R
LinCholesky(a, n, out) L mit L·Lᵀ = A
LinEigenSym(a, n, evals, evecs) Eigenwerte und -vektoren, nur symmetrisch
LinEigenSortDesc sortiert beide gemeinsam absteigend
LinSingularValues(a, m, n, out) Singulärwerte

LinEigenSym setzt eine symmetrische Matrix voraus — das Jacobi-Verfahren beruht darauf. Für allgemeine Matrizen und für die vollständige SVD ist std.decomp zuständig.

LinEigenSortDesc sortiert Werte und Vektoren gemeinsam; wer nur die Werte sortiert, ordnet die Vektoren falsch zu.


Rechnen

LinAdd, LinSub, LinScale, LinMul, LinMulVec, LinTranspose — dazu LinFill, LinZero, LinIdentity und LinCopy zum Anlegen.

LinMul(a, b, m, k, n, out) multipliziert eine m×k- mit einer k×n-Matrix. Die drei Maße stehen einzeln in der Signatur, weil sich das aus den Zeigern nicht ableiten lässt. out darf nicht auf a oder b zeigen.


Abgrenzung

Aufgabe Unit
Dichte Matrizen, Lösen und Zerlegen std.linalg
SVD, Pseudoinverse, allgemeine Eigenwerte std.decomp
Dünnbesetzte Vektoren std.sparse
Kleine feste Vektoren, Festkomma std.vector

Dünnbesetzte Matrizen und iterative Löser (CG, GMRES) gibt es derzeit nicht. std.matrix aus dem Bestand existiert, hat aber keine eigene Wiki-Seite; für Rechnungen in f64 ist std.linalg der Weg.


Letzte Aktualisierung: 2026-08-16 · alle Beispiele mit lyxc 1.0.21A übersetzt und ausgeführt; Determinante, Norm, Kondition, Lösung und Eigenwerte gegen eine unabhängige Referenzrechnung geprüft.