Skip to main content
IBM Quantum Platform

Qiskit SDK 2.1 notes de mise à jour


2.1.2

Prélude

Qiskit 2.1.2 est un petit patch qui corrige plusieurs bugs trouvés dans la série 2.1.

Corrections des erreurs

  • Dans Qiskit 2.1.0, la passe de transpiler a été ajoutée à l'étape du gestionnaire de passes prédéfinies lorsque VF2PostLayout transpiler a été ajouté à l'étape optimization du gestionnaire de passes prédéfinies lorsque optimization_level=3. Cependant, la sortie du passeur n'a jamais été appliquée au circuit. Cette version supprime le laissez-passer de l'étape optimization du gestionnaire de laissez-passer prédéfini afin de réduire les coûts d'exécution. Dans Qiskit 2.2.0, la passe fera partie de l'étape optimization et la sortie sera appliquée si la passe trouve une meilleure disposition.

  • Correction d'un problème dans la passe VF2Layout où, même avec un jeu de graines fixe, la sortie de la passe était potentiellement non déterministe, en particulier si le circuit d'entrée avait des qubits actifs qui ne contenaient que des opérations sur un seul qubit. Corrigé #14729

  • Correction d'un bogue dans PassManager.run() où la fonction callback n'était pas invoquée en cas d'utilisation de plusieurs circuits. Le rappel est désormais correctement déclenché pour chaque passe sur chaque circuit, y compris en cas d'exécution parallèle.

  • Les passes de transposition intégrées qui définissent la propriété final_layout gèrent désormais correctement la mise à jour de ce champ s'il a déjà été défini. On peut observer que la méthode TranspileLayout.routing_permutation renvoie maintenant une permutation correcte après avoir exécuté plus d'une passe qui fixe final_layout.

    Cela n'a pas eu d'incidence sur les appels normaux à transpile() ou generate_preset_pass_manager() utilisant les plugins intégrés de Qiskit; aucun pipeline construit sous cette forme ne tenterait de définir final_layout plus d'une fois.

  • Correction d'un bug dans Target.instruction_supported() où la vérification de l'ordre des qubits de l'instruction était ignorée lorsque la méthode était appelée avec les arguments operation_name et parameters qui correspondaient à une instruction existante.

  • Correction d'un problème de correction lors de l'exportation de circuits avec des instructions de retard utilisant les unités ps vers QASM3.

  • Correction d'un cas de figure dans l'affichage du QFT circuit. Auparavant, lorsque l'on appelait QFT.inverse() était appelé et que les attributs du circuit QFT étaient modifiés, le nom du QFT était affiché sous la forme "IQFT_dg". Ce n'était pas le cas, et il s'agit maintenant de "IQFT". Correction #14758.

  • Correction d'une fuite de mémoire dans la coordination de l'utilisation de qk_circuit_get_instruction et qk_circuit_instruction_clear.

  • Clarification du message d'erreur pour les versions spécifiées non valides en qpy.dump() afin qu'il soit plus facile d'agir.

  • Correction d'un problème avec la fonction generate_preset_pass_manager() qui ignorait à tort les données relatives aux contraintes de temps contenues dans un objet Target fourni lorsque l'argument backend n'était pas défini. Corrigé #14329

  • Correction d'un bug dans SparsePauliOp.simplify() où la méthode supprimait les termes de Pauli sur la base de la magnitude de leurs coefficients avant de combiner les doublons. Cela a entraîné un comportement incorrect dans deux cas de figure importants :

    1. Lorsque plusieurs termes de Pauli identiques avaient de petits coefficients qui étaient individuellement inférieurs au seuil de simplification mais dont la somme dépassait le seuil, ces termes ont été supprimés à tort.
    2. Lorsque plusieurs termes de Pauli identiques avaient des coefficients supérieurs au seuil mais dont la somme était proche de zéro, ils étaient incorrectement conservés.

    Voir #14194 pour plus de détails.


2.1.1

Prélude

Qiskit 2.1.1 est un petit patch qui corrige plusieurs bugs trouvés dans la série 2.1.

Corrections des erreurs

  • Correction d'un bug dans la vérification de l'égalité DAGOpNode où la comparaison de deux objets DAGOpNode contenant une instruction BoxOp instruction. Auparavant, l'attribut BoxOp.unit n'était pas pris en compte dans le cadre de la vérification de l'égalité, ce qui pouvait conduire à ce que deux nœuds inégaux soient considérés comme égaux.

  • Correction de l'avertissement de dépréciation pour Python 3.9 afin qu'il soit correctement identifié comme étant causé par du code utilisateur lors de l'importation de Qiskit. Auparavant, il n'était pas identifié comme étant causé par le code de l'utilisateur, ce qui signifiait que les filtres d'avertissement par défaut de Python n'affichaient pas l'avertissement à l'utilisateur.

  • Correction du comportement de l'argument max_trials pour VF2Layout lorsqu'il est défini à None ou à un nombre négatif. La passe a été documentée comme limitant la recherche à la taille du circuit ou de la cible si l'option est définie sur None, et comme acceptant des valeurs négatives pour spécifier une recherche non limitée. Cependant, dans 2.1.0, ce comportement a été modifié de manière incorrecte, de sorte que None effectue une recherche non bornée et que l'utilisation d'un nombre négatif entraîne une erreur. Ces oublis ont été corrigés de manière à ce que la passe se comporte comme prévu et soit cohérente avec les versions précédentes.

  • Correction d'un problème dans les plugins de synthèse de haut niveau MCXSynthesis1DirtyKG24 et MCXSynthesis2DirtyKG24 pour MCXGateoù les plugins ne considéraient pas les qubits auxiliaires propres disponibles comme des qubits auxiliaires sales disponibles. En particulier, le plugin MCXSynthesis2DirtyKG24 ne s'applique pas lorsqu'un qubit auxiliaire propre et un qubit auxiliaire sale sont disponibles.

  • Correction d'une régression de performance lors de la construction incrémentale de ParameterExpression en combinant un grand nombre de sous-expressions. Corrigé #14653


2.1.0

Prélude

