Skip to main content
IBM Quantum Platform

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 Evolution im fermionischen Raum zerlegt wird, lässt sich nun über sein neues, ausschließlich aus Schlüsselwörtern bestehendes synthesis Argument konfigurieren, das dem Argument synthesis von Qiskits entspricht PauliEvolutionGate. Die verfügbaren Methoden befinden sich im neuen qiskit_fermions.circuit.library.synthesis Modul, das die FermionicEvolutionSynthesis Schnittstelle und deren Implementierung FermionicLieTrotter erster Ordnung bereitstellt.

    Dieser Schritt von Fermion zu Fermion ist optional: Ein -Gatter Evolution kann 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ät groups) 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 nicht EvolutionSynthesis möglich ist.

    Die Standardeinstellung bleibt unverändert: Wenn man synthesis auf belässt, wird None verwendet FermionicLieTrotter, wodurch genau die Zerlegung reproduziert wird, die zuvor Evolution durchgeführt hat, sodass bestehende Schaltungen identisch synthetisiert werden.

  • Die Stichprobengewichte von QDriftTrotterization können nun über das neue, ausschließlich als Schlüsselwort verwendete Argument weights übergeben werden, anstatt bei jedem Aufruf aus dem weiterentwickelten Operator abgeleitet zu werden. Wenn man den Wert auf ( None Standard) 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 stattdessen group_coeff_means() einmal mit ab, zusammen mit group_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 hjh_j der qDRIFT -Zerlegung H=∑jhjHjH = \sum_j h_j H_j ist, wobei das Vorzeichen eines Koeffizienten zu HjH_j 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 gamma Stichproben führt, die sich jedoch über weiterentwickeln gamma * t. Und da das Array die Terme (oder Gruppen) eines bestimmten Operators beschreibt, wird seine Länge anhand jedes Evolution Gatters überprüft, auf das es angewendet wird, und eine Schaltung, die mehr als ein solches Gatter enthält, wird abgelehnt; wird dieses Feld weights nicht gesetzt, wird eine solche Schaltung weiterhin unterstützt, da jedes Gatter dann seine eigene Länge ableitet.

  • FCIDump stellt nun die von ihm analysierten elektronischen Integrale bereit, auf die zuvor nur durch die Konvertierung der gesamten Datenstruktur in ein. zugegriffen werden konnte FermionOperator. 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(), und get_two_body_tril_ab() get_two_body_tril_bb(). Die Beta-Spin-Arrays liefern die Werte für None eine spinbeschränkte Datei; das neue is_unrestricted Attribut gibt Auskunft über alle drei gleichzeitig. Das neue Attribut constant gibt die konstante (Kernabstoßungs-)Energie an, oder – falls None die 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 -Gatters Evolution im fermionischen Raum hinzugefügt. Wenn jeder Faktor einmal FermionicLieTrotter angewendet wird, werden diese symmetrisch zusammengesetzt, um Fehlerterme niedrigerer Ordnung auszugleichen, und sein reps Argument 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, groups an 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 war order=2 , wurde ein Trotter-Fehler erreicht reps=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.

    FermionicLieTrotter ist das Element erster Ordnung dieser Familie und wird nun auch als solches implementiert, wodurch es zudem das Argument reps erhält, das ihm zuvor fehlte. Beide sind bei gleichem Wert austauschbar reps.

    Beachten Sie, dass eine höhere Ordnung Genauigkeit durch Tiefe gewährleistet: Eine k „order“-Formel liefert ungefähr mal 5**((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 Gate Evolution in 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 und UCC UCJ, die intern ihre eigenen Komponenten aufbauen. Dieser Durchlauf trifft die Entscheidung stattdessen einmalig für die gesamte Pipeline. Ein optionales Prädikat filter schrä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 eines UCJ.

    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=False lediglich die Methode auszuwählen und die Erweiterung einem anderen Tool zu überlassen, beispielsweise Qiskit Decompose; beachten Sie, dass ein Gatter, das nie erweitert wird, die „Fermion-zu-Qubit“-Phase vollständig erreicht, wo es abgebildet wird, ohne dass es jemals Evolution.synthesis gelesen wird.

  • Das Modul qiskit_fermions.operators.terms.grouping behandelt 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 search

    Es 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(), und edge_vertex_jordan_wigner() transfer_vertex_jordan_wigner().

  • jordan_wigner() Es werden nun alle vier Operatortypen berücksichtigt und nicht mehr nur FermionOperator, 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 einem TypeError.

  • Die Methode is_hermitian() ist nun Teil des Protokolls OperatorTrait . Da jede Operatorklasse diese Funktion bereits bereitstellt, kann sie nun für jeden Wert vom Typ aufgerufen werden und nicht mehr OperatorTrait nur 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 True Ergebnis ist immer zuverlässig, während ein False Ergebnis für Operatortypen, deren Normalform keine echte kanonische Form ist, konservativ ist. Ein Beispiel hierfür finden Sie is_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 MapperFnEvolutionSynthesis bei 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 Eintrag groups an 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))
  • QDriftTrotterization Zeichnet nun auf, wie viele Ziehungen der Modus filter_trivial verworfen hat. Wenn mindestens ein Evolution Gatter tatsächlich gefiltert wurde, enthielt die zurückgegebene Schaltung die Überträge metadata filter_trivial.discarded und filter_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().

  • Evolution kann nun für jeden Operatortyp dieses Pakets simuliert werden, nicht nur für FermionOperator. Ein Operator anderer Art wird vor der Simulation über sein fermionisches Bild (das Protokoll SupportsFermionOperator ) umgewandelt, sodass die Entwicklung von MajoranaOperator, EdgeVertexOperator oder nicht TransferVertexOperator mehr zu führt NotImplementedError.

  • FermionOperator wird nun ffsim.SupportsTrace über eine neue _trace_() Methode implementiert, sodass die Spur eines Operators auf einem festen Sektor (norb, nelec) berechnet werden ffsim.trace() kann. Das sind die Voraussetzungen auf scipy.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 Modenblocks QfFermionOperator beibehält. Es ergänzt die bestehende Funktion qf_ferm_op_conserves_particle_number(), die lediglich die Gesamtsumme überprüft. Bei einer spin-orbitalen Anordnung von norb Raumorbitalen {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 NULL mit einer Blockanzahl von 0 behandelt alle Modi als einen einzigen Block, was dem Aufruf von entspricht qf_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() und qf_ferm_op_get_support(), sowie die Entsprechungen qf_transfer_op qf_maj_op, qf_edge_op und.

    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_support auf, um die Größe des Ausgabepuffers festzulegen, und übergeben Sie diesen Puffer anschließend an get_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_inplace und mul_inplace, zum Beispiel qf_ferm_op_add_inplace() qf_ferm_op_scaled_add_inplace() und qf_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 groups auf zurück NULL, genau wie es auch tut qf_ferm_op_add() . mul_inplace Es 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, QfEdgeVertexOperator und QfTransferVertexOperator, die jeweils über einen Funktionsumfang verfügen, der dem der bestehenden Operator-Strukturen entspricht.

    Beide Operatoren speichern zwei parallele Index-Arrays, und left_indices right_indices, anstelle des einzelnen Arrays modes , 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 Argument num_indices entgegen, 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(), und qf_transfer_vertex_to_edge_vertex().

  • Zur scaled_add C-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() und qf_transfer_op_scaled_add(). Jede gibt zurück left + 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 Funktion simplify auf, um gleichartige Terme zusammenzufassen.

  • QfFCIDump stellt nun die von ihm analysierten elektronischen Integrale bereit, auf die zuvor nur durch die Konvertierung der gesamten Datenstruktur in ein. zugegriffen werden konnte QfFermionOperator. Die neuen Zugriffsmethoden qf_fcidump_get_one_body_tril_a(), qf_fcidump_get_one_body_tril_b(), qf_fcidump_get_two_body_tril_aa(), und qf_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 QfFCIDump wird. Schütze die drei Beta-Spin-Getter mit dem neuen qf_fcidump_is_unrestricted()und qf_fcidump_constant() mit dem neuen qf_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 aufgebaut qf_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ügt qf_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 Suche qf_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() und qf_transfer_op_jordan_wigner().

Python Hinweise zum API-Upgrade

  • Die Funktionen qiskit_fermions.linalg.linear_operator und qiskit_fermions.linalg.apply_unitary wurden entfernt. Es handelte sich um dünne Wrapper um die _linear_operator_ Protokollmethoden und _apply_unitary_ , die und ffsim.apply_unitary() duplizierten ffsim.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.SupportsLinearOperator Protokolle und qiskit_fermions.protocols.SupportsApplyUnitary wurden 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:

    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. SupportsApplyUnitaryPlaced bleibt bestehen, da es um ffsim.SupportsApplyUnitary eine 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 aus OSError, während eine Datei, die das FCIDump-Format nicht einhält (fehlende Namelist im Header, fehlendes NORB oder NELEC Feld oder ein fehlerhaftes Feld MS2 ), eine Ausnahme auslöst ValueError. Ein FCIDump mit einem MO-Energiewert, der noch nicht unterstützt wird, löst ebenfalls einen Fehler aus ValueError.

  • Die Methode group_weights wurde aus allen Operatorklassen und aus dem Protokoll OperatorTrait entfernt. Sie wird durch ersetzt group_coeff_means(), eine freie Funktion im qiskit_fermions.operators.terms.grouping Modul, 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, ValueError anstatt stillschweigend akzeptiert zu werden. Die Zuweisung von None zum Löschen der Gruppenindizes bleibt davon unberührt.

  • MapperFnEvolutionSynthesis vereinfacht den vom Operator zurückgegebenen Ausdruck nicht mehr mapper_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_beta und entfernt double_factorized_2body. Die Varianten t2 dienten dazu, zu bedienen UCJ.from_t_amplitudes, das nun in ffsim liegt, und double_factorized_2body hatten keinen Aufrufer. Verwenden Sie stattdessen ffsim.linalg.double_factorized() ffsim.linalg.double_factorized_t2(), und ffsim.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 ein FermionOperator in ein umgewandelt und ffsim.FermionOperator an delegiert wird ffsim.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.fci Modul wurde zusammen mit dem Kernel entfernt, einschließlich seiner FciLinearOperator Klasse sowie der Funktionen occupation_axis_mask slater_determinant_statevector und. ffsim stellt entsprechende ffsim.addresses_to_strings() Entsprechungen bereit: bzw ffsim.slater_determinant() ..

  • OrbitalRotation greift nicht mehr auf einen „Generator-plus-Exponential“-Pfad zurück, wenn ffsim fehlt; es delegiert immer an ffsim.apply_orbital_rotation(). Die Ergebnisse bleiben unverändert, wenn ffsim installiert ist.

  • Das UCC Gatter 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 Argument variant und die Aufzählung UCC.Variant wegfallen:

    # before
    ansatz = UCC("restricted", t1, t2)
    
    # after
    ansatz = UCC(ffsim.UCCSDOpRestrictedReal(t1=t1, t2=t2))

    Dementsprechend UCC.to_parameters wurden, UCC.from_t_amplitudes``UCC.num_parameters, und UCC.from_parameters entfernt, ebenso wie die spinless Variante und die Opt-in-Parametrisierung antisymmetric , für die es kein ffsim-Äquivalent gibt. Die Operatoren von ffsim verwenden to_parameters() für n_params(), from_parameters() und identische Konventionen. Um einen Ansatz außerhalb dieser Familie zu entwickeln (einen spinlosen oder einen antisymmetrisierten „ t2t_2 “), konstruieren Sie direkt einen Operator über Evolution Ihren 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 und gate.uccsd_op.t1 abrufbar sind gate.uccsd_op.t2; das Gatter spiegelt diese nicht mehr als eigene Attribute wider. UCC.cluster_operator() bleibt unverändert. Ein vom ffsim-Operator übertragener final_orbital_rotation Wert wird nun als abschließendes angehängt OrbitalRotation.

    Da „ffsim“ nun der Eingabetyp des Gatters ist und nicht mehr nur ein optionaler Beschleuniger, UCC erfordert die Konstruktion eines die zusätzliche ffsim Klammer (pip install "qiskit-fermions[ffsim]") und löst MissingOptionalLibraryError ohne diese einen Fehler aus. ffsim unterstützt Windows nicht, daher ist das Gate dort nicht verfügbar; verwenden Sie WSL.

  • Das UCJ Gatter 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 das variant Argument und die Aufzählung UCJ.Variant wegfallen:

    # 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_parameters wurden, UCJ.from_t_amplitudes``UCJ.num_parameters, und UCJ.from_parameters entfernt: Die Operatoren von ffsim bieten für to_parameters() from_t_amplitudes(), n_params(), from_parameters() und identische Konventionen und zusätzlich die komprimierte (optimize=True) Doppel-Faktorisierung sowie from_cisd_vec(), was dieses Paket nie implementiert hat. Der umschlossene Operator steht als zur Verfügung UCJ.ucj_op, sodass seine Tensoren als usw gate.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, UCJ erfordert die Konstruktion eines die zusätzliche ffsim Klammer (pip install "qiskit-fermions[ffsim]") und löst MissingOptionalLibraryError ohne 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, ValueError anstatt 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 und QfExitCode übergibt das geparste über QfFCIDump einen 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_ValueError eine Datei das FCIDump-Format nicht einhält (fehlende Header-Namensliste, fehlendes NORB oder NELEC Feld, fehlerhaftes MS2 Feld 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_weights und die entsprechenden Typen wurden in und qf_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 ein QfExitCode anstelle von zurück void. Wird ein Gruppenarray übergeben, dessen Länge von der Anzahl der Terme des Operators abweicht, wird ein Fehler zurückgegeben, QfExitCode_ValueError anstatt dies stillschweigend zu akzeptieren; die Übergabe von zum NULL Löschen der Gruppenindizes bleibt davon unberührt.

Änderungen am Build-System

  • Die optionale simulation Abhängigkeit wurde in umbenannt ffsim, sodass zu wird pip install "qiskit-fermions[simulation]"``pip install "qiskit-fermions[ffsim]" . Der Zusatz bezeichnet die Abhängigkeit, die installiert wird, und nicht eine Funktion. Die Installation qiskit-fermions[all] bleibt davon unberührt.

  • Die optionale optimization Abhängigkeit wurde in umbenannt pyomo, sodass zu wird pip 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 und RelabelModes erstellt, dieses build_excitation_span_minimization_model() aber nicht lösen kann. Die Auswahl eines Solvers ist ein separater, bewusster Schritt (RelabelModes man durchläuft dessen solver Argumente, 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 Installation qiskit-fermions[all] bleibt davon unberührt.

Fehlerkorrekturen

  • Der übermäßige Speicherverbrauch von fermion_jordan_wigner() und von qf_ferm_op_jordan_wigner() (und damit auch von, wenn jordan_wigner() es auf ein angewendet wird FermionOperator) 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_THREADS Umgebungsvariable „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_canonicalize in C) auf, wenn Sie alle Duplikate zusammenführen möchten.

  • Es wurde ein Fehler behoben, bei dem die Methode Evolution.synthesis der Gatter, die mit Trotter transformiert werden, verworfen QDriftTrotterization wurde 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 gekennzeichnet Evolution.atomic.

  • Es wurde ein Fehler behoben, bei dem eine Permutation für den falschen Hamilton-Operator ermittelt RelabelModes wurde, wenn die Gatter Evolution eines Schaltkreises bereits zerlegt worden waren. Ein reduziert FermionicEvolutionSynthesis jeden 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 Evolution nie beendet wurde. Die Entwicklung eines einzelnen Operanden, der zur Zerlegung in einen identischen Einzelausdruck verwendet wurde Evolution, sodass eine wiederholte Erweiterung zu keinem Ergebnis führte. Am deutlichsten zeigte sich dies darin, dass dadurch ein inverse() ausgelöst wurde RecursionError, da die Definition des Gatters rekursiv durchlaufen wurde.

    Ein von a emittierter Faktor FermionicEvolutionSynthesis wird nun mit markiert Evolution.atomic und durch an Ort und Stelle belassen, decompose() anstatt erneut erweitert zu werden. Durch wiederholtes Evolution Zerlegen 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 eines UCC Clustergenerators. Die Exponentialfunktion eines solchen Faktors ist nicht unitär.

    Die „Fermion-zu-Qubit“-Stufe hat diese Faktoren mit einem ValueError bezü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, das Evolution denselben Operator für die negierte Zeit weiterentwickelt und die Methode synthesis des Gatters beibehält. Bisher durchlief die geerbte Implementierung die Definition des Gatters rekursiv und gab ein einfaches zurück Gate, wobei sowohl der Operator als auch die Synthesemethode verworfen wurden.

Leistungsverbesserungen

  • Die numerische Konditionierung der Zustandsvektor-Simulation für Evolution und OrbitalRotation Gatter 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 Bindung Python nahm ihr Argument als Wert entgegen, wodurch jeder Term-Puffer der Eingabe allein FermionOperator zum 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.

War diese Seite hilfreich?
Melden Sie auf GitHub einen Fehler, einen Tippfehler oder fordern Sie Inhalte an.