====== std.tensor — komplexe Tensoren und Quantenzustände ====== Tensoren mit allgemeiner Kontraktion über beliebige Achsen; darauf aufgesetzt Quantenzustände, Gatter, reduzierte Dichtematrix und Verschränkungsentropie. → [[lyx_-_programmiersprache:units:mathematik|Mathematik-Units]] · [[lyx_-_programmiersprache:units:complex|std.complex]] · [[lyx_-_programmiersprache:units:linalg|std.linalg]] · [[lyx_-_programmiersprache:units:fft|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 ist ''1'', nicht ''0,693''.** ''QuEntanglementEntropy'' rechnet in **Bit**, nicht in Nats: ''0'' heißt unverschränkt, ''1'' maximal verschränkt. Der Bell-Zustand ist maximal verschränkt, also genau 1. > > Die Quelle nennt die Genauigkeit selbst mit **rund 1e−7**, geerbt von ''LogF64''. 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^n'' komplexe 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.** ''QuReducedDensity'' spurt 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 und ''LinEigenSym'' aus [[lyx_-_programmiersprache:units:linalg|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 [[lyx_-_programmiersprache:units:sum|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.