La version de Qiskit v2.1 introduit plusieurs améliorations importantes dans des domaines clés tels que l'API C, les capacités du transpilateur et la facilité d'utilisation des circuits quantiques. En outre, elle comprend de nombreuses améliorations générales et corrections de bogues. Les principaux faits marquants sont les suivants :

  • Extensions de l'API C : S'appuyant sur le travail commencé dans la version précédente, Qiskit v2.1 ajoute le support pour la création et l'interaction avec des circuits quantiques via des fonctions API C, supportant l'ajout de portes standard, d'instructions standard et de portes unitaires. Cette version comprend également un ensemble de fonctions C permettant de construire et de manipuler un objet Target en préparation de la prise en charge d'un flux de travail de transpilation complet basé sur l'API C dans la prochaine version. De plus, QkComplex64 est désormais défini comme une structure, ce qui permet de représenter les nombres complexes sans tenir compte du compilateur lorsque l'on travaille avec l'API C de Qiskit. Le fichier d'en-tête de l'API C a également été mis à jour afin qu'il soit généralement compatible avec une utilisation native en C++.
  • Prise en charge de l'ensemble de base Clifford+T : Le transpiling des circuits pour une cible avec des portes Clifford+T est maintenant pris en charge dès le départ. Sous le capot, si l'ensemble de base est constitué uniquement de portes Clifford+T, Qiskit s'assure que les passes appropriées pour traiter ces portes sont ajoutées aux gestionnaires de passes prédéfinis. Il s'agit d'une première étape vers la prise en charge de la transpilation pour les backends tolérants aux pannes.
  • Améliorations apportées à BoxOp: Cette version ajoute la possibilité d'attacher des annotations personnalisées aux instructions BoxOp cette version ajoute la possibilité d'attacher des annotations personnalisées aux instructions, ce qui renforce le concept des déclarations en boîte de OpenQASM 3 dans Qiskit. Cela comprend également la sérialisation des annotations dans les formats QASM et QPY. En outre, la possibilité d'utiliser des durées d'étirement dans les boîtes a été ajoutée.
  • Python 3.9 dépréciation : Python 3.9 est déprécié à partir de Qiskit v2.1 et ne sera plus pris en charge dans Qiskit v2.3.

Pour plus de détails sur ce qui précède et bien d'autres choses encore, veuillez consulter les notes de version ci-dessous et visiter la documentation mise à jour.

Fonctionnalités de l'API C

  • L' API C de Qiskit ( qiskit.h ) permet désormais de construire et d'interagir avec les circuits quantiques. L'API C des circuits est centrée sur le type opaque QkCircuit qui représente le circuit. Le type QkCircuit permet de construire un circuit avec n'importe quel élément de circuit défini nativement dans le modèle de données interne de Qiskit, Rust, pour QuantumCircuit. Il s'agit actuellement des portes standard, Measure, Delay, Reset, Barrieret UnitaryGate. Les capacités de l'API C des circuits seront étendues dans les prochaines versions, à mesure que le modèle de données Qiskit sera ajouté de manière native au modèle de données interne de Rust, ce qui permettra de l'utiliser dans l'API C.

    Par exemple, vous pouvez utiliser l'API C pour construire un état GHZ de 1000 qubits :

    #include <qiskit.h>
    
    int main() {
        // Create an empty circuit with 1000 qubits and 1000 clbits
        QkCircuit *qc = qk_circuit_new(1000, 1000);
    
        // Add a Hadamard Gate on Qubit 0
        uint32_t one_qubit[1] = {0,};
        qk_circuit_gate(qc, QkGate_H, one_qubit, NULL); // The NULL pointer is for the parameter array.
                                                        // Since Hadamard doesn't have parameters it
                                                        // is never accessed.
    
        // Add the CX Gates:
        uint32_t qubits[2] = {0, 0};
        uint32_t num_qubits = qk_circuit_num_qubits(qc);
        for (int i = 1; i<num_qubits; i++) {
            qubits[1] = i;
            qk_circuit_gate(qc, QkGate_CX, qubits, NULL);
        }
    
        // Add the measurements:
        uint32_t num_clbits = qk_circuit_num_clbits(qc);
    
        for (uint32_t i = 0; i<num_clbits; i++) {
            qk_circuit_measure(qc, i, i);
        }
        qk_circuit_free(qc);
        return 0;
    }
  • L' API C de Qiskit ( qiskit.h ) prend désormais en charge la construction d'un fichier Target pour représenter une cible de transpilation. Par exemple :

    #include <qiskit.h>
    #include <math.h>
    
    int main() {
        // Create a Target with 3 qubits
        QkTarget *target = qk_target_new(3);
    
        // Create a Target Entry for a CX Gate
        QkTargetEntry *cx_entry = qk_target_entry_new(QkGate_CX);
        // Define properties for CX between qubits (0, 1) with a duration of 1.93e-9 sec and error rate 3.17e-10.
        uint32_t qargs[2] = {0, 1};
        qk_target_entry_add_property(cx_entry, qargs, 2, 1.93e-9, 3.17e-10);
        // Define properties for cx between qubits (1, 0) with a duration of 1.27e-9 sec and no error.
        uint32_t rev_qargs[2] = {1, 2};
        qk_target_entry_add_property(cx_entry, rev_qargs, 2, 1.27e-9, NAN);
        // Add the cx entry to the target.
        QkExitCode result_cx = qk_target_add_instruction(target, cx_entry);
        // Add global ideal Y gate entry to the target
        QkExitCode result_y = qk_target_add_instruction(target, qk_target_entry_new(QkGate_Y));
        // Create a Target entry for a Measurement with increasing duration and error as the qubit indices increase
        QkTargetEntry *measure = qk_target_entry_new_measure();
        for (uint32_t i = 0; i< qk_target_num_qubits(target); i++) {
            uint32_t q[1] = {i};
            qk_target_entry_add_property(measure, q, 1, 1e-6 * (i + 1), 1e-3 * (i + 1));
        }
        QkExitCode result_measure = qk_target_add_instruction(target, measure);
        return 0;
    }
    
  • Ajout d'un support pour l'interrogation des informations de version de Qiskit à partir de l'API C en utilisant les macros suivantes :

    • QISKIT_VERSION_MAJOR numéro de la version majeure : Contient le numéro de la version majeure.
    • QISKIT_VERSION_MINOR numéro de la version mineure : Contient le numéro de la version mineure.
    • QISKIT_VERSION_PATCH numéro de version du correctif : Contient le numéro de version du correctif.
    • QISKIT_VERSION : Contient une représentation numérique des informations relatives à la version, qui peut être utilisée pour des comparaisons.
    • QISKIT_VERSION_NUMERIC(M,m,p) : Une macro de type fonction qui renvoie la version " M.m.p " sous la forme d'une valeur numérique, qui peut être utilisée pour des comparaisons.

    Par exemple, pour vérifier si la version actuelle est au moins 2.1.0, vous pouvez utiliser :

    if (QISKIT_VERSION >= QISKIT_VERSION_NUMERIC(2, 1, 0)) {
        // Code for version 2.1.0 or later
    }
  • Activation de la compatibilité C++ pour l'API C. L'en-tête généré permet désormais d'appeler directement des objets et des fonctions à partir de C++. Par exemple, une observable de 100 qubits avec le terme XYZ sur les 3 premiers qubits peut être construite comme suit

    #include <iostream>
    #include <complex>
    #include <vector>
    #include <qiskit.h>
    
    int main() {
        uint32_t num_qubits = 100;
    
        // Use smart pointer with custom deleter to manage QkObs memory
        QkObs *obs = qk_obs_zero(num_qubits);
    
        // Construct the observable term
        std::complex<double> coeff_complex = 2.0;
        QkComplex64 coeff = qk_complex64_from_native(coeff_complex);
        std::vector<QkBitTerm> bit_terms = {QkBitTerm_X, QkBitTerm_Y, QkBitTerm_Z};
        std::vector<uint32_t> indices = {0, 1, 2};
    
        QkObsTerm term {
            .coeff      = coeff,
            .len        = bit_terms.size(),
            .bit_terms  = bit_terms.data(),
            .indices    = indices.data(),
            .num_qubits = num_qubits
        };
    
        qk_obs_add_term(obs.get(), &term);
    
        // Print observable properties
        std::cout << "num_qubits: " << qk_obs_num_qubits(obs) << "\n";
        std::cout << "num_terms: "  << qk_obs_num_terms(obs)  << "\n";
    
        qk_obs_free(obs);
        return 0;
    }

