Versionshinweise zu Qiskit Fermions
0.2.0
Präludium
Mit dieser Version werden die Möglichkeiten dieses Pakets zur Steuerung der Schaltungssynthese erweitert. Ein Evolution Gatter akzeptiert nun eine explizite synthesis Methode, ein neues synthesis Modul stellt Formeln für das Fermionenprodukt erster und höherer Ordnung bereit, und der FermionicTrotterization Pass wählt eine davon aus und wendet sie auf alle Evolutionen in einem Schaltkreis gleichzeitig an. Darüber hinaus erhielt der Jordan-Wigner-Mapper direkte Implementierungen für alle vier Operatordarstellungen, und dank neuer Adapter kann die Ausgabe eines Mappers vereinfacht oder gruppenweise ausgegeben werden. Die C-API hat erheblich aufgeholt. Die Kanten- und Knotenrepräsentationen, ihre Mapper und ihre Algebra sind nun von C aus zugänglich, ebenso wie die Operatorunterstützung, die Sektorkonservierung, die In-Place- und skalierte Arithmetik sowie die Gruppenreihenfolge. Beide APIs erhielten zudem Zugriff auf die von einem FCIDump geparsten elektronischen Integrale, die zuvor nur durch die Umwandlung der gesamten Datenstruktur in einen Operator erreicht werden konnten. Zudem zieht diese Version eine klarere Grenze hinsichtlich des Verwendungszwecks dieses Pakets: fermionische Operatoren, die Mapper, die diese umwandeln, sowie der Mapper-unabhängige Schaltkreis und dessen Transpilierung. Da Simulation in den Zuständigkeitsbereich von ffsim fällt, wurden der native FCI-Kernel und die ihn duplizierenden Linearalgebra-Hilfsfunktionen entfernt, um diese Aufgaben an ffsim zu delegieren. Die UCJ Gatter UCC und umschließen nun die Operatoren von ffsim, anstatt deren Parametrisierungen neu zu implementieren. Für die Simulation ist daher das ffsim Zusatzmodul erforderlich, das – aufgrund der Abhängigkeit von ffsim von PySCF, – unter Windows nicht verfügbar ist; das Erstellen von Operatoren, deren Zuordnung und das Transpilieren der resultierenden Schaltkreise werden jedoch weiterhin überall unterstützt. Da es sich hierbei noch um eine „ pre-1.0 “-Version handelt, erfolgte all dies durch Entfernung und nicht durch Veralterung: In den unten aufgeführten Upgrade-Hinweisen wird jede entfernte API ihrem Ersatz gegenübergestellt; es empfiehlt sich, diese vor dem Upgrade vollständig durchzulesen.
Python API-Funktionen
-
Wie ein Gatter
Evolutionim fermionischen Raum zerlegt wird, lässt sich nun über sein neues, ausschließlich aus Schlüsselwörtern bestehendessynthesisArgument konfigurieren, das dem Argumentsynthesisvon Qiskits entsprichtPauliEvolutionGate. Die verfügbaren Methoden befinden sich im neuenqiskit_fermions.circuit.library.synthesisModul, das dieFermionicEvolutionSynthesisSchnittstelle und deren ImplementierungFermionicLieTrottererster Ordnung bereitstellt.Dieser Schritt von Fermion zu Fermion ist optional: Ein -Gatter
Evolutionkann direkt an die Fermion-zu-Qubit-Stufe weitergeleitet werden, unabhängig davon, wie viele Terme sein Operator enthält. Eine vorherige Zerlegung ist eine Entscheidung, die getroffen wird, um kostengünstigere Faktoren zu erhalten oder Strukturen (wie beispielsweise gegenseitige Kommutativitätgroups) aufzudecken, die in der späteren Phase genutzt werden können. Da beide Seiten der Umformung im Fermionenraum verbleiben, bleibt diese Struktur erhalten – und genau das können diese Methoden nutzen, während dies mit Qiskit nichtEvolutionSynthesismöglich ist.Die Standardeinstellung bleibt unverändert: Wenn man
synthesisauf belässt, wirdNoneverwendetFermionicLieTrotter, wodurch genau die Zerlegung reproduziert wird, die zuvorEvolutiondurchgeführt hat, sodass bestehende Schaltungen identisch synthetisiert werden. -
Die Stichprobengewichte von
QDriftTrotterizationkönnen nun über das neue, ausschließlich als Schlüsselwort verwendete Argumentweightsübergeben werden, anstatt bei jedem Aufruf aus dem weiterentwickelten Operator abgeleitet zu werden. Wenn man den Wert auf (NoneStandard) belässt, verhält sich das Programm genau wie zuvor, sodass bestehende Schaltkreise identisch abgetastet werden.Dies ist eine Leistungsoption: Der Standardpfad reduziert bei jedem Aufruf von die Anzahl der Werte pro Operatorterm von einem auf einen pro Gruppe
run(), was bei der Erzeugung eines Ensembles aus einem einzelnen Hamilton-Operator doppelte Arbeit bedeutet, obwohl das Ergebnis jedes Mal identisch ist. Leiten Sie es stattdessengroup_coeff_means()einmal mit ab, zusammen mitgroup_order(), wodurch die Gruppensuche aus derselben Schleife herausgelöst wird:hamiltonian = group_order(hamiltonian) weights = group_coeff_means(hamiltonian) pm.optimization = FermionicPassManager( [QDriftTrotterization(num_groups, weights=weights)] )Die Einträge müssen nicht-negativ sein, da ein Gewicht der Betrag der qDRIFT -Zerlegung ist, wobei das Vorzeichen eines Koeffizienten zu gehört und direkt aus dem entwickelten Operator abgelesen wird.
Ein mitgeliefertes Array unterliegt zwei Einschränkungen. Seine Skalierung ist nicht frei: Die Summe der Gewichte bestimmt auch die gemeinsame Evolutionszeit, sodass die Multiplikation jedes Eintrags mit zu identischen
gammaStichproben führt, die sich jedoch über weiterentwickelngamma * t. Und da das Array die Terme (oder Gruppen) eines bestimmten Operators beschreibt, wird seine Länge anhand jedesEvolutionGatters überprüft, auf das es angewendet wird, und eine Schaltung, die mehr als ein solches Gatter enthält, wird abgelehnt; wird dieses Feldweightsnicht gesetzt, wird eine solche Schaltung weiterhin unterstützt, da jedes Gatter dann seine eigene Länge ableitet. -
FCIDumpstellt nun die von ihm analysierten elektronischen Integrale bereit, auf die zuvor nur durch die Konvertierung der gesamten Datenstruktur in ein. zugegriffen werden konnteFermionOperator. Die neuen Methoden geben schreibgeschützte Kopien als „ NumPy “-Arrays zurück, und zwar in demselben abgeflachten Layout, das auch die „electronic-integral“-Konstruktoren verwenden:get_one_body_tril_a(),get_one_body_tril_b(),get_two_body_tril_aa(), undget_two_body_tril_ab()get_two_body_tril_bb(). Die Beta-Spin-Arrays liefern die Werte fürNoneeine spinbeschränkte Datei; das neueis_unrestrictedAttribut gibt Auskunft über alle drei gleichzeitig. Das neue Attributconstantgibt die konstante (Kernabstoßungs-)Energie an, oder – fallsNonedie Datei keine enthält:fcidump = FCIDump.from_file("molecule.fcidump") one_body = fcidump.get_one_body_tril_a() two_body = fcidump.get_two_body_tril_aa()Beachten Sie, dass anders als die anderen Zwei-Körper-Arrays gepackt
get_two_body_tril_ab()ist: Es ist nur vierfach symmetrisch und enthält daher die vollständige Matrix(npair, npair), wobei das Zeilenpaar den Alpha-Spin und das Spaltenpaar die Beta-Spin-Spezies indiziert. Die Indexformel der einzelnen Arrays finden Sie in der Klassendokumentation. Die Erweiterung dieser Elemente zu Dichtematrizen oder(norb, norb)Tensoren(norb,) * 4– wie sie beispielsweise von Werkzeugen zur samplebasierten Diagonalisierung benötigt werden – bleibt dem Aufrufer überlassen. -
FermionicSuzukiTrotterEs wurde eine Formel für ein Produkt höherer Ordnung zur Zerlegung eines -GattersEvolutionim fermionischen Raum hinzugefügt. Wenn jeder Faktor einmalFermionicLieTrotterangewendet wird, werden diese symmetrisch zusammengesetzt, um Fehlerterme niedrigerer Ordnung auszugleichen, und seinrepsArgument unterteilt die Entwicklung in mehrere kürzere Schritte:Evolution(num_modes, operator, time=1.0, synthesis=FermionicSuzukiTrotter(order=2, reps=4))Da er auf den Fermionenoperator wirkt, spaltet er diesen entlang der Stellen,
groupsan denen sie zugewiesen sind – eine Aufteilung, die für eine nach der Fermion-zu-Qubit-Abbildung angewandte Produktformel nicht mehr verfügbar ist. An einer Fermi-Hubbard-Kette mit sechs Moden, die in drei Flussgruppen unterteilt warorder=2, wurde ein Trotter-Fehler erreichtreps=4, der etwa halb so groß war wie bei einer Formel zweiter Ordnung auf der Qubit-Seite, und das bei etwas weniger Zwei-Qubit-Gattern.FermionicLieTrotterist das Element erster Ordnung dieser Familie und wird nun auch als solches implementiert, wodurch es zudem das Argumentrepserhält, das ihm zuvor fehlte. Beide sind bei gleichem Wert austauschbarreps.Beachten Sie, dass eine höhere Ordnung Genauigkeit durch Tiefe gewährleistet: Eine
k„order“-Formel liefert ungefähr mal5**((k-2)/2)so viele Faktoren wie eine „ order-2 “-Formel. Beachten Sie außerdem, dass die Genauigkeit einer zerlegten Schaltung durch die schwächere der beiden Formeln – die Fermionenformel oder die Fermion-zu-Qubit-Formel – bestimmt wird; daher bringt es wenig, hier die Ordnung zu erhöhen, während die letztere in erster Ordnung bleibt. -
Es wurde ein Transpiler-Durchlauf hinzugefügt
FermionicTrotterization, der jedes GateEvolutionin einer Schaltung mithilfe einer Methode zur Fermion-zu-Fermion-Synthese „trotterisiert“:pm.optimization = FermionicPassManager( [FermionicTrotterization(FermionicSuzukiTrotter(order=2, reps=4))] )Die Auswahl einer Synthesemethode pro Gate bedeutet, diese durch alle Komponenten zu führen, aus denen ein besteht
Evolution– einschließlich undUCCUCJ, die intern ihre eigenen Komponenten aufbauen. Dieser Durchlauf trifft die Entscheidung stattdessen einmalig für die gesamte Pipeline. Ein optionales Prädikatfilterschränkt die Auswahl auf eine Teilmenge der Gatter ein. Dies ist sinnvoll, wenn eine Schaltung Entwicklungen, die von einer höheren Ordnung profitieren, mit solchen mischt, bei denen dies nicht der Fall ist, wie beispielsweise bei den vollständig kommutierenden Diagonal-Coulomb-Operatoren einesUCJ.Der Pass entwickelt jedes ausgewählte Gate in die Faktoren auf, die seine Methode ausgibt, sodass kein separater Entwicklungsschritt erforderlich ist. Verwenden Sie „Pass“, um
apply=Falselediglich die Methode auszuwählen und die Erweiterung einem anderen Tool zu überlassen, beispielsweise QiskitDecompose; beachten Sie, dass ein Gatter, das nie erweitert wird, die „Fermion-zu-Qubit“-Phase vollständig erreicht, wo es abgebildet wird, ohne dass es jemalsEvolution.synthesisgelesen wird. -
Das Modul
qiskit_fermions.operators.terms.groupingbehandelt nun neben der Zuweisung von Gruppenindizes auch die Analyse einer bestehenden Gruppierung. Gruppenindizes haben keine eigene Bedeutung, daher gibt keine der neuen Funktionen Auskunft darüber, ob eine Gruppierung „korrekt“ ist; jede beantwortet eine spezifische Frage zu einer Gruppierung, sodass eine Annahme, die ein nachgelagerter Nutzer trifft, im Vorfeld überprüft werden kann, anstatt bei jedem Aufruf erneut berechnet zu werden:groups_are_hermitian()gibt für jede Gruppe an, ob der aus ihren Elementen gebildete Operator hermitesch ist. Dies ist die Eigenschaft, auf der eine randomisierte Produktformel beruht, wenn sie Stichproben aus ganzen Gruppen entnimmt, da nur eine hermitische Gruppe eine unitäre Zeitentwicklung aufweist.groups_have_uniform_coeffs()Gibt für jede Gruppe an, ob ihre Koeffizienten numerisch gleich sind (standardmäßig nach Absolutwert).
Siehe „Begriffe zu Gruppenoperatoren“: Ein Beispiel mit der Operatorstruktur finden Sie dort.
-
Es wurde hinzugefügt
group_order(), was eine Kopie eines Operators zurückgibt, bei der dessen Terme nach Gruppenindex geordnet sind. Jede Gruppe wird zu einer zusammenhängenden Folge von Termen, und die Gruppenindizes werden nicht-absteigend; da die Sortierung stabil ist, behalten die Terme innerhalb einer Gruppe ihre relative Reihenfolge bei. Ein Operator, der keine Gruppenindizes nachverfolgt, hat keine Sortiergrundlage und wird als unveränderte Kopie zurückgegeben.Gruppenindizes geben lediglich an, welche Terme zusammengehören; daher ändert sich dadurch lediglich die Anordnung der Terme eines Operators, nicht jedoch dessen Wert. Das Layout ist der Grund dafür, dass die Gruppensuche kostengünstig ist: Normalerweise
split_out_groups()muss jeder Term durchsucht werden, um die angeforderten Gruppen zu finden, doch bei einem gruppengeordneten Operator werden stattdessen die Gruppengrenzen binär durchsucht, sodass eine Suche nur so viel kostet wie die angeforderten Gruppen und nicht wie die enthaltenen Terme. Eine einmalige Sortierung im Vorfeld zahlt sich daher bei wiederholten Abfragen aus:from qiskit_fermions.operators.terms.ordering import group_order hamil = group_order(hamil) # every subsequent hamil.split_out_groups(group_indices=...) is now a binary searchEs lohnt sich, dies zu tun, bevor man wiederholt mit transpiliert
QDriftTrotterization, da dieses bei jedem Aufruf seine Stichprobengruppen nachschlägt. Ein ausgearbeitetes Beispiel finden Sie unter „ SqDRIFT -Schaltungen generieren “. -
Es wurden direkte Jordan-Wigner-Abbildungen für die drei verbleibenden Operatordatenstrukturen hinzugefügt:
majorana_jordan_wigner(), undedge_vertex_jordan_wigner()transfer_vertex_jordan_wigner(). -
jordan_wigner()Es werden nun alle vier Operatortypen berücksichtigt und nicht mehr nurFermionOperator, wobei die Aufgabe an die direkte Implementierung delegiert wird, die dem jeweiligen Operator entspricht. Die Übergabe eines der anderen drei Betreibertypen führte zuvor zu einemTypeError. -
Die Methode
is_hermitian()ist nun Teil des ProtokollsOperatorTrait. Da jede Operatorklasse diese Funktion bereits bereitstellt, kann sie nun für jeden Wert vom Typ aufgerufen werden und nicht mehrOperatorTraitnur für eine konkrete Operatorklasse.Beachten Sie, dass die Aussagekraft dieser Prüfung je nach Operatortyp variiert, was im Protokoll als dessen schwächste Garantie dokumentiert ist: Ein
TrueErgebnis ist immer zuverlässig, während einFalseErgebnis für Operatortypen, deren Normalform keine echte kanonische Form ist, konservativ ist. Ein Beispiel hierfür finden Sieis_hermitian()unter […]. -
Es wurden zwei Adapter hinzugefügt, die eine Mapper-Funktion umschließen, um die von ihr erzeugte Reihenfolge der Pauli-Terme zu steuern, die nun
MapperFnEvolutionSynthesisbei der Synthese erhalten bleibt.simplify()vereinfacht den abgebildeten Operator, indem doppelte Pauli-Terme zusammengefasst und eine kanonische Reihenfolge der Terme festgelegt werden.group_wise()wendet einen Operator jeweils auf einen Eintraggroupsan und summiert die Ergebnisse. Der Operator bleibt unverändert, aber die Terme jeder Gruppe werden nebeneinander statt verschachtelt angeordnet, wodurch sich diejenigen, die auf disjunkte Qubits wirken, eine Schaltungsschicht teilen können:MapperFnEvolutionSynthesis(group_wise(jordan_wigner)) -
QDriftTrotterizationZeichnet nun auf, wie viele Ziehungen der Modusfilter_trivialverworfen hat. Wenn mindestens einEvolutionGatter tatsächlich gefiltert wurde, enthielt die zurückgegebene Schaltung die Überträgemetadatafilter_trivial.discardedundfilter_trivial.emitted, die jeweils einen Zählwert pro gefiltertem Gatter in der Reihenfolge der Schaltung enthielten. Ihr Verhältnis gibt die Akzeptanzwahrscheinlichkeit an, also den Faktor, um den die Filterung die Koeffizienten der beibehaltenen Terme erhöht hat. Beide Felder sind nicht vorhanden, wenn kein Gate gefiltert wurde; lesen Sie sie daher mit.get(). -
Evolutionkann nun für jeden Operatortyp dieses Pakets simuliert werden, nicht nur fürFermionOperator. Ein Operator anderer Art wird vor der Simulation über sein fermionisches Bild (das ProtokollSupportsFermionOperator) umgewandelt, sodass die Entwicklung vonMajoranaOperator,EdgeVertexOperatoroder nichtTransferVertexOperatormehr zu führtNotImplementedError. -
FermionOperatorwird nunffsim.SupportsTraceüber eine neue_trace_()Methode implementiert, sodass die Spur eines Operators auf einem festen Sektor(norb, nelec)berechnet werdenffsim.trace()kann. Das sind die Voraussetzungen aufscipy.sparse.linalg.expm_multiply()dem Weg der Evolution.
Funktionen der C-API
-
Es wurde hinzugefügt
qf_ferm_op_conserves_sector(), wodurch überprüft wird, ob jeder Term eines die Teilchenzahl innerhalb jedes ModenblocksQfFermionOperatorbeibehält. Es ergänzt die bestehende Funktionqf_ferm_op_conserves_particle_number(), die lediglich die Gesamtsumme überprüft. Bei einer spin-orbitalen Anordnung vonnorbRaumorbitalen{norb, norb}erfordert das Durchlaufen der beiden Blöcke, dass die Alpha- und Beta-Sektoren getrennt erhalten bleiben, d. h. es muss eine strikte Erhaltung sowohl der Teilchenzahl als auch der z-Komponente des Spins gewährleistet sein:uint32_t spin_blocks[2] = {norb, norb}; bool conserves = qf_ferm_op_conserves_sector(op, spin_blocks, 2);Die Übergabe
NULLmit einer Blockanzahl von0behandelt alle Modi als einen einzigen Block, was dem Aufruf von entsprichtqf_ferm_op_conserves_particle_number(). -
Die Unterstützung für den Operator wurde zur C-API hinzugefügt, die zuvor nur unter Python über
get_support. verfügbar war. Jede der vier Operator-Darstellungen erhielt ein Funktionspaar:qf_ferm_op_num_support()undqf_ferm_op_get_support(), sowie die Entsprechungenqf_transfer_opqf_maj_op,qf_edge_opund.Im Gegensatz zu den anderen Gettern geben diese keinen Zeiger auf den Operator zurück, da die Unterstützung bei Bedarf berechnet und nicht gespeichert wird. Rufen Sie zunächst die Funktion
num_supportauf, um die Größe des Ausgabepuffers festzulegen, und übergeben Sie diesen Puffer anschließend anget_support:uint32_t num_support = qf_ferm_op_num_support(op); uint32_t *support = malloc(num_support * sizeof(uint32_t)); qf_ferm_op_get_support(op, support);Die C-Funktionen schreiben die Modusindizes in aufsteigender Reihenfolge, während die Methode „ Python “ eine ungeordnete Liste zurückgibt
set. -
Die C-API wurde um In-Place-Operatorarithmetik erweitert, wodurch die Zuweisung eines Ergebnisoperanden vermieden wird, wenn der linke Operand überschrieben werden kann. Jede der vier Operator-Darstellungen ergab
add_inplace,scaled_add_inplaceundmul_inplace, zum Beispielqf_ferm_op_add_inplace()qf_ferm_op_scaled_add_inplace()undqf_ferm_op_mul_inplace():// Accumulate `factor * right` into `left` without building an intermediate. QkComplex64 factor = {-1.0, 0.0}; qf_ferm_op_scaled_add_inplace(left, right, &factor);Beachten Sie, dass sich die drei in ihrer Behandlung von Gruppenindizes unterscheiden. Die beiden Additionen addieren die Terme des rechten Operanden und setzen daher das Attribut
groupsauf zurückNULL, genau wie es auch tutqf_ferm_op_add().mul_inplaceEs werden lediglich die Koeffizienten skaliert, wodurch die Anzahl der Terme unverändert bleibt und somit die Gruppierung erhalten bleibt. -
Es wurde eine C-API für die Operatordarstellungen „edge-vertex“ und „transfer-vertex“ hinzugefügt, die zuvor nur über Python verfügbar waren. Dazu gehören zwei neue „opaque“-Strukturen,
QfEdgeVertexOperatorundQfTransferVertexOperator, die jeweils über einen Funktionsumfang verfügen, der dem der bestehenden Operator-Strukturen entspricht.Beide Operatoren speichern zwei parallele Index-Arrays, und
left_indicesright_indices, anstelle des einzelnen Arraysmodes, das der Majorana-Operator verwendet. Da ein Generator immer durch genau ein Paar(left, right)identifiziert wird, haben die beiden Arrays zwangsläufig dieselbe Länge, und die Konstruktoren nehmen daher ein einziges Argumentnum_indicesentgegen, das beide abdeckt. -
Es wurden und
qf_edge_op_canonical_order()qf_transfer_op_canonical_order()sowie die Kommutator-, Antikommutator- und Doppelkommutator-Funktionen für beide neuen Operatortypen (qf_edge_op_commutator()und Freunde) hinzugefügt. -
Es wurden C-API-Funktionen für die Edge-Vertex- und Transfer-Vertex-Mapper hinzugefügt:
qf_edge_vertex_to_fermion(),qf_edge_vertex_to_majorana(),qf_transfer_vertex_to_fermion(),qf_transfer_vertex_to_majorana(), undqf_transfer_vertex_to_edge_vertex(). -
Zur
scaled_addC-API wurden für alle vier Operator-Darstellungen hinzugefügt:qf_ferm_op_scaled_add(),qf_maj_op_scaled_add(),qf_edge_op_scaled_add()undqf_transfer_op_scaled_add(). Jede gibt zurückleft + factor * right, wobei die Skalierung in die Addition integriert wird, sodass dabei keine skalierte Kopie des rechten Operanden erstellt wird.So wird die Subtraktion auch in der C-API ausgedrückt, da ein Faktor von die angehängten Koeffizienten negiert
-1:QkComplex64 minus_one = {-1.0, 0.0}; QfFermionOperator *difference = qf_ferm_op_scaled_add(left, right, &minus_one);Was betrifft
qf_ferm_op_add(), so werden die Terme des rechten Operanden angehängt und nicht mit denen des linken kombiniert, sodass das Ergebnis keine Gruppenindizes enthält. Rufe die entsprechende Funktionsimplifyauf, um gleichartige Terme zusammenzufassen. -
QfFCIDumpstellt nun die von ihm analysierten elektronischen Integrale bereit, auf die zuvor nur durch die Konvertierung der gesamten Datenstruktur in ein. zugegriffen werden konnteQfFermionOperator. Die neuen Zugriffsmethodenqf_fcidump_get_one_body_tril_a(),qf_fcidump_get_one_body_tril_b(),qf_fcidump_get_two_body_tril_aa(), undqf_fcidump_get_two_body_tril_ab()qf_fcidump_get_two_body_tril_bb()greifen auf den internen Puffer zurück und schreiben einen Zeiger und eine Länge über Ausgabeparameter:double *integrals; uint64_t len; qf_fcidump_get_one_body_tril_a(fcidump, &integrals, &len);Der zurückgegebene Zeiger darf nicht freigegeben werden und bleibt nur so lange gültig, bis das freigegeben
QfFCIDumpwird. Schütze die drei Beta-Spin-Getter mit dem neuenqf_fcidump_is_unrestricted()undqf_fcidump_constant()mit dem neuenqf_fcidump_has_constant(); der Aufruf eines der beiden ohne Schutz führt zu einem Panic. Informationen zur Indexformel der einzelnen Arrays finden Sie in der Dokumentation zur Kopfzeile; beachten Sie insbesondere, dass anders als die beiden anderen Zwei-Körper-Arrays aufgebautqf_fcidump_get_two_body_tril_ab()ist und die vollständige(npair, npair)Matrix enthält, da es nur vierfach symmetrisch ist. -
Es wurden und
qf_ferm_op_groups_are_hermitian()hinzugefügtqf_ferm_op_groups_have_uniform_coeffs(), die für jede Gruppe angeben, ob der aus ihren Termen gebildete Operator hermitisch ist und ob ihre Koeffizienten numerisch gleich sind, sowie die entsprechenden Funktionen für die Operatortypen Majorana, Kanten-Knoten und Transfer-Knoten. -
Es wurde hinzugefügt
qf_ferm_op_group_order(), das eine Kopie eines Operators zurückgibt, bei der die Terme nach Gruppenindex geordnet sind, sowie die entsprechenden Funktionen für die Operatortypen Majorana (qf_maj_op_group_order()), Kante-Knoten (qf_edge_op_group_order()) und Transfer-Knoten (qf_transfer_op_group_order()). Jede Gruppe wird zu einer zusammenhängenden Folge von Termen, wodurch die Gruppengrenzen mittels binärer Sucheqf_ferm_op_split_out_groups()ermittelt werden können, anstatt jeden Term einzeln zu durchsuchen. -
Es wurden direkte Jordan-Wigner-Mapper für die drei verbleibenden Operator-Datenstrukturen hinzugefügt, zusätzlich zu den bereits vorhandenen
qf_ferm_op_jordan_wigner():qf_maj_op_jordan_wigner(),qf_edge_op_jordan_wigner()undqf_transfer_op_jordan_wigner().
Python Hinweise zum API-Upgrade
-
Die Funktionen
qiskit_fermions.linalg.linear_operatorundqiskit_fermions.linalg.apply_unitarywurden entfernt. Es handelte sich um dünne Wrapper um die_linear_operator_Protokollmethoden und_apply_unitary_, die undffsim.apply_unitary()dupliziertenffsim.linear_operator(). Rufen Sie stattdessen die Funktionen von ffsim auf oder, falls ffsim nicht installiert ist, direkt die Protokollmethode des Objekts:# before from qiskit_fermions.linalg import apply_unitary, linear_operator vec = apply_unitary(vec, gate, norb, nelec) linop = linear_operator(operator, norb, nelec) # after (with ffsim) vec = ffsim.apply_unitary(vec, gate, norb=norb, nelec=nelec) linop = ffsim.linear_operator(operator, norb=norb, nelec=nelec) # after (without ffsim) vec = gate._apply_unitary_(vec, norb, nelec, copy=True) linop = operator._linear_operator_(norb, nelec)Die Methoden selbst bleiben unverändert.
-
Die
qiskit_fermions.protocols.SupportsLinearOperatorProtokolle undqiskit_fermions.protocols.SupportsApplyUnitarywurden aus demselben Grund entfernt: Sie wiederholten Verträge, die in ffsim definiert sind. Verwenden Sie die eigenen Protokolle von ffsim, die eins zu eins nachgebildet wurden:qiskit_fermions.protocols.SupportsApplyUnitarywirdffsim.SupportsApplyUnitaryqiskit_fermions.protocols.SupportsLinearOperatorwirdffsim.SupportsLinearOperator
Die Protokoll methoden (
_apply_unitary_und_linear_operator_) bleiben unverändert, sodass die Objekte dieses Pakets, die diese implementiert haben, dies weiterhin tun; lediglich die lokale Neudefinition der Schnittstelle entfällt.SupportsApplyUnitaryPlacedbleibt bestehen, da es umffsim.SupportsApplyUnitaryeine Modusplatzierung erweitert wird und kein ffsim-Äquivalent hat. -
from_file()Löst nun eine abfangbare „ Python “-Ausnahme aus, wenn eine Datei nicht geparst werden kann, anstatt einen Rust-Panic weiterzugeben. Ein Pfad, der nicht geöffnet oder gelesen werden kann, löst eine Ausnahme ausOSError, während eine Datei, die das FCIDump-Format nicht einhält (fehlende Namelist im Header, fehlendesNORBoderNELECFeld oder ein fehlerhaftes FeldMS2), eine Ausnahme auslöstValueError. Ein FCIDump mit einem MO-Energiewert, der noch nicht unterstützt wird, löst ebenfalls einen Fehler ausValueError. -
Die Methode
group_weightswurde aus allen Operatorklassen und aus dem ProtokollOperatorTraitentfernt. Sie wird durch ersetztgroup_coeff_means(), eine freie Funktion imqiskit_fermions.operators.terms.groupingModul, deren Verhalten unverändert bleibt:# before weights = op.group_weights() # after from qiskit_fermions.operators.terms.grouping import group_coeff_means weights = group_coeff_means(op) -
Die Zuweisung eines Arrays
groups, dessen Länge von der Anzahl der Terme des Operators abweicht, löst nun einen Fehler aus,ValueErroranstatt stillschweigend akzeptiert zu werden. Die Zuweisung vonNonezum Löschen der Gruppenindizes bleibt davon unberührt. -
MapperFnEvolutionSynthesisvereinfacht den vom Operator zurückgegebenen Ausdruck nicht mehrmapper_fn. Durch die Vereinfachung werden die Pauli-Terme in eine kanonische Reihenfolge sortiert, und eine Produktformel fasst sie in der Reihenfolge zusammen, in der sie empfangen werden, sodass das bisherige Verhalten die vom Mapper gewählte Reihenfolge außer Acht ließ.Dadurch ändert sich die synthetisierte Schaltung für bestehende Pipelines: Die Anzahl der Gatter bleibt unverändert, aber die Reihenfolge, in der die Rotationen ausgegeben werden (und damit die Zwei-Qubit-Tiefe), kann variieren. Die approximierte Entwicklung bleibt unverändert.
Beachten Sie außerdem, dass die Reihenfolge der Terme, die ein Mapper erzeugt, nicht garantiert stabil zwischen den Durchläufen ist, da die Operatoren des Rust-Kerns die Reihenfolge, in der ihre Terme hinzugefügt wurden, nicht beibehalten. Um
simplify()das bisherige Verhalten wiederherzustellen und eine kanonische Reihenfolge festzulegen, umschließen Sie den Mapper mit dem neuen Element:MapperFnEvolutionSynthesis(simplify(jordan_wigner)) -
Die Funktionen zur doppelten Faktorisierung wurden aus
qiskit_fermions.linalg:double_factorized_t2,double_factorized_t2_alpha_beta,reconstruct_t2,reconstruct_t2_alpha_betaund entferntdouble_factorized_2body. Die Variantent2dienten dazu, zu bedienenUCJ.from_t_amplitudes, das nun in ffsim liegt, unddouble_factorized_2bodyhatten keinen Aufrufer. Verwenden Sie stattdessenffsim.linalg.double_factorized()ffsim.linalg.double_factorized_t2(), undffsim.linalg.double_factorized_t2_alpha_beta(); letzteres ist eine Obermenge der entfernten Zwei-Körper-Routine und bietet zusätzlich eine optimierte (optimize=True) Zerlegung. -
Für die Simulation wird nun ffsim benötigt. Der native Rust-FCI-Kernel (Full Configuration Interaction), der früher als Grundlage diente,
_linear_operator_wurde entfernt; die Methode wird nun dadurch implementiert, dass einFermionOperatorin ein umgewandelt undffsim.FermionOperatoran delegiert wirdffsim.linear_operator().Simulation ist das Kerngebiet von ffsim: Dieses Paket konzentriert sich auf fermionische Mapper sowie auf den mapperunabhängigen Schaltkreis und dessen Transpilation. Da ffsim auf PySCF, angewiesen ist, das Windows nicht unterstützt, ist die Simulation unter Windows folglich nicht verfügbar; der übrige Teil des Pakets (Erstellen von Operatoren, deren Zuordnung und das Transpiling der resultierenden Schaltkreise) ist auf allen Plattformen davon nicht betroffen. Windows-Benutzer, die eine Simulation durchführen müssen, können dies über das Windows-Subsystem für „ Linux “ tun.
Der Aufruf eines Simulations-Einstiegspunkts ohne installiertes ffsim löst nun einen Fehler aus
MissingOptionalLibraryError. -
Das
qiskit_fermions.linalg.fciModul wurde zusammen mit dem Kernel entfernt, einschließlich seinerFciLinearOperatorKlasse sowie der Funktionenoccupation_axis_maskslater_determinant_statevectorund. ffsim stellt entsprechendeffsim.addresses_to_strings()Entsprechungen bereit: bzwffsim.slater_determinant().. -
OrbitalRotationgreift nicht mehr auf einen „Generator-plus-Exponential“-Pfad zurück, wenn ffsim fehlt; es delegiert immer anffsim.apply_orbital_rotation(). Die Ergebnisse bleiben unverändert, wenn ffsim installiert ist. -
Das
UCCGatter besteht nun aus einem der UCCSD-Operatoren von ffsim, der als einziges Konstruktorargument dient. Die Spin-Variante und die Anzahl der Moden werden aus diesem Operator abgelesen, sodass das Argumentvariantund die AufzählungUCC.Variantwegfallen:# before ansatz = UCC("restricted", t1, t2) # after ansatz = UCC(ffsim.UCCSDOpRestrictedReal(t1=t1, t2=t2))Dementsprechend
UCC.to_parameterswurden,UCC.from_t_amplitudes``UCC.num_parameters, undUCC.from_parametersentfernt, ebenso wie diespinlessVariante und die Opt-in-Parametrisierungantisymmetric, für die es kein ffsim-Äquivalent gibt. Die Operatoren von ffsim verwendento_parameters()fürn_params(),from_parameters()und identische Konventionen. Um einen Ansatz außerhalb dieser Familie zu entwickeln (einen spinlosen oder einen antisymmetrisierten „ “), konstruieren Sie direkt einen Operator überEvolutionIhren eigenen Cluster-Operator, wodurch Sie zudem die Kontrolle über die Trotter-Reihenfolge seiner Terme erhalten.Der „wrapped“-Operator ist als verfügbar
UCC.uccsd_op, sodass seine Amplituden als undgate.uccsd_op.t1abrufbar sindgate.uccsd_op.t2; das Gatter spiegelt diese nicht mehr als eigene Attribute wider.UCC.cluster_operator()bleibt unverändert. Ein vom ffsim-Operator übertragenerfinal_orbital_rotationWert wird nun als abschließendes angehängtOrbitalRotation.Da „ffsim“ nun der Eingabetyp des Gatters ist und nicht mehr nur ein optionaler Beschleuniger,
UCCerfordert die Konstruktion eines die zusätzlicheffsimKlammer (pip install "qiskit-fermions[ffsim]") und löstMissingOptionalLibraryErrorohne diese einen Fehler aus. ffsim unterstützt Windows nicht, daher ist das Gate dort nicht verfügbar; verwenden Sie WSL. -
Das
UCJGatter besteht nun aus einem der UCJ-Operatoren von ffsim, der sein einziges Konstruktorargument darstellt. Die Spinvariante, die Anzahl der Raumorbitale und die Anzahl der Moden werden diesem Operator entnommen, sodass dasvariantArgument und die AufzählungUCJ.Variantwegfallen:# before ansatz = UCJ.from_t_amplitudes(nelec, t2, t1=t1, n_reps=2) ansatz = UCJ("balanced", diag_coulomb_mats, orbital_rotations) # after ansatz = UCJ(ffsim.UCJOpSpinBalanced.from_t_amplitudes(t2, t1=t1, n_reps=2)) ansatz = UCJ(ffsim.UCJOpSpinBalanced(diag_coulomb_mats, orbital_rotations))Dementsprechend
UCJ.to_parameterswurden,UCJ.from_t_amplitudes``UCJ.num_parameters, undUCJ.from_parametersentfernt: Die Operatoren von ffsim bieten fürto_parameters()from_t_amplitudes(),n_params(),from_parameters()und identische Konventionen und zusätzlich die komprimierte (optimize=True) Doppel-Faktorisierung sowiefrom_cisd_vec(), was dieses Paket nie implementiert hat. Der umschlossene Operator steht als zur VerfügungUCJ.ucj_op, sodass seine Tensoren als uswgate.ucj_op.diag_coulomb_mats. zugänglich sind; das Gate spiegelt sie nicht mehr als eigene Attribute wider.Da „ffsim“ nun der Eingabetyp des Gatters ist und nicht mehr nur ein optionaler Beschleuniger,
UCJerfordert die Konstruktion eines die zusätzlicheffsimKlammer (pip install "qiskit-fermions[ffsim]") und löstMissingOptionalLibraryErrorohne diese einen Fehler aus. ffsim unterstützt Windows nicht, daher ist das Gate dort nicht verfügbar; verwenden Sie WSL. -
Das „Entpicklen“ eines Operators, dessen „pickled“ Gruppenindizes nicht mehr für jeden Term die Zahl 1 aufweisen, löst nun einen Fehler aus,
ValueErroranstatt einen Operator zu erzeugen, dessen Gruppenindizes nicht mehr mit seinen Termen übereinstimmen. Dies gilt nur für manuell erstellte Payloads oder solche, die von einer inkompatiblen Version geschrieben wurden; von dieser Version geschriebene Pickles bleiben beim Hin- und Rücktransport unverändert.
Hinweise zur Aktualisierung der C-API
-
qf_fcidump_from_file()gibt nun ein zurück undQfExitCodeübergibt das geparste überQfFCIDumpeinen neuen Ausgabeparameter, was der bereits von den Mapper-Funktionen verwendeten Konvention entspricht:QfFCIDump *fcidump = NULL; QfExitCode exit = qf_fcidump_from_file("molecule.fcidump", &fcidump);Die Funktion kehrt zurück, wenn
QfExitCode_ValueErroreine Datei das FCIDump-Format nicht einhält (fehlende Header-Namensliste, fehlendesNORBoderNELECFeld, fehlerhaftesMS2Feld oder ein MO-Energiewert, der noch nicht unterstützt wird), wobei der Ausgabeparameter unverändert bleibt. Dies ersetzt die bisherige Signatur, die den Zeiger direkt zurückgab und keine Möglichkeit bot, einen Fehler zu melden (eine nicht parsbare Datei löste einen Rust-Panic über die FFI-Grenze hinweg aus, was ein undefiniertes Verhalten darstellt). -
qf_ferm_op_group_weightsund die entsprechenden Typen wurden in undqf_ferm_op_group_coeff_means()„Friends“ umbenannt. Ihr Verhalten hat sich nicht geändert. -
qf_ferm_op_set_groups()und die entsprechenden typbezogenen Varianten geben nun einQfExitCodeanstelle von zurückvoid. Wird ein Gruppenarray übergeben, dessen Länge von der Anzahl der Terme des Operators abweicht, wird ein Fehler zurückgegeben,QfExitCode_ValueErroranstatt dies stillschweigend zu akzeptieren; die Übergabe von zumNULLLöschen der Gruppenindizes bleibt davon unberührt.
Änderungen am Build-System
-
Die optionale
simulationAbhängigkeit wurde in umbenanntffsim, sodass zu wirdpip install "qiskit-fermions[simulation]"``pip install "qiskit-fermions[ffsim]". Der Zusatz bezeichnet die Abhängigkeit, die installiert wird, und nicht eine Funktion. Die Installationqiskit-fermions[all]bleibt davon unberührt. -
Die optionale
optimizationAbhängigkeit wurde in umbenanntpyomo, sodass zu wirdpip install "qiskit-fermions[optimization]"``pip install "qiskit-fermions[pyomo]". Der neue Name bezeichnet die Abhängigkeit, die installiert wird, und nicht eine Funktion, wie es der alte Name fälschlicherweise vermuten ließ: Pyomo ist eine Modellierungssprache, die zwar das gemischt-ganzzahlige Programm hinter undRelabelModeserstellt, diesesbuild_excitation_span_minimization_model()aber nicht lösen kann. Die Auswahl eines Solvers ist ein separater, bewusster Schritt (RelabelModesman durchläuft dessensolverArgumente, und dieses Paket schreibt nicht vor, welches gewählt werden soll), und die Benennung des Zusatzmoduls nach „Pyomo“ macht diese Grenze bereits bei der Installation deutlich. Die Installationqiskit-fermions[all]bleibt davon unberührt.
Fehlerkorrekturen
-
Der übermäßige Speicherverbrauch von
fermion_jordan_wigner()und vonqf_ferm_op_jordan_wigner()(und damit auch von, wennjordan_wigner()es auf ein angewendet wirdFermionOperator) wurde behoben. Der Mapper sammelte die abgebildeten Terme mithilfe einer Addition, die doppelte Pauli-Terme aneinanderreihte, anstatt sie zusammenzuführen, sodass die Zwischengröße mit der Anzahl der emittierten Pauli-Terme anstieg und nicht mit der Anzahl der unterschiedlichen Terme. Das Abbilden eines großen Hamilton-Operators könnte daher den verfügbaren Speicher erschöpfen, obwohl das vereinfachte Ergebnis um Größenordnungen kleiner war. Die Akkumulatoren werden nun kanonisiert, sobald sie um den Faktor ihrer zuvor zusammengeführten Größe angewachsen sind, wodurch der von ihnen belegte Speicherplatz in Abhängigkeit von dem Operator, den sie tatsächlich darstellen, begrenzt wird.Der Spitzen-Speicherbedarf steigt weiterhin mit der Anzahl der Worker-Threads: Die Terme werden an den jeweils freien Thread übergeben, anstatt nach den von ihnen erzeugten Pauli-Strings aufgeteilt zu werden, sodass jeder Akkumulator letztendlich etwa eine vollständige Kopie des abgebildeten Operators enthält. Was sich geändert hat, ist der Faktor, den jeder von ihnen trägt – früher war er proportional zur Anzahl der emittierten Pauli-Terme, jetzt zur Anzahl der unterschiedlichen Terme. Eine Verringerung der Thread-Anzahl über die
RAYON_NUM_THREADSUmgebungsvariable „rayon“ senkt daher den Spitzenwert in etwa proportional und ist die geeignete Maßnahme, wenn der Arbeitsspeicher knapp ist.Der abgebildete Operator bleibt unverändert: Bei der Kanonisierung werden lediglich doppelte Terme zusammengefasst, sodass das Ergebnis genau dieselbe Observable wie zuvor darstellt. Es ist jedoch nicht mehr garantiert, dass sie vollständig vereinfacht ist, und die Anzahl der darin enthaltenen Terme kann je nach Fadenzahl variieren. Rufen Sie (
simplify()qk_obs_canonicalizein C) auf, wenn Sie alle Duplikate zusammenführen möchten. -
Es wurde ein Fehler behoben, bei dem die Methode
Evolution.synthesisder Gatter, die mit Trotter transformiert werden, verworfenQDriftTrotterizationwurde und abgetastete Gatter ausgegeben wurden, die in nicht-unitäre Faktoren zerlegt werden konnten. Die gesampelten Gatter übernehmen nun die Synthesemethode des Gatters, das sie ersetzen, und sind entsprechend gekennzeichnetEvolution.atomic. -
Es wurde ein Fehler behoben, bei dem eine Permutation für den falschen Hamilton-Operator ermittelt
RelabelModeswurde, wenn die GatterEvolutioneines Schaltkreises bereits zerlegt worden waren. Ein reduziertFermionicEvolutionSynthesisjeden Faktor, den es ausgibt, auf die Trägermenge dieses Faktors, sodass der Operator des Faktors Modusindizes enthält, die lokal zum Gatter sind, während seine Position im Register durch die Qubit-Argumente des Knotens bestimmt wird. Bei der automatischen Optimierung wurde nur der Operator betrachtet, der diese lokalen Indizes zusammenfasste: Jeder eingeschränkte Zwei-Modus-Faktor wurde zum Anregungsfaktor,(0, 1)unabhängig davon, welche Moden er tatsächlich koppelte, und eine Fernkopplung fiel vollständig aus dem Modell heraus.Die dabei zurückgegebene Permutation war zwar gültig, jedoch für einen Hamilton-Operator optimiert, der nicht dem des Schaltkreises entsprach, und es trat kein Fehler auf, da lokale Indizes selbst gültige Modusindizes sind. Strecken, deren Entwicklung den Pass vollständig erreichte, blieben davon unberührt. Wenn Sie sich auf die Permutation einer zerlegten Schaltung verlassen haben, führen Sie den Durchlauf erneut durch: Möglicherweise wird nun eine andere (und bessere) Permutation zurückgegeben.
-
Ein Fehler behoben, bei dem die Zerlegung des Gates
Evolutionnie beendet wurde. Die Entwicklung eines einzelnen Operanden, der zur Zerlegung in einen identischen Einzelausdruck verwendet wurdeEvolution, sodass eine wiederholte Erweiterung zu keinem Ergebnis führte. Am deutlichsten zeigte sich dies darin, dass dadurch eininverse()ausgelöst wurdeRecursionError, da die Definition des Gatters rekursiv durchlaufen wurde.Ein von a emittierter Faktor
FermionicEvolutionSynthesiswird nun mit markiertEvolution.atomicund durch an Ort und Stelle belassen,decompose()anstatt erneut erweitert zu werden. Durch wiederholtesEvolutionZerlegen von erreicht man somit einen Fixpunkt. -
Es wurde ein Fehler behoben, bei dem nicht-unitäre Faktoren
decompose()erzeugt wurden, wenn die Funktion mehr als zweimal auf einen Operator mit Gruppen angewendet wurde. Jede Gruppe wurde Term für Term weiter unterteilt, doch ein einzelner Term ist im Allgemeinen nicht hermitesch, selbst wenn die Gruppe, zu der er gehört, hermitesch ist – ein anschauliches Beispiel hierfür sind die konjugierten Paare einesUCCClustergenerators. Die Exponentialfunktion eines solchen Faktors ist nicht unitär.Die „Fermion-zu-Qubit“-Stufe hat diese Faktoren mit einem
ValueErrorbezüglich komplexer Koeffizienten verworfen, doch die Zustandsvektor-Simulation hat sie ohne Einwände berücksichtigt und einen nicht normierten Zustand zurückgegeben. Da eine Gruppe nun atomar ist, findet die Aufspaltung, durch die sie entstanden ist, nicht mehr statt. -
Evolution.inverse()wird nun direkt implementiert und gibt ein zurück, dasEvolutiondenselben Operator für die negierte Zeit weiterentwickelt und die Methodesynthesisdes Gatters beibehält. Bisher durchlief die geerbte Implementierung die Definition des Gatters rekursiv und gab ein einfaches zurückGate, wobei sowohl der Operator als auch die Synthesemethode verworfen wurden.
Leistungsverbesserungen
-
Die numerische Konditionierung der Zustandsvektor-Simulation für
EvolutionundOrbitalRotationGatter wurde verbessert, indem die exakte Spur des Operators mit festem Sektor an die Matrix-Exponential-Routine von SciPy’s übergeben wurde. -
fermion_jordan_wigner()kopiert den übergebenen Operator nicht mehr. Die BindungPythonnahm ihr Argument als Wert entgegen, wodurch jeder Term-Puffer der Eingabe alleinFermionOperatorzum Zweck des Einlesens dupliziert wurde.
0.1.0
Präludium
Dies ist die erste Version von Qiskit Fermions, einer Erweiterung von Qiskit mit Werkzeugen für fermionische Systeme. Es bietet Operator-Datenstrukturen, ein Framework und eine Bibliothek zur Umwandlung dieser Operatoren in die Qubit-Form (Mapper) sowie ein Framework und eine Bibliothek zur Synthese der entsprechenden Quantenschaltungen. Entsprechend der Designphilosophie von Qiskit ist der Kern dieses Pakets in Rust geschrieben und wird über eigene Bindings sowohl für „ Python “ als auch für C bereitgestellt.