std.tensor — komplexe Tensoren und Quantenzustände
Tensoren mit allgemeiner Kontraktion über beliebige Achsen; darauf aufgesetzt Quantenzustände, Gatter, reduzierte Dichtematrix und Verschränkungsentropie.
→ Mathematik-Units · std.complex · std.linalg · std.fft
import std.tensor;
Schicht 0, hängt an std.math und std.alloc. 40 Funktionen. Alle Beispiele mit lyxc 1.0.21A übersetzt und ausgeführt.
Darstellung
Ein komplexer Tensor sind zwei f64-Felder — Realteil und Imaginärteil, getrennt und gleich lang. Die Form beschreibt ein int64-Feld shape mit rank Einträgen; TenSize(shape, rank) liefert die Gesamtzahl der Elemente.
| Funktion | Zweck |
|---|---|
TenSize(shape, rank) | Elementzahl aus der Form |
TenStrides(shape, rank, outStrides) | Schrittweiten je Achse |
TenFlatIndex(strides, idx, rank) | Mehrfachindex → flache Position |
TenUnflatten(flat, shape, rank, outIdx) | und zurück |
Rechnen: TenAdd, TenSub, TenScale, TenConj, TenCopy, TenZero, TenNorm, TenNormSq, TenInner.
Umformen und Verknüpfen: TenPermute (Achsen tauschen), TenOuter (äußeres Produkt), TenContract (Kontraktion über gemeinsame Achsen), TenPartialTrace (Teilsystem ausspuren). TenContractRank(rankA, rankB, nAxes) sagt vorab, welchen Rang das Ergebnis hat — nützlich, um den Zielpuffer richtig zu bemessen.
Quantenzustände
Ein Zustand aus nQubits Qubits ist ein Vektor der Länge 2^nQubits; QuStateSize rechnet das aus. Ein Gatter ist selbst ein kleiner Tensor, den die QuGate*-Funktionen füllen — QuApply1 wendet ein Einzelqubit-Gatter an, QuApply2 ein Zweiqubit-Gatter.
unit main;
import std.io;
import std.string;
import std.alloc;
import std.tensor;
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 nq: int64 := 2;
var sz: int64 := QuStateSize(nq);
ZI("StateSize(2 Qubits) : ", sz);
var re: int64 := alloc(sz * 8);
var im: int64 := alloc(sz * 8);
QuStateZero(re, im, nq); // |00>
var g: int64 := alloc(4 * 2 * 8);
var gi: int64 := alloc(4 * 2 * 8);
QuGateH(g, gi);
QuApply1(re, im, nq, 0, g, gi); // Hadamard auf Qubit 0
var c: int64 := alloc(16 * 2 * 8);
var ci: int64 := alloc(16 * 2 * 8);
QuGateCNOT(c, ci);
QuApply2(re, im, nq, 0, 1, c, ci); // CNOT -> Bell-Zustand
ZF("P(|00>) : ", QuProbability(re, im, nq, 0));
ZF("P(|01>) : ", QuProbability(re, im, nq, 1));
ZF("P(|10>) : ", QuProbability(re, im, nq, 2));
ZF("P(|11>) : ", QuProbability(re, im, nq, 3));
ZF("P(Qubit0 = 1) : ", QuProbQubitOne(re, im, nq, 0));
ZF("Norm : ", TenNorm(re, im, sz));
ZF("Entropie Qubit 0 : ", QuEntanglementEntropy(re, im, nq, 0));
return 0;
}
StateSize(2 Qubits) : 4
P(|00>) : 0.499999
P(|01>) : 0.000000
P(|10>) : 0.000000
P(|11>) : 0.499999
P(Qubit0 = 1) : 0.499999
Norm : 0.999999
Entropie Qubit 0 : 1.000000
Das ist der Bell-Zustand: die beiden Qubits sind entweder beide 0 oder beide 1, je zur Hälfte — die gemischten Ergebnisse haben Wahrscheinlichkeit null. Die Norm bleibt 1, wie sie es bei unitären Gattern muss; das ist zugleich eine referenzfreie Prüfung, dass die Gatter richtig angewandt wurden.
Die Entropie ist1, nicht0,693.QuEntanglementEntropyrechnet in Bit, nicht in Nats:0heißt unverschränkt,1maximal verschränkt. Der Bell-Zustand ist maximal verschränkt, also genau 1.
Die Quelle nennt die Genauigkeit selbst mit rund 1e−7, geerbt vonLogF64. Das genügt, um verschränkt von unverschränkt zu unterscheiden — nicht für feine Vergleiche benachbarter Zustände.
| Gruppe | Gatter |
|---|---|
| Einzelqubit | QuGateH · QuGateX · QuGateY · QuGateZ · QuGateS · QuGateT |
| Drehungen | QuGateRX · QuGateRY · QuGateRZ (Winkel in Radiant) |
| Zweiqubit | QuGateCNOT · QuGateCZ · QuGateSWAP |
| Funktion | Zweck |
|---|---|
QuProbability(re, im, nQubits, basis) | Wahrscheinlichkeit eines Basiszustands |
QuProbQubitOne(…, qubit) | Wahrscheinlichkeit, dass ein einzelnes Qubit 1 ist |
QuReducedDensity(…, qubit, outRe, outIm) | reduzierte Dichtematrix (2×2) |
QuEntanglementEntropy(…, qubit) | Von-Neumann-Entropie in Bit |
QuNormalize | Zustand wieder auf Norm 1 bringen |
QuStateZero / QuStateBasis | Anfangszustand setzen |
Grenzen
Der Speicher wächst exponentiell.2^nkomplexe Zahlen zu je 16 Byte: 20 Qubits sind 16 MB, 30 Qubits 16 GB, 40 Qubits nicht mehr darstellbar. Das ist keine Eigenheit dieser Unit, sondern die Natur der Zustandsvektor-Simulation.
Die Entropie gibt es nur für einzelne Qubits.QuReducedDensityspurt auf eine 2×2-Matrix aus, deren Eigenwerte geschlossen dastehen. Für größere Teilsysteme bräuchte es ein Eigenwertverfahren — der Weg wäre die reelle Einbettung einer hermiteschen Matrix undLinEigenSymaus std.linalg; umgesetzt ist er nicht.
Noch nicht auf kompensiertes Summieren umgestellt — drei Stellen. Bei sehr großen Zuständen mit stark verschiedenen Amplituden lohnt eine Gegenprobe über std.sum.
Letzte Aktualisierung: 2026-08-16 · alle Beispiele mit lyxc 1.0.21A übersetzt und ausgeführt; der Bell-Zustand über Wahrscheinlichkeiten, Norm und Entropie geprüft, die Entropie-Einheit aus der Quelle abgelesen.