Caractéristiques des circuits

  • Ajout d'une fonction random_circuit_from_graph() qui génère un circuit aléatoire induisant le même graphe d'interaction que celui spécifié par interaction_graph.

    La probabilité de tirer au hasard une arête du graphe d'interaction en tant que porte à deux qubits peut être définie par l'utilisateur dans l'attribut de poids d'une arête dans le graphe d'interaction d'entrée. Si l'utilisateur ne définit pas de probabilité, chaque arête est dessinée uniformément. En d'autres termes, chaque porte à deux qubits représentée par une arête dans le graphe d'interaction a la même probabilité d'être ajoutée au circuit aléatoire. Si seul un sous-ensemble de probabilités d'arêtes est défini, ValueError sera affiché.

    Dans cet exemple, cp_map est une liste d'arêtes avec des poids arbitraires.

    from qiskit.circuit.random.utils import random_circuit_from_graph
    import rustworkx as rx
    pydi_graph = rx.PyDiGraph()
    n_q = 5
    cp_map = [(0, 1, 0.18), (1, 2, 0.15), (2, 3, 0.15), (3, 4, 0.22)]
    pydi_graph.extend_from_weighted_edge_list(cp_map)
    # cp_map can be passed in directly as interaction_graph
    qc = random_circuit_from_graph(interaction_graph = pydi_graph,
      min_2q_gate_per_edge = 1,
      max_operands = 2,
      measure = True,
      conditional = True,
      reset = True,
      seed = 0,
      insert_1q_oper = True,
      prob_conditional = 0.21,
      prob_reset = 0.1)
    qc.draw(output='mpl')
    _images/release_notes-1.png
  • Ajout d'une nouvelle QuantumCircuit méthode : QuantumCircuit.has_control_flow_op() pour vérifier si un objet QuantumCircuit contient des opérations de flux de contrôle.

  • Un nouveau module qiskit.circuit.annotation et un objet de principe Annotation ont été ajoutés.

    Les annotations sont un moyen d'étiqueter les instructions (pour l'instant seulement BoxOp) avec des données locales, personnalisées par l'utilisateur. Ces données sont destinées à être consommées par des passes de transposition personnalisées. Les annotations permettent d'attacher des données à des instructions spécifiques, plutôt que d'utiliser l'objet global-contexte PropertySet lors de la compilation.

    Tous les objets Annotation tous les objets ont un champ namespace . Cette clé sous forme de chaîne est utilisée pour les recherches, afin que les consommateurs puissent savoir s'ils gèrent une annotation particulière ou non. Il n'existe actuellement aucune méthode permettant d'interroger la sémantique abstraite d'une sous-classe Annotation mais ces méthodes devraient être développées à l'avenir.

    Pour une analyse complète des capacités et des cas d'utilisation, voir qiskit.circuit.annotation pour une discussion complète sur les capacités et les cas d'utilisation.

  • BoxOp (créées par QuantumCircuit.box()) peuvent désormais être annotées avec des instances Annotation personnalisées. L'égalité de deux boîtes dépend de l'égalité des annotations.

    Généralement, cela se fait en passant une liste d'annotations comme seul argument positionnel lors de l'utilisation de QuantumCircuit.box() sous la forme d'un gestionnaire de contexte :

    from qiskit.circuit import annotation, QuantumCircuit
    
    class MyAnnotation(annotation.Annotation):
        namespace = "my.annotation"
    
        def __eq__(self, other):
            return isinstance(other, MyAnnotation)
    
    qc = QuantumCircuit()
    with qc.box([MyAnnotation()]):
        pass
  • La méthode UnitaryGate.control() utilise désormais en interne qs_decomposition() au lieu de Isometry pour la décomposition utilisée pour définir l'élément contrôlé UnitaryGate. Cette modification réduit le nombre de CXGate utilisés dans le definition pour l'élément retourné ControlledGate d'environ 2x.

  • Amélioration de la synthèse d'une commande multiple U1Gateafin qu'elle ne croisse pas de manière exponentielle avec le nombre de contrôles.

  • L'attribut BoxOp.duration peut désormais être un expr.Expr de type Durationtout comme Delay.duration. Il s'agit également de soutenir Stretch pour la durée d'un BoxOp.

