Wie dieses Paket zu ffsim steht
Die Konzepte in diesem Leitfaden sind nur in der Python-API verfügbar.
ffsim und dieses Paket teilen die Arbeit auf, statt sich zu überschneiden, entlang einer einzigen Linie:
| ffsim ist zuständig für | qiskit-fermions ist zuständig für |
|---|---|
Die übergeordneten Ansatz-Operatoren (UCJOpSpinBalanced, UCCSDOpRestrictedReal und ihre Verwandten), erstellt aus Coupled-Cluster-Amplituden oder einem Parametervektor | Den fermionischen Circuit (FermionicCircuit), zu dem diese Operatoren werden, und seine Transpilation in einen Qubit-Circuit unter einer beliebigen Fermion-zu-Qubit-Kodierung |
| Schnelle Simulation in einem kompakten Raum fester Teilchenzahl | Das Mapper-Framework und die Operator-Datenstrukturen, aus denen der Circuit erstellt wird |
Die praktische Folge gilt in beide Richtungen. Die Ansatz-Mathematik liegt in ffsim, sodass UCJ und UCC einen ffsim-Operator direkt als Eingabe nehmen. Umgekehrt sind die eigenen Qiskit-Gates von ffsim spezifisch für die Jordan-Wigner-Transformation, sodass der Gewinn, einen seiner Ansatz-Operatoren hierher zu bringen, darin besteht, ihn über eine andere Kodierung abzusenken.
Die Simulation ist der Punkt, an dem sich beide treffen, und dieser Leitfaden erklärt, wie. ffsim ist das Simulations-Backend dieses Pakets, erreicht über seine eigenen Protokolle statt über einen Wrapper: Der SKQD-Leitfaden ruft ffsim.apply_unitary(), ffsim.linear_operator() und ffsim.sample_state_vector() direkt auf FermionicCircuit-Objekten und FermionOperator-Objekten ohne Konvertierungsschritt auf.
An die Simulationsschnittstelle von ffsim andocken
ffsim ist ein Hochleistungssimulator für fermionische Quantencircuits, der Teilchenzahl- und Spin-Z-Erhaltung ausnutzt, um Zustandsvektoren kompakter darzustellen als ein generischer -dimensionaler Qubit-Zustandsvektor. Er definiert Protokolle, die jedes Objekt implementieren kann, um an seiner Simulationsmaschinerie teilzunehmen (siehe qiskit_fermions.protocols für die eigenen Protokolle dieses Pakets, die demselben Entwurf folgen):
-
ffsim.SupportsApplyUnitary, über die Methode_apply_unitary_(vec, norb, nelec, copy), die das Objekt als Unitäre auf einen Zustandsvektor fester Teilchenzahl anwendet -
ffsim.SupportsLinearOperator, über die Methode_linear_operator_(norb, nelec), die einescipy.sparse.linalg.LinearOperator-Sicht auf das Objekt in demselben Sektor zurückgibt -
ffsim.SupportsTrace, über die Methode_trace_(norb, nelec), die die Spur des Objekts in diesem Sektor zurückgibt.
Dieses Paket implementiert diese Schnittstelle: Jedes fermionische Gate in qiskit_fermions.circuit.library stellt _apply_unitary_ bereit, und FermionOperator stellt _linear_operator_ und _trace_ bereit. Dadurch sind die Operatoren und Circuits dieses Pakets mit ffsim kompatibel, sodass seine Werkzeuge nativ und ohne Konvertierungsschritt mit ihnen arbeiten. ffsim.apply_unitary() kann einen FermionicCircuit von Anfang bis Ende simulieren, ffsim.linear_operator() kann einen FermionOperator diagonalisieren, und Sampling-Werkzeuge wie ffsim.sample_state_vector() (im SKQD-Leitfaden verwendet, um einen simulierten Zustandsvektor in Messzählungen umzuwandeln) funktionieren ohne Änderung.
Was _linear_operator_ zurückgibt, ist ein gewöhnlicher SciPy-LinearOperator, sodass scipy.sparse.linalg.eigsh() und verwandte Funktionen auch darauf funktionieren.
>>> import ffsim
>>> import numpy as np
>>>
>>> from qiskit_fermions.circuit import FermionicCircuit
>>> from qiskit_fermions.circuit.library import Evolution
>>> from qiskit_fermions.operators import FermionOperator, ann, cre
>>>
>>> norb, nelec = 2, (1, 1)
>>> hamiltonian = FermionOperator.from_terms([
... ([cre(0), ann(1)], 0.5),
... ([cre(1), ann(0)], 0.5),
... ])
>>>
>>> circuit = FermionicCircuit(2 * norb)
>>> circuit.append(Evolution(2 * norb, hamiltonian, time=1.0), circuit.modes)
>>>
>>> reference = ffsim.hartree_fock_state(norb, nelec)
>>> state = ffsim.apply_unitary(reference, circuit, norb=norb, nelec=nelec) # native ffsim call
Die Kopplung über die Protokolle von ffsim bringt Folgendes: Sein aktiv entwickeltes Ökosystem aus Simulations- und Sampling-Werkzeugen lässt sich unverändert auf die Circuits und Operatoren dieses Pakets anwenden, und Nutzer, die bereits mit ffsim arbeiten, können die Gates und Operatoren dieses Pakets einmischen, ohne eine weitere Simulations-API zu lernen.
ffsim ist eine optionale Abhängigkeit
ffsim ist als optionales Extra deklariert (pip install "qiskit-fermions[ffsim]", oder transitiv durch [all]) und wird zur Laufzeit durch HAS_FFSIM abgesichert (wie oben gezeigt). Die Installation schaltet die Simulation frei: ffsim.SupportsLinearOperator und ffsim.SupportsTrace werden implementiert, indem der FermionOperator dieses Pakets in einen ffsim.FermionOperator umgewandelt wird, sodass sie ohne ffsim MissingOptionalLibraryError auslösen. Alles, was nicht simuliert (Operatoren erstellen, abbilden und die resultierenden Circuits transpilieren), braucht davon nichts.
Fermionische Simulation findet in einem Sektor fester Teilchenzahl statt
Sowohl _apply_unitary_ als auch _linear_operator_ nehmen ein Argument nelec entgegen und stellen den Zustandsvektor über der Determinantenbasis fester Teilchenzahl für diesen (norb, nelec)-Sektor dar, entsprechend dem FCI-Raum-Aufbau von ffsim (und, transitiv, PySCF), statt über dem vollen -dimensionalen Raum, den ein generischer Qubit-Simulator verwenden würde. Das ist ein viel kleinerer Raum (seine Größe ist ein Produkt von Binomialkoeffizienten statt einer Zweierpotenz), bringt aber eine harte Einschränkung mit sich. Nur Operatoren und Gates, die die Teilchenzahl erhalten (und im spinbehafteten Fall die Teilchenzahl jeder Spinsorte einzeln), lassen sich darin darstellen. Ein Operator, dessen Wirkung Amplitude in eine andere Teilchenzahl verschieben würde, hat dafür keinen Platz.
ffsim löst das, indem es einen solchen Operator rundweg ablehnt: Die Umwandlung in einen linearen Operator löst einen ValueError aus, der benennt, welcher Erhaltungssatz verletzt ist. Das ist die richtige Voreinstellung, denn die Anwendung von für einen Hamiltonian mit einem Term, der die Teilchenzahl nicht erhält, würde sonst eine eigentlich unitäre Abbildung in eine nicht unitäre, physikalisch bedeutungslose verwandeln.
-
Evolutionreicht diese Ablehnung von dem Operator weiter, den es entwickelt. -
OrbitalRotationprüft, dass seine (eingebettete) Rotationsmatrix im spinbehafteten Fall über die Alpha/Beta-Aufteilung hinweg blockdiagonal ist, und löst einenValueErroraus, wenn sie Spinsektoren vermischt.
>>> from qiskit_fermions.circuit.library import Evolution
>>>
>>> non_conserving = FermionOperator.from_terms([([cre(0), cre(1)], 1.0)]) # creates 2 particles
>>> gate = Evolution(2 * norb, non_conserving, time=1.0)
>>>
>>> try:
... gate._apply_unitary_(reference, norb, nelec, copy=True)
... except ValueError as exc:
... print("rejected:", exc)
rejected: The given FermionOperator could not be converted to a LinearOperator because it does not conserve particle number and the z component of spin. Conserves particle number: False Conserves spin z: False
Eine Simulation ohne Teilchenzahlerhaltung ist im fermionischen Raum daher durch die Konstruktion der Darstellung mit festem Sektor nicht möglich, und das ist der Preis für den kompakten FCI-Raum, der die fermionische Simulation überhaupt erst handhabbar macht. Wenn dein Algorithmus Operatoren benötigt, die die Teilchenzahl verletzen (zum Beispiel einen Qubit-nativen Fehlerkanal oder einen Operator, der für einen abgebildeten Hamiltonian gebaut wurde, der die Teilchenzahlen nicht term für term erhält), transpiliere zuerst auf Qubits und simuliere den resultierenden QuantumCircuit stattdessen mit einem Simulator auf Qubit-Ebene. Dafür funktioniert jeder Transpilationsweg; die Leitfäden zum fermionischen Circuit und zur Transpilation gehen mehr ins Detail, aber generate_preset_jw_pass_manager() ist eine vernünftige Standardwahl.
Die Blockspin-Konvention für spinbehaftete Systeme
nelec ist als int | tuple[int, int] typisiert, und sein Typ, nicht ein separates Flag, bestimmt, welches der unterstützten Modus-Layouts gewählt wird:
-
Ein int wählt die spinlose Interpretation. Die
norbModi werden direkt als spinlose Orbitale behandelt, undnelecist die Gesamtteilchenzahl. -
Ein Paar
(n_alpha, n_beta)wählt die spinbehaftete Interpretation von2 * norbModi unter einer festen Blockspin-Konvention. Die Modi0 .. norbsind die Alpha-Orbitale (Spin up) und die Modinorb .. 2 * norbsind die Beta-Orbitale (Spin down). Jede Spinsorte wird unabhängig erhalten; ein reiner Alpha-Term kann ein Elektron zwischen Alpha-Modi bewegen, aber nie in einen Beta-Modus, und umgekehrt.
Diese Fallunterscheidung geschieht an jedem ffsim-Protokoll-Einstiegspunkt in diesem Paket (Gate-Konstruktoren, _apply_unitary_placed_-Implementierungen und die Sektorkompilierung des nativen Rust-Kernels), und sie ist die Konvention, die in den Leitfäden zu LUCJ und SKQD durchgängig verwendet wird (zum Beispiel füllt InitializeModes.from_hartree_fock() Alpha-Besetzungen in die Modi 0 .. n_alpha und Beta-Besetzungen in die Modi norb .. norb + n_beta). Es lohnt sich, sie dem Modul qiskit_fermions.operators und allgemein FermionicCircuit gegenüberzustellen, die generische Modusindizes ohne inhärente Spin-Semantik verwenden (siehe den Leitfaden zum fermionischen Circuit). Die Blockspin-Bedeutung wird nur auferlegt, wenn einem Simulationsaufruf ein spinbehaftetes nelec übergeben wird, nicht in der Operator- oder Circuit-Darstellung selbst verankert.
>>> from qiskit_fermions.circuit.library import InitializeModes
>>>
>>> norb, nelec = 3, (2, 1)
>>> init = InitializeModes.from_hartree_fock(norb, nelec)
>>> print([bool(occ) for occ in init.occupation]) # alpha modes 0,1; beta mode 3 (= norb + 0)
[True, True, False, True, False, False]
Nächste Schritte
-
Gehe den Leitfaden zu SKQD durch, um zu sehen, wie
ffsim.apply_unitary()undffsim.sample_state_vector()zusammen verwendet werden, um Circuits aus den Gates dieses Pakets zu sampeln und einen Hamiltonian-Erwartungswert überffsim.linear_operator()auszuwerten (das selbst von derselben hier beschriebenen Protokollmethode_linear_operator_getragen wird). -
Gehe den Leitfaden zu LUCJ für die andere Hälfte der Geschichte durch: einen ffsim-Ansatz-Operator durch die Transpilations-Pipeline dieses Pakets zu führen und auf eine Geräte-Kopplungskarte abzubilden.
-
Lies den Leitfaden zum fermionischen Circuit für die generische, spinagnostische Modusindizierung, die außerhalb von Simulationsaufrufen verwendet wird.
-
Lies den Transpilations-Leitfaden, um zu erfahren, wie du den fermionischen Raum verlässt
und auf Qubits simulierst, was für Operatoren ohne Teilchenzahlerhaltung erforderlich ist.
-
Stöbere in
qiskit_fermions.protocolsfür den vollständigen Katalog der Protokolle, die dieses Paket definiert, einschließlich der Konvertierungsprotokolle (SupportsFermionOperator,SupportsMajoranaOperator), die nichts mit ffsim zu tun haben. -
Lies ffsims eigene Leitfäden für die Workflows, die ffsim selbst besitzt, insbesondere den Aufbau eines UCJ-Ansatzes und dessen variationelle Optimierung. Die Parametervektoren, die diese Leitfäden steuern, sind das, was
UCJundUCCüber die von ihnen gebauten Operatoren akzeptieren.