Fonctionnalités primitives

OpenQASM Caractéristiques

  • qasm3.dump() et qasm3.dumps() ont un nouvel argument annotation_handlers , qui est utilisé pour fournir des instances de annotation.OpenQASM3Serializer au processus d'exportation OpenQASM 3, qui peut sérialiser les objets personnalisés Annotation vers OpenQASM 3.

  • Lorsque qiskit_qasm3_import>=0.6.0 est installé, qasm3.load() et qasm3.loads() ont un nouvel argument annotation_handlers , qui est utilisé pour fournir des instances de annotation.OpenQASM3Serializer au processus d'importation de OpenQASM 3, qui peut désérialiser les objets personnalisés Annotation à partir de OpenQASM 3. Ce support est actuellement limité aux déclarations box , car c'est le seul endroit où Qiskit peut représenter les annotations dans son modèle de données.

Caractéristiques du QPY

  • Ajout d'un nouveau format QPY, version 15, qui prend en charge les nouveaux objets Annotation avec la prise en charge des sérialiseurs et désérialiseurs externes. Le format permet à ces sérialiseurs d'avoir un état, et des emplacements sûrs dans le format binaire sont alloués pour les objets d'état personnalisés et les représentations d'annotations personnalisées.

  • qpy.dump() et qpy.load() ont maintenant un argument optionnel annotation_factories , qui est utilisé pour fournir des fonctions de construction d'objets de type annotation.QPYSerializer pour gérer les Annotation sous-classes. Ceux-ci doivent être fournis par l'utilisateur, de la même manière que pour metadata_serializer, car en général, Qiskit ne peut pas connaître tous les objets possibles définis de l'extérieur Annotation définis à l'extérieur.

  • Ajout d'une nouvelle fonction get_qpy_version() au module qpy module. Cette fonction inspecte un fichier QPY et récupère la version du format QPY utilisée dans la charge utile. La version est renvoyée sous la forme d'un entier, qui peut être utilisé à des fins de journalisation ou de débogage. voir #14201.

Caractéristiques de l'information quantique

  • Une nouvelle classe, PauliLindbladMapest ajoutée. Il s'agit d'une paramétrisation basée sur Pauli d'un sous-ensemble de cartes linéaires d'opérateurs multi-qubits, utilisée dans des applications d'apprentissage du bruit. Cette classe devrait constituer l'épine dorsale d'algorithmes améliorés d'apprentissage du bruit et permettre un contrôle meilleur et plus efficace des modèles de bruit dans les futures versions de Qiskit.

  • Introduit le QubitSparsePauli et QubitSparsePauliList qui représentent les mêmes concepts que les classes Pauli et PauliList respectivement, mais qui ne stockent que les termes non identiques, d'une manière analogue à la classe SparseObservable. Ces classes sont principalement destinées à être utilisées avec le nouveau PauliLindbladMap.

Caractéristiques de la synthèse

  • Ajout d'un nouvel algorithme de synthèse pour HalfAdderGate qui ne nécessite pas de qubits auxiliaires et qui a un meilleur nombre de CX par rapport à adder_qft_d00():

  • Ajout de nouvelles décompositions pour MCXGate l'utilisation d'ancillae propres, ce qui améliore la profondeur et l'efficacité des circuits :

    Exemple d'utilisation :

    from qiskit.synthesis.multi_controlled import synth_mcx_1_clean_kg24
    
    n_ctrls = 10
    qc = synth_mcx_1_clean_kg24(n_ctrls)
    qc.draw()
  • La synthèse des portes multi-contrôlées a été améliorée pour réduire le nombre de portes synthétisées CZGate a été améliorée afin de réduire le nombre de portes synthétisées. Dans certains cas, la réduction peut atteindre 99 %. Pour ce faire, on s'est appuyé sur la synthèse améliorée autour du MCXGate avec une synthèse CZGate de la synthèse contrôlée.

  • Amélioration du plugin par défaut pour la synthèse d'objets AnnotatedOperation objets. Cette amélioration est particulièrement utile lors de la création et de la transposition de circuits contrôlés comportant des portes contrôlées. Par exemple :

    from qiskit.circuit import QuantumCircuit
    from qiskit.circuit.library import CXGate
    from qiskit.compiler import transpile
    
    inner = QuantumCircuit(5)
    inner.append(CXGate().control(3, annotated=True), [0, 1, 2, 3, 4])
    controlled_inner_gate = inner.to_gate().control(2, annotated=True)
    qc = QuantumCircuit(15)
    qc.append(controlled_inner_gate, [0, 1, 2, 3, 4, 5, 6])
    qct = transpile(qc, basis_gates=["cx", "u"])

    Ce code crée un circuit quantique qc qui contient un circuit quantique à 2 contrôles avec une porte CX à 3 contrôles. Grâce à cette amélioration, le nombre de portes CX dans le circuit transpilé est réduit de 378 à 30. Il convient de noter qu'en spécifiant annotated=True lors de la définition de la logique de contrôle, les portes contrôlées sont créées en tant qu'opérations annotées. Cela évite une synthèse trop rapide, permet au transpondeur de détecter que controlled_inner_gate est équivalent à une porte X à 6 contrôles, et de choisir la meilleure méthode de synthèse disponible pour les portes X à plusieurs contrôles, en particulier en utilisant les qubits ancilla disponibles.

  • La fonction adder_qft_d00()utilisée pour synthétiser ModularAdderGate et HalfAdderGate accepte désormais un paramètre supplémentaire annotated. Si True, la porte QFT inverse dans les additionneurs est mise en œuvre en tant qu'opérations annotées, ce qui permet au transpondeur d'appliquer des optimisations supplémentaires.

  • La décomposition quantique de Shannon (qs_decomposition()) comprend désormais une optimisation qui réduit le nombre de CXGate dans le cas où l'unité d'entrée est une unité contrôlée.

  • La fonction de synthèse synth_mcx_1_clean_b95() produit maintenant un circuit avec moins de portes CX.

  • La classe SolovayKitaevDecomposition dispose désormais d'arguments supplémentaires dans l'initialisateur, ce qui lui permet d'être directement construite à partir d'un ensemble de basis_gates et d'un depth pour les approximations de base.

  • Ajouté SolovayKitaevDecomposition.save_basic_approximations() pour enregistrer l'ensemble des approximations de base utilisées par la classe dans un format binaire. Cette modification, combinée aux nouveaux arguments de l'initialisateur, permet aux utilisateurs d'éviter l'utilisation explicite de generate_basic_approximations() et de s'appuyer uniquement sur SolovayKitaevDecomposition.

Fonctionnalités du transpilateur

  • La fonction generate_preset_pass_manager() génère maintenant un gestionnaire de passe spécial lorsque l'ensemble de base est constitué uniquement de portes Clifford+T. Formellement, un ensemble de bases Clifford+T doit contenir uniquement des portes Clifford, ainsi que soit TGate, TdgGateou les deux. La liste complète des portes de Clifford prises en charge peut être obtenue en utilisant la commande get_clifford_gate_names().

    Par exemple :

    from qiskit.circuit import QuantumCircuit
    from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
    from qiskit.quantum_info import get_clifford_gate_names
    
    basis_gates = get_clifford_gate_names() + ["t", "tdg"]
    pm = generate_preset_pass_manager(basis_gates=basis_gates)
    
    qc = QuantumCircuit(1)
    qc.rx(0.8, 0)
    qct = pm.run(qc)
    print(qct.count_ops())

    Il en résulterait avec :

    OrderedDict([('h', 10210), ('t', 4508), ('tdg', 4503), ('sdg', 943), ('s', 941)])

    Auparavant, le gestionnaire de passes généré ne pouvait pas traiter l'exemple ci-dessus car il ne pouvait pas décomposer les portes de rotation à un qubit en portes de Clifford+T UGate en portes de Clifford+T. Cependant, le nouveau gestionnaire de passe utilise la décomposition de Solovay-Kitaev pour approximer les portes de rotation à un qubit en utilisant les portes H, T et Tdg , et appelle la passe de transposition pour traduire les portes dans l'ensemble de base cible BasisTranslator pour traduire les portes dans l'ensemble de base cible. Le nouveau gestionnaire de passes comporte également d'autres modifications permettant une traduction plus efficace en portes Clifford+T.

    Il est important de noter que l'ensemble de portes de la base Clifford+T spécifiée doit être universel, sinon la transpilation risque d'échouer. Bien que l'ensemble de portes ["h", "t", "tdg"] ou même ["h", "t"] soit suffisant pour assurer l'universalité, il est recommandé d'ajouter d'autres portes de Clifford à l'ensemble si possible, faute de quoi la traduction risque d'être moins efficace. Par exemple, si la porte S n'est pas incluse, les portes S peuvent être décomposées en paires de portes T (c'est-à-dire que les portes de Clifford peuvent être décomposées en portes non-Clifford, ce qui n'est pas forcément le comportement souhaité).

    Voici un exemple un peu plus grand :

    from qiskit.circuit import QuantumCircuit
    from qiskit.circuit.library import QFTGate
    from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
    
    qc = QuantumCircuit(4)
    qc.append(QFTGate(4), [0, 1, 2, 3])
    
    basis_gates = ["cx", "s", "sdg", "h", "t", "tdg"]
    pm = generate_preset_pass_manager(basis_gates=basis_gates, optimization_level=2)
    
    qc = QuantumCircuit(4)
    qc.append(QFTGate(4), [0, 1, 2, 3])
    
    qct = pm.run(qc)
    print(qct.count_ops())

    Il en résulterait avec :

    OrderedDict([('h', 96510), ('tdg', 42396), ('t', 42389), ('s', 8240), ('sdg', 8235), ('cx', 12)])
  • Ajout d'un nouveau plugin de synthèse de haut niveau HalfAdderSynthesisR25 pour synthétiser un HalfAdderGate. Le nouveau plugin est basé sur adder_ripple_r25().

    L'article HalfAdderSynthesisDefault a également été mis à jour pour suivre la séquence suivante de synthétiseurs de demi-addition : "HalfAdder.ripple_r25" lorsqu'il y a 3\leq 3 qubits, "HalfAdder.ripple_c04" lorsqu'un qubit auxiliaire est disponible, et "HalfAdder.ripple_r25" dans tous les autres cas.

  • Ajout de plusieurs plugins de synthèse de haut niveau permettant de synthétiser des objets en forme d'étoile MCXGate:

    La classe MCXSynthesisDefault a également été mise à jour pour exécuter la séquence suivante de méthodes de synthèse MCX jusqu'à ce que la première réussisse : : "mcx.2_clean_kg24", "mcx.1_clean_kg24", "mcx.n_clean_m15", "mcx.n_dirty_i15"`, ``"mcx.2_dirty_kg24", "mcx.1_dirty_kg24", "mcx.1_clean_b95", "mcx.noaux_v24". Les méthodes sont ordonnées de manière à ce que les méthodes de meilleure qualité soient appliquées en premier.

  • VF2PostLayout a été ajouté à la fin de l'étape d'optimisation par défaut lors de l'utilisation du niveau d'optimisation 3.

  • Ajout d'une nouvelle passe d'optimisation OptimizeCliffordT qui fusionne les paires de portes T consécutives en portes S et les paires de portes Tdg consécutives en portes Sdg. Cette optimisation est particulièrement efficace pour réduire le nombre de T après la décomposition de Solovay-Kitaev, qui produit plusieurs portes T ou Tdg consécutives. Par exemple :

    from qiskit.circuit import QuantumCircuit
    from qiskit.transpiler.passes import SolovayKitaev, OptimizeCliffordT
    
    qc = QuantumCircuit(1)
    qc.rx(0.8, 0)
    
    # Run Solovay-Kitaev pass on qc
    transpiled = SolovayKitaev()(qc)
    print(transpiled.count_ops().get("t", 0) + transpiled.count_ops().get("tdg", 0))
    # Should print 12779
    
    # Run Clifford+T optimization
    optimized = OptimizeCliffordT()(transpiled)
    print(optimized.count_ops().get("t", 0) + optimized.count_ops().get("tdg", 0))
    # Should print 9011
  • Ajout de la passe ContextAwareDynamicalDecoupling qui met en œuvre un découplage dynamique tenant compte du contexte, basé sur des séquences de Walsh-Hadamard. Les séquences de retard insérées seront mutuellement orthogonales aux séquences sur les qubits voisins et tiendront compte des spectateurs de contrôle/cible des portes CX et ECR. Pour plus d'informations, voir arXiv:2403.06852 pour plus d'informations.

    Exemple :

    from qiskit.circuit.library import QFT
    from qiskit.transpiler import PassManager, CouplingMap
    from qiskit.transpiler.passes import ALAPScheduleAnalysis, ContextAwareDynamicalDecoupling
    from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
    from qiskit.providers.fake_provider import GenericBackendV2
    
    num_qubits = 10
    circuit = QFT(num_qubits)
    circuit.measure_all()
    
    target = GenericBackendV2(
        100,
        basis_gates=["id", "rz", "sx", "x", "ecr"],
        coupling_map=CouplingMap.from_grid(10, 10)
    ).target
    
    pm = generate_preset_pass_manager(optimization_level=2, target=target)
    dd = PassManager([
        ALAPScheduleAnalysis(target=target),
        ContextAwareDynamicalDecoupling(target=target),
    ])
    
    transpiled = pm.run(circuit)
    with_dd = dd.run(transpiled)
    
    with_dd.draw("mpl", idle_wires=False)
    _images/release_notes-2.png
  • Ajout des attributs suivants à la classe DAGCircuit pour permettre d'interroger le nombre de variables d'étirement : num_stretches, num_captured_stretches et num_declared_stretches.

  • Ajout d'un nouveau plugin de synthèse unitaire CliffordUnitarySynthesis qui tente de synthétiser une porte unitaire donnée en vérifiant si elle peut être représentée par un Clifford, auquel cas il renvoie un circuit qui implémente cette porte unitaire et n'est constitué que de portes de Clifford.

    Le plugin est invoqué par la passe UnitarySynthesis transpiler pass lorsque le paramètre method est fixé à "clifford".

    En outre, le paramètre plugin_config de UnitarySynthesis peut être utilisé pour transmettre les paramètres suivants spécifiques au plugin :

    • min_qubits : le nombre minimum de qubits à considérer (la valeur par défaut est 1).
    • max_qubits : le nombre maximum de qubits à considérer (la valeur par défaut est 3).

    Par exemple :

    import math
    
    from qiskit.circuit import QuantumCircuit
    from qiskit.circuit.library import UnitaryGate
    from qiskit.quantum_info import Operator
    from qiskit.transpiler.passes import UnitarySynthesis
    
    # clifford unitary over 2 qubits
    c2 = QuantumCircuit(2)
    c2.h(0)
    c2.rz(math.pi / 4, 1)
    c2.rz(math.pi / 4, 1)
    c2.sdg(1)
    uc2 = UnitaryGate(Operator(c2).data)
    
    # non-clifford unitary over 2 qubits
    n2 = QuantumCircuit(2)
    n2.h(0)
    n2.rz(math.pi / 4, 1)
    n2.sdg(1)
    un2 = UnitaryGate(Operator(n2).data)
    
    # quantum circuit with two unitary gates
    qc = QuantumCircuit(3)
    qc.append(uc2, [2, 1])
    qc.append(un2, [0, 2])
    
    transpiled = UnitarySynthesis(method="clifford")(qc)
    transpiled.draw("mpl")
    _images/release_notes-3.png

    L'exécution du code ci-dessus resynthétise la première porte unitaire en portes de Clifford, tandis que la deuxième porte reste inchangée.

    Si nous modifions l'exemple ci-dessus comme suit :

    config = {"min_qubits": 3}
    transpiled = UnitarySynthesis(method="clifford", plugin_config=config)(qc)

    les deux portes unitaires restent inchangées.

Fonctionnalités de visualisation

  • Introduction de styles personnalisés pour la fonction dag_drawer() fonction. Cela vous permet de passer un dictionnaire au paramètre style avec des attributs personnalisés qui modifient le style du DAG que la fonction renvoie. Par exemple :

    from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit
    from qiskit.converters import circuit_to_dag
    from qiskit.visualization import dag_drawer
    
    q = QuantumRegister(3, 'q')
    c = ClassicalRegister(3, 'c')
    circ = QuantumCircuit(q, c)
    circ.h(q[0])
    circ.cx(q[0], q[1])
    circ.measure(q[0], c[0])
    circ.rz(0.5, q[1]).c_if(c, 2)
    
    dag = circuit_to_dag(circ)
    
    style = {
        "inputnodecolor": "pink",
        "outputnodecolor": "lightblue",
        "opnodecolor": "red",
    }
    
    dag_drawer(dag, style=style)

Mise à niveau

  • La bibliothèque python-dateutil n'est plus une dépendance de Qiskit. Depuis que Qiskit v2.0, plus rien dans la bibliothèque n'utilisait le site python-dateutil et Qiskit ne dépendait plus de la bibliothèque. Cette version le supprime de la liste des dépendances, de sorte qu'il n'est pas automatiquement installé comme condition préalable à l'utilisation de Qiskit. Si vous comptiez sur Qiskit pour installer dateutil pour vous en tant que dépendance, vous devrez maintenant vous assurer que vous l'installez manuellement (ce qui est la meilleure pratique pour les dépendances directes).

  • sympy n'est plus nécessaire pour installer Qiskit. Après la migration vers un moteur symbolique basé sur Rust pour la classe ParameterExpression les utilisations de SymPy sont isolées à quelques utilitaires de visualisation, la passe de TemplateOptimization transpiler pass, ParameterExpression.sympify() (qui est explicitement pour l'interopérabilité SymPy ) et SparsePauliOp.simplify() en cas d'utilisation de coefficients paramétrés. Cette fonctionnalité n'étant pas la plus utilisée, SymPy est désormais traité comme une dépendance optionnelle et ces fonctions lèveront une MissingOptionalLibraryError si elles sont utilisées et que SymPy n'est pas installé.

  • La dépendance à l'égard de symengine , qui était utilisée pour la construction d'objets, a été supprimée ParameterExpression a été supprimée. Il a été remplacé par un moteur symbolique interne et n'est plus nécessaire pour les fonctionnalités de base de Qiskit. La seule exception est que symengine a été incorporé dans les formats QPY 10, 11 et 12, il est donc toujours nécessaire si vous désérialisez ces formats. La dépendance à l'égard de symengine pour qpy.load() a été rendue explicitement optionnelle dans 2.0.0, mais si vous comptiez auparavant sur l'installation par défaut de symengine pour cette fonctionnalité, vous devrez désormais l'installer manuellement pour charger la charge utile. Si vous utilisiez ParameterExpression.sympify() pour obtenir un objet expression symengine à partir d'un objet ParameterExpression vous obtiendrez désormais une expression sympy . Si vous avez besoin de l'utiliser avec symengine, vous pouvez utiliser symengine.sympify pour convertir l'expression sympy en une expression symengine.

Notes sur la mise à niveau des circuits

  • L'attribut definition de l'élément HalfAdderGate a été modifié pour utiliser en interne adder_ripple_r25() pour générer la définition de la porte pour un circuit plus efficace sans qubits auxiliaires. Si l'ancienne définition est souhaitée pour une raison quelconque, vous pouvez utiliser directement la fonction adder_qft_d00() qui générera un circuit équivalent à celui que l'on obtenait dans les versions précédentes definition dans les versions précédentes.

  • Le circuit renvoyé par la fonction excitation_preserving() et la classe ExcitationPreserving sont maintenant construits à l'aide d'un seul XXPlusYYGate. Il s'agit d'un changement par rapport aux versions précédentes qui utilisaient un RXXGate suivi d'un RYYGate. Cette nouvelle construction de circuit est équivalente mais utilise moins de portes qui préservent toutes l'excitation, ce qui est par définition plus simple.

  • Les definition de plusieurs portes standard ont été mis à jour selon les principes suivants :

    • Lorsqu'elle est disponible, une définition utilisant des portes de Clifford est préférée aux définitions qui incluent des portes non-Clifford.
    • Lorsqu'elle est disponible, une définition utilisant des portes Clifford+T est préférée à une définition utilisant une porte UGate.
    • L'utilisation de PhaseGate est préférée à U1Gate.
    • L'utilisation de UGate est préférée à `U2Gate et `U3Gate.

    L'invariant suivant reste valable : en développant récursivement les définitions des portes, toute porte peut être exprimée en fin de compte en utilisant uniquement la base ["cx", "u"] . Les définitions de toutes les portes standard sont toutes équivalentes, de sorte que la sémantique des portes ne change pas, mais la construction exacte du circuit retourné pour certaines portes n'est plus exactement la même. Cette modification était nécessaire pour prendre en charge la transpilation Clifford+T.

  • Qiskit utilise désormais sa propre bibliothèque d'expressions symboliques, basée sur Rust, pour implémenter les fonctions internes de ParameterExpression et Parameter. Comme il s'agit d'une nouvelle implémentation du moteur de mathématiques symboliques de base utilisé pour ParameterExpression il peut y avoir des différences mineures dans le comportement exact de certaines fonctionnalités. Il devrait toujours produire des résultats équivalents pour l'API documentée. Veuillez ouvrir un dossier si vous constatez des problèmes d'exactitude.

Notes de mise à niveau de l'API C

  • La façon dont les nombres complexes sont exposés dans l'API C de Qiskit a changé. Auparavant, QkComplex64 était un type dépendant du compilateur qui permettait de transmettre des types complexes natifs par pointeur à l'API de Qiskit (par exemple sous la forme double complex*). Bien que pratique, cette approche repose implicitement sur des hypothèses d'agencement de la mémoire qui ne sont pas strictement garanties.

    Qiskit v2.1 expose désormais QkComplex64 { double re; double im; } en tant que structure, pour s'assurer que l'agencement de la mémoire est toujours compatible et pour un support plus large du compilateur. Pour des raisons de commodité, les convertisseurs qk_complex64_from_native et qk_complex64_to_native , qui dépendent du compilateur, sont fournis, ce qui permet de convertir la structure en un nombre complexe natif. Notez qu'ils ne fonctionnent que sur les plates-formes supportant double complex ou pour les compilateurs MSVC utilisant _Dcomplex.

    Par exemple :

    #include <qiskit.h>
    #include <math.h>
    #include <stdio.h>
    #include <complex.h>
    
    int main(int argc, char *argv[]) {
        // platform-independent constructions:
        QkComplex64 coeff = {5.0, 3.0};
    
        // ... or using converter
        // double complex native = 5.0 + I * 3; // uses C11 standard, does not work on MSVC
        // QkComplex64 coeff = qk_complex64_from_native(&native);  // convert from native
    
        uint32_t num_qubits = 100;
        QkObs *obs = qk_obs_zero(num_qubits);
        QkBitTerm bit_terms[3] = {QkBitTerm_X, QkBitTerm_Y, QkBitTerm_Z};
        uint32_t indices[3] = {0, 1, 2};
        QkObsTerm term = {coeff, 3, bit_terms, indices, num_qubits};
        qk_obs_add_term(obs, &term);
        printf("num_qubits: %u\n", qk_obs_num_qubits(obs));
        printf("num_terms: %lu\n", qk_obs_num_terms(obs));
    
        qk_obs_free(obs);
        return 0;
    }

Notes de mise à niveau QPY

  • La version QPY par défaut émise par qpy.dump() a été remplacée par la dernière version 15 de QPY. Si vous avez besoin de générer une version plus ancienne pour une raison quelconque, vous pouvez utiliser le mot-clé version dans la commande qpy.dump() pour spécifier une version plus ancienne à générer.

Notes de mise à niveau de Synthesis

  • Le format de sérialisation des approximations de base dans les algorithmes Solovay-Kitaev est passé de .npy à un autre format binaire, basé sur Rust serde et bincode. Toutes les routines qui chargent des approximations de base (telles que generate_basic_approximations(), SolovayKitaevDecomposition.load_basic_approximations() ou l'initialisateur de SolovayKitaev) supportent toujours le chargement du format hérité. Cependant, tout nouveau fichier sera stocké dans le nouveau format. Si vous utilisez l'ancien format, rétrogradez Qiskit vers < 2.2 et stockez les fichiers nécessaires.

  • Les valeurs par défaut de SolovayKitaev (et les classes apparentées) sont passées à depth=12 et reps=5. Ceci est dû au fait que l'implémentation sous-jacente est maintenant en Rust, ce qui nous permet d'augmenter la précision par défaut, tout en restant significativement plus rapide que la version précédente Python.

Notes de mise à niveau du transpilateur

  • Les plugins de mise en page intégrés pour les gestionnaires de passage actuels ne contiendront plus leur composante principale (par exemple, une instance de "sabre") si aucune contrainte de couplage n'est fournie SabreLayout pour la scène "sabre" ) si aucune contrainte de couplage n'est fournie. Auparavant, les plugins construisaient des instances invalides de leurs passes de mise en page, en supposant qu'une logique distincte empêcherait les passes de s'exécuter et de soulever des exceptions.

    Cela ne devrait pas avoir d'effet significatif sur l'utilisation des gestionnaires de passes prédéfinis ou des plugins, puisqu'il n'était déjà jamais valable d'appeler les passes dans un état invalide.

Remarques concernant la dépréciation

  • La prise en charge de l'exécution de Qiskit avec Python 3.9 est obsolète et sera supprimée dans la version de Qiskit v2.3. La version 2.3.0 est la première version après que Python 3.9 soit en fin de vie et ne soit plus supporté [1]. Cela signifie qu'à partir de la version 2.3.0, vous devrez mettre à jour la version Python que vous utilisez vers Python 3.9 ou une version supérieure.

    [1] https://devguide.python.org/versions/

Circuits obsolètes

Corrections des erreurs

  • Correction d'un bug dans la fonction dag_drawer() et la méthode DAGCircuit.draw() où la définition de l'argument du mot-clé style=plain n'affichait pas les étiquettes de circuit pour les nœuds du DAG dans la visualisation.

  • Correction d'un bogue dans la méthode QuantumCircuit.assign_parameters() où les paramètres qui n'étaient pas utilisés dans le circuit et qui étaient passés sous forme de chaînes n'étaient pas ignorés lorsque l'argument strict=False était défini. Se référer au problème #13933 pour plus de détails.

  • Correction de cas limites dans la configuration de Makefile pour Windows, où la variable d'environnement prédéfinie OS ne correspondait pas à la sortie de la commande uname -s .

  • Fixe l'attribut name de l'attribut OrGatequi était incorrectement défini à la chaîne "and" au lieu de la valeur attendue "or" qui est maintenant renvoyée. Cette valeur incorrecte "and" était en conflit avec le AndGate.name et aurait pu conduire à plusieurs problèmes liés à l'utilisation de Orgate et à sa différenciation d'un AndGate.

  • Correction d'un bug dans la fonction qpy.load() qui ne parvenait pas à désérialiser les circuits dont les paramètres avaient été réaffectés à des paramètres portant le même nom. Correction de #13720, #13720, et #13720.

  • Correction de l'article GenericBackendV2 pour inclure désormais BoxOp comme un type d'instruction pris en charge dans l'instruction générée GenericBackendV2.target généré lorsque le mot-clé argument control_flow=True est défini dans le constructeur.

  • Lors de la synthèse d'une porte MCXGate avec 3 commandes, la fonction de synthèse synth_mcx_n_dirty_i15() nécessitait un qubit auxiliaire, produisant un circuit avec 5 qubits (3 de contrôle, 1 de cible et 1 auxiliaire). Cependant, l'algorithme de synthèse actuel n'utilise pas ce qubit auxiliaire. Ce comportement est maintenant corrigé : le circuit synthétisé est sur 4 qubits (3 de contrôle et 1 de cible), ce qui permet à la fonction de synthèse d'être appliquée dans un nombre légèrement plus important de cas.

  • Les QuantumCircuit.draw() et circuit_drawer() rendra maintenant les instructions BoxOp dans une QuantumCircuit dans la même tranche verticale si les portées verticales ne se chevauchent pas sont désormais rendues dans la même tranche verticale, dans la mesure du possible.

  • Correction de la méthode QuantumCircuit.draw() et la fonction circuit_drawer() en mode "mpl" afin d'insérer moins d'espaces inutiles à l'intérieur du bord gauche lorsque l'on dessine des instances dans une fenêtre BoxOp dans un QuantumCircuit.

Autres remarques

  • Ajout d'une nouvelle cible de dépendance optionnelle qpy-compat. Cette cible doit être utilisée si vous envisagez de charger des fichiers utilisant des formats QPY plus anciens qpy des fichiers utilisant les anciens formats QPY. La cible installe des exigences supplémentaires utilisées pour le chargement de fichiers QPY utilisant des versions de format < 13. If you are only using newer QPY format versions you do no need to install this. The qpy.dump() only generates QPY > =13. Ceci n'est nécessaire que pour le chargement de fichiers générés avec des versions plus anciennes (antérieures à 2.0.0 ) de Qiskit. Vous pouvez installer cette nouvelle variante optionnelle avec pip install qiskit[qpy-compat].

  • Les poids relatifs des composantes "basic" et "lookahead" des SabreSwap et SabreLayout ont été modifiés lorsque le suivi des ensembles étendus est actif (comme c'est toujours le cas en SabreLayoutet l'est par défaut dans SabreSwap). La composante heuristique relative à la distance entre les qubits dans une porte individuelle de la couche frontale ne s'affaiblit plus proportionnellement au nombre de portes dans la couche frontale; ce comportement était un choix historique, mais pour les circuits de grande taille, il a pour effet accidentel de faire en sorte que la couche frontale soit presque ignorée, ce qui est désastreux pour l'efficacité.

    Les améliorations de routage qui en résultent devraient être les plus perceptibles pour les circuits qui peuvent fréquemment être stratifiés en couches de plus de 20 portes parallèles à deux qubits.

Cette page a-t-elle été utile ?
Signaler un bogue, une coquille ou proposer du contenu sur GitHub.