Skip to main content
IBM Quantum Platform

Qiskit SDK 1.3 notes de mise à jour


1.3.3

Prélude

Qiskit 1.3.3 est une version mineure de correction de bugs pour la série 1.3.

Corrections des erreurs

  • Correction d'un bug où les étiquettes des barrières étaient mal positionnées lors de l'utilisation du paramètre reverse_bits = True dans la méthode QuantumCircuit.draw() méthode. Ce bogue entraînait un désalignement des étiquettes sur les opérations de barrière, ce qui pouvait créer une certaine confusion dans les visualisations de circuits. Correction #13609.

  • Application d'un petit facteur de régularisation contre les matrices hermitiennes mal conditionnées dans les représentations de super-opérateurs.

  • Les comparaisons d'instructions Delay y compris à l'intérieur des circuits, exigent désormais que les unités et la valeur de la durée soient égales. Corrige #13812.

  • Correction d'un bug dans le CommutationChecker qui pouvait échouer lors de la vérification de la relation de commutation d'une rotation de Pauli à deux qubits avec une porte qui n'est pas dans le cache de commutation. Par exemple :

    import numpy as np
    from qiskit.circuit.library import RXXGate, RGate
    from qiskit.circuit.commutation_library import SessionCommutationChecker as scc
    
    res = scc.commute(RGate(2, 2), [1], [], RXXGate(np.pi / 2), [0, 1], [])

    Ce problème est désormais résolu et la relation de commutation est correctement calculée. Correction #13742.

  • Correction d'un bug où QuantumCircuit.qubit_stop_time() et QuantumCircuit.qubit_duration() renvoyait un temps (durée) incorrect. Le problème a été déclenché lorsque certains qubits ont des instructions alors que d'autres qubits sont inactifs. Corrige #8729.

  • Correction d'un bug dans la passe RemoveIdentityEquivalent où les portes proches de l'identité jusqu'à une phase globale étaient supprimées du circuit, mais la phase globale du circuit n'était pas mise à jour. En particulier, RemoveIdentityEquivalent supprime désormais les portes non paramétrées GlobalPhaseGate non paramétrés. Corrige #13778.

  • Correction d'un bug dans random_clifford() qui l'empêchait d'échantillonner le groupe de Clifford complet. Corrige #13606.

  • Lorsque SabreLayout est utilisé pour effectuer simultanément la mise en page et le routage (comme c'est le cas pour les options par défaut de transpile() et generate_preset_pass_manager()) sur une page Target ou CouplingMap avec une connectivité disjointe, et que le circuit d'entrée s'inscrit dans un seul composant de la carte de couplage, la permutation de routage sera désormais suivie correctement.

    Auparavant, les qubits de la carte de couplage qui n'étaient pas connectés, même indirectement, à un qubit utilisé par le circuit acheminé n'étaient pas inclus dans la permutation de routage finale. Cela peut entraîner des comportements surprenants à une grande distance du point de défaillance, même si la compilation semble avoir réussi, comme des appels à la fonction TranspileLayout.final_index_layout() qui soulèvent des KeyError.

    Ce bogue n'affectait pas les backends entièrement connectés, comme c'est le cas pour la plupart d'entre eux. Corrige #13732.


1.3.2

Prélude

Qiskit 1.3.2 est une version mineure de correction de bugs pour la série 1.3.

Notes de mise à niveau de Synthesis

  • Les plugins de synthèse de haut niveau pour LinearFunction ne soulèvent plus d'erreur lorsqu'un objet autre que LinearFunction est transmis à la méthode run . Au lieu de cela, ils renvoient désormais None, ce qui est cohérent avec les autres plugins. Si vous vous attendiez à ce que cette erreur soit levée, vous pouvez effectuer manuellement une vérification de l'instance.

Corrections des erreurs

  • Auparavant, le CommutationChecker mettait en cache les relations de commutation de Instructionavec float-only params comme clé pour interroger la relation. Cela pourrait conduire à des résultats incorrects si la définition de l'instruction dépendait d'informations supplémentaires au-delà de l'attribut params comme, par exemple, dans le cas de PauliEvolutionGate. Ce comportement est maintenant corrigé, et le vérificateur de commutations ne met en cache les commutations que pour les portes standard natives de Qiskit. Pour les portes personnalisées, ce changement peut entraîner un coût en termes de performances; cependant, il garantit des résultats corrects en évitant la mise en cache non sécurisée.

  • Correction d'un bogue dans la fonction CommutationCheckeroù la vérification des relations de commutation d'une instruction avec des valeurs non numériques dans l'attribut params (comme dans le cas de PauliGate) pouvait provoquer une erreur. Correction #13570.

  • Les CommutationChecker n'a pas traité correctement les commutations de CRXGate, CRYGate et CRZGate pour les angles de rotation de la forme (4k+2)π(4k + 2)\pi, avec kZk \in \mathbb Z. Dans ces cas, on supposait à tort que ces portes commutaient avec n'importe quelle porte. Ce comportement est désormais corrigé, et ces portes ne commuent correctement avec n'importe quelle porte que lorsque l'angle de rotation est un multiple de 4π4\pi.

  • Correction d'un bogue à cause duquel les fonctions suivantes de la bibliothèque des circuits produisaient des erreurs lorsqu'elles étaient appelées avec num_qubits=1: efficient_su2(), real_amplitudes(), excitation_preserving() et pauli_two_design() (pour un seul qubit, ces circuits ne contiennent pas de portes à 2 qubits). Correction #13480.

  • Correction d'un bogue où toute instruction nommée "mcmt" était incorrectement transmise à la routine de synthèse de haut niveau pour a MCMTGatece qui entraînait un échec ou un résultat invalide. Ce problème peut se produire, par exemple, lors de la manipulation du circuit MCMT nommé "mcmt", et en le convertissant implicitement en instruction (par exemple, en l'ajoutant à un autre circuit ). Correction #13563.

  • Correction d'un bogue où la synthèse par défaut de la formule de produit pour PauliEvolutionGate ne gérait pas correctement les termes d'identité dans l'opérateur. Le terme d'identité totale devrait introduire une phase globale égale à -evolution_time, mais il est décalé d'un facteur 2 et pourrait se briser pour des temps paramétrés. Correction #13625. Correction #13675. Correction #13644.

  • Correction d'une incohérence dans le circuit généré par la synthèse de l'évolution de Pauli à l'aide de SuzukiTrotter ou LieTrotter (méthode par défaut). Pour les temps d'évolution paramétrés, les circuits résultants contenaient des paramètres avec une partie complexe erronée de zéro, ce qui affectait la sortie de ParameterExpression.sympify(). La sortie ne contient plus que des valeurs réelles. Correction #13642.

  • Correction d'un bug qui faisait que PauliList.insert() avec qubit=True produisait un attribut de phase de forme incorrecte lorsque l'objet original était de longueur 1. Correction #13623.

  • Correction d'un bogue dans qasm3.Exporter qui provoquait le plantage de l'exportateur lors de la manipulation d'une porte unitaire en raison d'un traitement incorrect de son champ params . Correction #13362.

  • Correction d'un bug dans la méthode Target.instruction_supported() où les cibles avec self.num_qubits==None renvoyaient toujours False indépendamment de l'ensemble de base pris en charge.

  • Correction d'un bug dans la passe de UnitarySynthesis où les blocs de UnitaryGatesur 3 qubits ou plus n'étaient pas synthétisés correctement. Cela a conduit, par exemple, à l'écrasement du circuit par le dernier bloc traité ou à des paniques internes lorsque des mesures étaient effectuées après un tel bloc. Correction #13586.

  • Correction d'un bug dans la passe de transposition UnitarySynthesis où les portes non-2-qubit étaient incluses dans la base de 2 qubits disponible, ce qui provoquait une panique sur TwoQubitWeylDecomposition en raison de la non-concordance des dimensions.

  • Correction d'un bogue où l'initialisation de SparsePauliOp avec un grand nombre de termes de Pauli-Y (typiquement 100\geq 100 ) et sans coeffs explicite donnait un coefficient proche de 1 mais avec une erreur en virgule flottante. Le coefficient est maintenant correctement de 1 par défaut. Correction #13522.


1.3.1

Prélude

Qiskit 1.3.1 est une version mineure de correction de bugs pour la série 1.3.

Notes sur la mise à niveau des circuits

  • La méthode de contrôle générique des portes évite désormais d'essayer de traduire les portes en une base prise en charge lorsque la porte est déjà prise en charge. Cela peut modifier légèrement la synthèse de la porte contrôlée, mais ne devrait pas augmenter le nombre de portes à deux qubits.

Corrections des erreurs

  • Correction d'un bogue où l'appel à QuantumCircuit.decompose() sur une instruction qui n'avait pas de définition à l'intérieur d'un bloc c_if provoquait une erreur. Correction #13493.

  • Les opérations à l'intérieur d'une opération de flux de contrôle (par exemple QuantumCircuit.for_loop()) n'étaient pas correctement décomposées lors de l'appel à QuantumCircuit.decompose(). Correction #13544.

  • Ajout de définitions par défaut pour FullAdderGate, HalfAdderGate, ModularAdderGate et MultiplierGate ce qui permet de construire des Operatord'être construits à partir de circuits quantiques contenant ces portes.

  • Correction du nombre de qubits ancilla propres requis par FullAdderSynthesisV95, HalfAdderSynthesisV95, et ModularAdderSynthesisV95 plugins.

  • Ajout d'un plugin FullAdderSynthesisDefault qui choisit la meilleure décomposition pour FullAdderGate en fonction du nombre de qubits ancilla propres disponibles.

  • Fixe HalfAdderSynthesisDefault et ModularAdderSynthesisDefault pour les plugins HalfAdderGate et ModularAdderGate respectivement, pour choisir la meilleure décomposition en fonction du nombre de qubits ancilla propres disponibles.

  • Correction d'un comportement incorrect de la mise en cache lors de l'affectation des paramètres, qui pouvait entraîner la corruption des définitions dans la base de données des paramètres EquivalenceLibrary étaient corrompues. Cela permet de résoudre des problèmes inattendus lors de l'exécution en parallèle de la traduction de la base. Correction #13504.

  • Correction d'une série de bogues lors du traitement de circuits avec des phases globales paramétrées dans lesquels la phase globale n'était pas correctement assignée lors de l'assignation des paramètres. Parmi les cas connus, on peut citer

    • l'assignation de paramètres après l'appel QuantumCircuit.decompose() sur un circuit, où la décomposition introduit une phase globale
    • l'attribution de paramètres à un circuit construit à partir d'un DAG par l'intermédiaire de dag_to_circuit()
    • l'attribution de paramètres aux circuits créés avec pauli_twirl_2q_gates()où le circuit à faire tourner avait une phase globale paramétrée

    Correction #13534.

  • Correction d'un bug dans RZGate.control() pour plus d'un qubit de contrôle, qui utilisait une décomposition inutilement coûteuse. Correction #13473.


1.3.0

Prélude

La version 1.3.0 de Qiskit apporte des améliorations majeures en termes de performance et de qualité du transpileur. De nombreuses nouvelles fonctionnalités, corrections et améliorations ont été introduites dans cette nouvelle version de Qiskit :

  • Les structures de données de base pour la transpilation dans Qiskit ont été portées à Rust en interne. Il s'agit d'éléments tels que DAGCircuit, Target, EquivalenceLibraryet d'autres. Les API publiques pour toutes ces structures de données restent inchangées, mais les performances après les réécritures ont été améliorées.

  • La majorité des passes de transpilation utilisées par le gestionnaire de passes prédéfinies ont été portées en Rust, ce qui a permis d'améliorer la durée d'exécution globale de 6x par rapport à Qiskit 1.2.4 lors de l'exécution des tests de référence benchpress. Parmi les passes particulièrement impactantes qui ont grandement bénéficié des réécritures, on peut citer les passes suivantes BasisTranslator, CommutationAnalysis, ConsolidateBlocks, et UnitarySynthesis. Vous pouvez vous référer aux notes de mise à jour des fonctionnalités pour une liste complète des passages portés.

  • Améliorations de la bibliothèque de circuits qui augmentent la qualité de la compilation et la vitesse de construction des circuits. Les opérations se répartissent désormais en plusieurs catégories :

    • Les opérations structurelles, qui ont une décomposition unique, sont représentées comme des fonctions qui renvoient un QuantumCircuit (par exemple : real_amplitudes()). La plupart de ces fonctions sont construites en Rust, ce qui permet d'accélérer considérablement le temps d'exécution de la construction des circuits.
    • Les opérations abstraites, qui peuvent être mises en œuvre à l'aide de différentes décompositions, sont représentées sous la forme de Gate ou Instruction (par exemple : PauliEvolutionGate). Cela permet de construire un circuit quantique abstrait et de laisser le compilateur choisir la décomposition optimale.

    L'utilisation d'une description abstraite du circuit est particulièrement puissante en combinaison avec les améliorations apportées à la passe de transposition, qui peut maintenant prendre en compte les qubits auxiliaires inactifs pour trouver la meilleure décomposition possible pour une porte donnée HighLevelSynthesis qui peut maintenant prendre en compte les qubits auxiliaires inactifs pour trouver la meilleure décomposition disponible pour une porte donnée.

  • La version minimale prise en charge de Python est désormais 3.9, car Python 3.8 est arrivé en fin de vie en 2024-10. La prise en charge officielle de Python 3.13 a également été ajoutée dans cette version.

Caractéristiques des circuits

  • Amélioration de la fonctionnalité de CommutationChecker pour inclure la prise en charge des portes paramétrées suivantes avec des paramètres libres : RXXGate, RYYGate, RZZGate, RZXGate, RXGate, RYGate, RZGate, PhaseGate, U1Gate, CRXGate, CRYGate, CRZGate, CPhaseGate. Auparavant, ces paramètres n'étaient pris en charge qu'avec des paramètres liés.

  • Ajout d'une nouvelle fonction quantum_volume() pour générer un objet de volume quantique QuantumCircuit tel que défini dans A. Cross et al. Validating quantum computers using randomized model circuits, Phys. Rev. A 100, 032328 (2019). Cette nouvelle fonction diffère de la classe QuantumVolume existante en ce sens qu'elle renvoie un objet QuantumCircuit au lieu de construire un objet de sous-classe. La seconde est que cette nouvelle fonction est multithread et implémentée en rust, de sorte qu'elle génère le circuit de sortie ~10x plus rapidement que la QuantumVolume classe.

  • Amélioration des performances d'exécution lors de la construction de la classe QuantumVolume avec l'argument classical_permutation fixé à True. En interne, il appelle maintenant la fonction quantum_volume() qui est écrite en Rust et qui est ~10x plus rapide lors de la génération d'un circuit de volume quantique.

  • Ajout d'une nouvelle fonction de manipulation des circuits pauli_twirl_2q_gates() qui peut être utilisée pour appliquer le tourbillon de Pauli à un circuit donné. Cela ne fonctionne que pour faire tourner un ensemble fixe de portes à deux qubits, actuellement CXGate, ECRGate, CZGate, iSwapGate. Par exemple :

    from qiskit.circuit import QuantumCircuit, pauli_twirl_2q_gates
    
    qc = QuantumCircuit(2)
    qc.cx(0, 1)
    twirled_circuit = pauli_twirl_2q_gates(qc, seed=123456)
    twirled_circuit.draw("mpl")
    _images/release_notes-1.png
  • Ajout de portes arithmétiques binaires pour l'addition sur place de deux registres nn -qubit, c'est-à-dire abaa+b|a\rangle |b\rangle \mapsto |a\rangle |a+b\rangle. La porte ModularAdderGate met en œuvre l'addition modulo 2n2^n, le HalfAdderGate comprend un qubit de report, et le FullAdderGate comprend un qubit d'entrée et un qubit de sortie. Voir la documentation correspondante pour plus de détails et d'exemples.

    Contrairement aux circuits de bibliothèque existants, tels que CDKMRippleCarryAdderla manipulation de la porte abstraite permet au compilateur (ou à l'utilisateur) de sélectionner la synthèse de porte optimale, en fonction du contexte du circuit.

  • Ajout du MultiplierGate pour la multiplication de deux registres nn -qubit, c'est-à-dire ab0abab|a\rangle |b\rangle |0\rangle \mapsto |a\rangle |b\rangle |a \cdot b\rangle. Voir la documentation de la classe pour plus de détails et d'exemples.

  • Les circuits quantiques à logique booléenne de qiskit.circuit.library ont maintenant des représentations équivalentes en tant qu'objets Gate ce qui permet de les utiliser avec HighLevelSynthesis transpiler pass et l'infrastructure de plugins.

  • Des implémentations spécialisées de __eq__() ont été ajoutées pour toutes les portes de circuits de la bibliothèque standard. La plupart des portes standard étaient déjà spécialisées dans cette méthode, mais certaines ne l'étaient pas et pouvaient provoquer des ralentissements importants à des endroits inattendus.

  • Ajouté evolved_operator_ansatz(), hamiltonian_variational_ansatz(), et qaoa_ansatz() dans la bibliothèque de circuits pour mettre en œuvre des circuits variationnels basés sur des évolutions d'opérateurs. evolved_operator_ansatz() et qaoa_ansatz() sont fonctionnellement équivalents à EvolvedOperatorAnsatz et QAOAAnsatzmais sont généralement plus performants.

    L'outil hamiltonian_variational_ansatz() est conçu pour prendre un seul hamiltonien et le diviser automatiquement en termes commutés afin de mettre en œuvre un ansatz variationnel hamiltonien. Cette opération pouvait déjà être réalisée manuellement à l'aide de la fonction EvolvedOperatorAnsatzmais c'est désormais plus pratique.

  • Ajouté grover_operator() pour construire un circuit opérateur de Grover, utilisé dans l'algorithme de Grover et l'estimation/amplification d'amplitude, par exemple. Cette fonction est similaire à GroverOperatormais ne vous demande pas de choisir l'implémentation de la porte X multi-contrôlée, et laisse le compilateur déterminer la décomposition optimale. En outre, elle n'enferme pas le circuit dans une porte opaque et est plus rapide car moins de décompositions sont nécessaires pour la transpilation.

    from qiskit.circuit import QuantumCircuit
    from qiskit.circuit.library import grover_operator
    
    oracle = QuantumCircuit(2)
    oracle.z(0)  # good state = first qubit is |1>
    grover_op = grover_operator(oracle, insert_barriers=True)
    grover_op.draw('mpl')
    _images/release_notes-2.png
  • Un nouvel attribut de données, qiskit.circuit.CONTROL_FLOW_OP_NAMESest disponible pour trouver et vérifier facilement si une opération donnée de type Instruction est une opération de flux de contrôle par son nom.

  • La bibliothèque d'équivalence standard (SessionEquivalenceLibrary) a maintenant des règles qui peuvent directement convertir entre la bibliothèque standard de Qiskit 2q les interactions continues de type Ising (par ex. CPhaseGate, RZZGate, RZXGateet ainsi de suite) en utilisant des relations d'équivalence locales. Auparavant, plusieurs de ces conversions passaient par une forme 2-CX, ce qui entraînait une génération de circuits moins efficace.

    Remarque

    En général, l'outil BasisTranslator n'est pas assuré de trouver la "meilleure" relation d'équivalence pour un Targetmais trouvera toujours une équivalence s'il en existe une. Nous nous appuyons sur des passes de resynthèse et d'optimisation de portes plus coûteuses dans le transpileur pour améliorer le résultat. Ces passes ne sont actuellement pas aussi efficaces pour les ensembles de base avec une interaction à deux qubits paramétrée de manière continue que pour les interactions à deux qubits super-contrôlées discrètes.

  • Ajout d'un nouvel argument "apply_synthesis" à Decomposequi permet à la passe de transposition d'appliquer la synthèse de haut niveau pour décomposer les objets qui ne sont définis que par une routine de synthèse. Par exemple :

    from qiskit import QuantumCircuit
    from qiskit.quantum_info import Clifford
    from qiskit.transpiler.passes import Decompose
    
    cliff = Clifford(HGate())
    circuit = QuantumCircuit(1)
    circuit.append(cliff, [0])
    
    # Clifford has no .definition, it is only defined by synthesis
    nothing_happened = Decompose()(circuit)
    
    # this internally runs the HighLevelSynthesis pass to decompose the Clifford
    decomposed = Decompose(apply_synthesis=True)(circuit)
  • Ajout de la fonction iqp() pour construire des circuits en temps polynomial quantique instantané (IQP). En plus de la classe IQP existante, la fonction permet également de construire des circuits IQP aléatoires :

    from qiskit.circuit.library import random_iqp
    
    random_iqp = random_iqp(num_qubits=4)
    random_iqp.draw('mpl')
    _images/release_notes-3.png
  • Ajout de l'élément MCMTGate pour représenter une opération multi-contrôle multi-cible comme une porte. Cette représentation de la porte du circuit existant MCMT permet au compilateur de sélectionner la meilleure implémentation disponible en fonction du nombre et de l'état des qubits auxiliaires présents dans le circuit.

    L'implémentation souhaitée peut être choisie en spécifiant le plugin de synthèse de haut niveau :

    from qiskit import QuantumCircuit, transpile
    from qiskit.circuit.library import MCMTGate, HGate
    from qiskit.transpiler.passes import HLSConfig  # used for the synthesis config
    
    mcmt = MCMTGate(HGate(), num_ctrl_qubits=5, num_target_qubits=3)
    
    circuit = QuantumCircuit(20)
    circuit.append(mcmt, range(mcmt.num_qubits))
    
    config = HLSConfig(mcmt=["vchain"])  # alternatively use the "noaux" method
    synthesized = transpile(circuit, hls_config=config)

    En outre, le système MCMTGate prend également en charge les états de contrôle personnalisés (c'est-à-dire ouverts) des qubits de contrôle.

  • Dans le cadre de la modernisation de la bibliothèque de circuits, chacun des circuits quantiques suivants est également représenté sous forme d'objet ou peut être construit à l'aide d'une méthode de synthèse Gate ou peuvent être construits à l'aide d'une méthode de synthèse :

  • La classe CommutationChecker a été réécrite en rouille. Cette classe conserve les mêmes fonctionnalités et la même API publique qu'auparavant, mais elle est désormais beaucoup plus rapide dans la plupart des cas.

  • PauliFeatureMap et ZZFeatureMap permettent désormais de spécifier l'intrication sous la forme d'un dictionnaire dont les clés représentent le nombre de qubits et les valeurs sont des listes de tuples entiers qui définissent quels qubits sont intriqués les uns avec les autres. Cela permet une plus grande flexibilité dans la construction de cartes de caractéristiques adaptées à des algorithmes quantiques spécifiques. Exemple d'utilisation :

    from qiskit.circuit.library import PauliFeatureMap
    entanglement = {
      1: [(0,), (2,)],
      2: [(0, 1), (1, 2)],
      3: [(0, 1, 2)],
    }
    qc = PauliFeatureMap(3, reps=2, paulis=['Z', 'ZZ', 'ZZZ'], entanglement=entanglement, insert_barriers=True)
    qc.decompose().draw('mpl')
  • La méthode count_ops() dans QuantumCircuit a été réécrite en rouille. Il fonctionne désormais entre 3 et 9 fois plus vite.

  • Ajout de fonctions de bibliothèque de circuits pauli_feature_map(), z_feature_map(), zz_feature_map() pour construire des circuits de cartes de Pauli. Ces fonctions sont environ 8x plus rapides que les objets actuels de la bibliothèque de circuits, PauliFeatureMap, ZFeatureMapet ZZFeatureMapet les remplaceront à l'avenir.

    Les fonctions peuvent être utilisées en remplacement :

    from qiskit.circuit.library import pauli_feature_map, PauliFeatureMap
    
    fm = pauli_feature_map(20, paulis=["z", "xx", "yyy"])
    also_fm = PauliFeatureMap(20, paulis=["z", "xx", "yyy"]).decompose()

Fonctionnalités primitives

  • La prise en charge des données de niveau 1 a été ajoutée à BackendSamplerV2ainsi que la prise en charge du passage d'options à la méthode run() de l'élément enveloppé BackendV2. Les options d'exécution peuvent être spécifiées en utilisant une entrée "run_options" dans le dictionnaire options transmis à BackendSamplerV2. L'entrée "run_options" doit être un dictionnaire qui associe les noms des arguments aux valeurs à transmettre à la méthode run() du backend. Lorsqu'un "meas_level = 1 " est défini dans les options d'exécution, les résultats provenant du backend seront traités comme des résultats de niveau 1 au lieu de tableaux de bits (le format de niveau 2).

  • Estimator et StatevectorEstimator renvoient des valeurs d'espérance de manière stochastique si le circuit d'entrée comprend une réinitialisation de certains sous-systèmes. Le résultat n'était pas reproductible auparavant, mais il peut désormais l'être si l'on fixe une graine aléatoire. Par exemple :

    from qiskit.primitives import StatevectorEstimator
    
    estimator = StatevectorEstimator(seed=123)

    ou :

    from qiskit.primitives import Estimator
    
    estimator = Estimator(options={"seed":123})

OpenQASM Caractéristiques

Caractéristiques du QPY

  • Ajout d'un nouveau format QPY version 13 qui ajoute une représentation native Qiskit des objets ParameterExpression objets.

Caractéristiques de l'information quantique

  • La performance de SparsePauliOp.from_operator() a été optimisée en plus des méthodes d'amélioration des algorithmes introduites dans Qiskit 1.0. Il est maintenant environ cinq fois plus rapide qu'auparavant pour les matrices entièrement denses, prenant environ 40ms pour décomposer un opérateur 10q impliquant tous les termes de Pauli.

  • Ajout d'un nouvel argument assume_unitary à qiskit.quantum_info.Operator.power(). Lorsque True, nous utilisons une méthode plus rapide basée sur la décomposition de Schur pour élever Operator à une puissance fractionnaire.

  • Ajouté SparsePauliOp.to_sparse_list() pour convertir un opérateur dans un format de liste clairsemée. Cela fonctionne à l'inverse de SparsePauliOp.from_sparse_list(). Par exemple :

    from qiskit.quantum_info import SparsePauliOp
    
    op = SparsePauliOp(["XIII", "IZZI"], coeffs=[1, 2])
    sparse = op.to_sparse_list()  # [("X", [3], 1), ("ZZ", [1, 2], 2)]
    
    other = SparsePauliOp.from_sparse_list(sparse, op.num_qubits)
    print(other == op)  # True
  • La performance de Pauli.to_label() s'est considérablement améliorée pour les grands Paulis.

  • La méthode Operator.power() a un nouveau paramètre branch_cut_rotation. Ceci peut être utilisé pour déplacer le point de coupe de la racine, ce qui peut affecter la matrice choisie comme racine principale. Par défaut, il est fixé à une petite rotation positive pour rendre les racines des opérateurs ayant une valeur propre réelle négative (comme les opérateurs de Pauli) plus stables face aux différences de précision numérique.

  • Une nouvelle classe d'observables a été ajoutée. SparseObservable représente les observables sous la forme d'une somme de termes, à l'instar de SparsePauliOpmais avec deux différences essentielles :

    1. Chaque terme complet est stocké sous la forme (effective) d'une série de paires (qubit, bit_term) , sans stocker les qubits qui subissent l'identité de ce terme. Cela améliore considérablement l'utilisation de la mémoire pour les observables tels que la somme pondérée de Paulis iciZi\sum_i c_i Z_i.
    2. L'alphabet des termes à un qubit est surcomplet pour l'espace des opérateurs; il peut représenter des opérateurs de Pauli (comme SparsePauliOp), mais aussi des projecteurs sur les états propres des opérateurs de Pauli, comme 00\lvert 0\rangle\langle 0\rangle. De tels projecteurs peuvent être mesurés sur le matériel aussi efficacement que leur opérateur de Pauli correspondant, mais SparsePauliOp nécessiterait un nombre exponentiel de termes pour représenter 00n{\lvert0\rangle\langle0\rvert}^{\otimes n} sur nn qubits, alors que SparseObservable ne nécessite qu'un seul terme.

    Vous pouvez construire et manipuler SparseObservable à l'aide d'une interface familière aux utilisateurs de SparsePauliOp:

    from qiskit.quantum_info import SparseObservable
    
    obs = SparseObservable.from_sparse_list([
      ("XZY", (2, 1, 0), 1.5j),
      ("+-", (100, 99), 0.5j),
      ("01", (50, 49), 0.5),
    ])

    SparseObservable n'est actuellement pas pris en charge en tant que format d'entrée pour les primitives (qiskit.primitives), mais nous prévoyons d'étendre ces interfaces pour les inclure à l'avenir.

Caractéristiques de la synthèse

  • Ajout de fonctions de synthèse synth_mcx_gray_code() et synth_mcx_noaux_v24() qui synthétisent des portes X multicontrôlées. Ces fonctions ne nécessitent pas de qubits ancillaires supplémentaires.

  • Ajout de fonctions de synthèse synth_c3x() et synth_c4x() qui synthétisent respectivement des portes X à 3 et 4 contrôles.

  • Ajouter une fonction de synthèse synth_mcx_n_dirty_i15() qui synthétise une porte X multi-contrôlée avec kk contrôles en utilisant k2k - 2 dirty ancillary qubits produisant un circuit avec au plus 8k68 * k - 6 portes CX, par Iten et. al. (arXiv:1501.06911).

  • Ajouter une fonction de synthèse synth_mcx_n_clean_m15() qui synthétise une porte X multi-contrôlée avec kk contrôles en utilisant k2k - 2 qubits auxiliaires propres produisant un circuit avec au plus 6k66 * k - 6 portes CX, par Maslov ( arXiv:1508.03273 ).

  • Ajouter une fonction de synthèse synth_mcx_1_clean_b95() qui synthétise une porte X multi-contrôlée avec kk contrôles en utilisant un seul qubit auxiliaire propre produisant un circuit avec au plus 16k816 * k - 8 portes CX, par Barenco et al. ( arXiv:quant-ph/9503016 ).

  • Ajouté adder_qft_d00(), adder_ripple_c04(), et adder_ripple_v95() pour synthétiser les portes de l'additionneur, ModularAdderGate, HalfAdderGate, et FullAdderGate.

  • Ajouté multiplier_cumulative_h18() et multiplier_qft_r17() pour synthétiser le MultiplierGate.

  • Ajouté synth_mcmt_vchain() pour synthétiser la porte multi-contrôle multi-cible avec un nombre linéaire de portes de Toffoli et k-1 qubits auxiliaires pour k qubits de contrôle, avec le plugin de synthèse de haut niveau MCMTSynthesisVChain.

  • Ajout d'une structure de plugin de synthèse de haut niveau pour le plugin MCMTGatey compris le MCMTSynthesisNoAux (pour l'absence de qubits auxiliaires), le plugin mentionné ci-dessus MCMTSynthesisVChain (utilisant num_control - 1 qubits auxiliaires), et le plugin MCMTSynthesisDefault pour permettre au compilateur de choisir la décomposition optimale.

  • La fonction random_clifford() a été portée en Rust, ce qui a permis d'améliorer la durée d'exécution d'un facteur 3.

  • Ajouté ProductFormula.expand()qui vous permet de visualiser l'expansion d'une formule de produit dans un format Pauli clairsemé. Par exemple, nous pouvons demander le format d'une expansion de Trotter du second ordre d'un hamiltonien comme suit :

    from qiskit.quantum_info import SparsePauliOp
    from qiskit.circuit.library import PauliEvolutionGate
    from qiskit.synthesis.evolution import SuzukiTrotter
    
    hamiltonian = SparsePauliOp(["IX", "XI", "ZZ"], coeffs=[-1, -1, 1])
    evo = PauliEvolutionGate(hamiltonian, time=3.14)
    trotter = SuzukiTrotter(order=2)
    print(trotter.expand(evo))

    qui imprimera

    [('X', [0], -3.14), ('X', [1], -3.14), ('ZZ', [0, 1], 6.28),
    ('X', [1], -3.14), ('X', [0], -3.14)]
  • Ajout de la structure du plugin pour le fichier PauliEvolutionGate. Le plugin par défaut, PauliEvolutionSynthesisDefaultconstruit le circuit comme auparavant, mais plus rapidement, car il utilise Rust en interne. Plus le circuit est grand (par exemple. par la taille de l'hamiltonien, le nombre de pas de temps ou l'ordre de Suzuki-Trotter), plus l'accélération est importante. Par exemple, un hamiltonien d'Heisenberg de 100 qubits avec 10 pas de temps et une formule de Trotter du 4e ordre est maintenant construit ~9.4x plus rapidement. Le nouveau plugin, PauliEvolutionSynthesisRustiqutilise l'algorithme de synthèse décrit dans l'article " Faster and short synthesis of Hamiltonian simulation circuits" de (de) Brugière et Martiel " et est implémenté dans Rustiq. Par exemple :

    from qiskit.circuit import QuantumCircuit
    from qiskit.quantum_info import SparsePauliOp
    from qiskit.circuit.library import PauliEvolutionGate
    from qiskit.compiler import transpile
    from qiskit.transpiler.passes import HLSConfig
    
    op = SparsePauliOp(["XXX", "YYY", "IZZ"])
    qc = QuantumCircuit(4)
    qc.append(PauliEvolutionGate(op), [0, 1, 3])
    config = HLSConfig(PauliEvolution=[("rustiq", {"upto_phase": False})])
    tqc = transpile(qc, basis_gates=["cx", "u"], hls_config=config)
    tqc.draw(output='mpl')
    _images/release_notes-4.png

    Cet extrait de code utilise le plugin Rustiq pour synthétiser des objets dans le circuit quantique qc PauliEvolutionGate objets dans le circuit quantique qc. Le plugin est appelé avec l'option supplémentaire upto_phase = False, ce qui permet d'obtenir des circuits plus petits au prix d'une éventuelle non-conservation de la phase globale. Pour la liste complète des options prises en charge, voir la documentation de PauliEvolutionSynthesisRustiq.

  • Port synth_cz_depth_line_mr() à la rouille. Cette fonction synthétise un circuit CZ pour la connectivité du plus proche voisin linéaire (LNN), basé sur la méthode Maslov et Roetteler. Sur une matrice binaire de 350x350, l'implémentation de Rust permet une accélération d'environ 30x.

  • Port synth_permutation_reverse_lnn_kms() vers Rust, qui synthétise une permutation inverse pour l'architecture LNN en utilisant la méthode Kutin, Moulton, Smithline.

  • Ajout d'un nouvel argument preserve_order à ProductFormulaqui permet de réordonner les termes de Pauli dans l'hamiltonien avant l'expansion de la formule du produit, afin de comprimer la profondeur du circuit final. En fixant cette valeur à False, on obtient un terme de la forme

Z0Z1+X1X2+Y2Y3Z_0 Z_1 + X_1 X_2 + Y_2 Y_3

seront réordonnées en

Z0Z1+Y2Y3+X1X2Z_0 Z_1 + Y_2 Y_3 + X_1 X_2

ce qui conduira à l'application en parallèle des rotations RZZ et RYY , au lieu des trois rotations séquentielles de la première partie.

Cette option peut être définie via l'interface du plugin :

from qiskit import QuantumCircuit, transpile
from qiskit.circuit.library import PauliEvolutionGate
from qiskit.quantum_info import SparsePauliOp
from qiskit.synthesis.evolution import SuzukiTrotter
from qiskit.transpiler.passes import HLSConfig

op = SparsePauliOp(["XXII", "IYYI", "IIZZ"])
time, reps = 0.1, 1

synthesis = SuzukiTrotter(order=2, reps=reps)
hls_config = HLSConfig(PauliEvolution=[("default", {"preserve_order": False})])

circuit = QuantumCircuit(op.num_qubits)
circuit.append(PauliEvolutionGate(op, time), circuit.qubits)

tqc = transpile(circuit, basis_gates=["u", "cx"], hls_config=hls_config)
tqc.draw('mpl')
_images/release_notes-5.png

Fonctionnalités du transpilateur

  • Ajouter l'argument matrix_based à la passe de CollectCliffords transpiler. Si le nouveau paramètre matrix_based=True, la passe de transposition peut collecter des portes unitaires qui sont des portes de Clifford pour certains paramètres CollectCliffords transpiler pass peut collecter des portes unitaires qui sont des portes de Clifford pour certains paramètres, par exemple RZGate les portes dont les angles sont des multiples de π/2\pi / 2.

  • La passe de RemoveIdentityEquivalent la passe de transpilation est maintenant exécutée dans le cadre des gestionnaires de passes prédéfinies aux niveaux d'optimisation 2 et 3. La passe s'exécute pendant les étapes init et optimization , car les optimisations qu'elle applique sont valables dans les deux étapes et la passe est rapide à exécuter.

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

    Ainsi que :

    • MCXSynthesisDefaultpour choisir la méthode de synthèse la plus efficace en fonction du nombre de qubits ancilla propres et sales disponibles.

    A titre d'exemple, considérons la transpilation du circuit suivant :

    from qiskit.circuit import QuantumCircuit
    from qiskit.compiler import transpile
    
    qc = QuantumCircuit(7)
    qc.x(0)
    qc.mcx([0, 1, 2, 3], [4])
    qc.mcx([0, 1, 2, 3, 4], [5])
    qc.mcx([0, 1, 2, 3, 4, 5], [6])
    
    transpile(qc).draw('mpl', fold=-1)
    _images/release_notes-6.png

    Pour la première porte MCX, les qubits 5 et 6 peuvent être utilisés comme ancillas propres, et la meilleure méthode de synthèse disponible synth_mcx_n_clean_m15 sera choisie. Pour la deuxième porte MCX, le qubit 6 peut être utilisé comme ancilla propre, la méthode synth_mcx_n_clean_m15 ne s'applique plus, et c'est donc la méthode synth_mcx_1_clean_b95 qui sera choisie. Pour la troisième porte MCX, il n'y a pas de qubits ancillaires, et la méthode synth_mcx_noaux_v24 sera choisie.

  • La passe SabreLayout a été mis à jour pour exécuter deux ou trois essais de mise en page supplémentaires par défaut, indépendamment de la valeur de l'argument du mot-clé layout_trials . Un modèle trivial et son inverse sont inclus pour tous les backends, tout comme le modèle DenseLayout qui a été ajouté à 1.2.0. En outre, les anneaux les plus grands du graphe de connectivité des hexagones lourds d'un backend IBM sont ajoutés si les backends ont 127, 133 ou 156 qubits. Cela peut constituer un bon point de départ pour certains circuits sur ces backends couramment utilisés, alors que pour tous les autres, il s'agit simplement d'un "essai aléatoire" supplémentaire.

  • Les DAGCircuit a été réimplémenté en Rust. Cette réécriture de la classe Python devrait être entièrement compatible avec l'API de l'ancienne implémentation Python. Bien que la classe ait été précédemment implémentée en utilisant rustworkx, pour laquelle la structure de graphe de données sous-jacente existe en Rust, l'implémentation de la classe et de toutes les données a été réalisée à l'adresse Python. Cette nouvelle version de DAGCircuit stocke les représentations natives de Rust pour toutes ses données et est plus efficace en termes de mémoire grâce à la représentation comprimée des qubits et des clbits conçue pour les instructions au repos. Il permet également aux passes de transpilation de manipuler complètement un DAGCircuit à partir de Rust, ce qui permet d'améliorer les performances.

  • Un nouvel argument qubits_initially_zero a été ajouté à qiskit.compiler.transpile(), generate_preset_pass_manager()et à PassManagerConfig. Si la valeur par défaut est True, les qubits sont supposés être initialement dans l'état 0|0\rangle, ce qui peut offrir des possibilités d'optimisation supplémentaires pour les différentes passes du transpondeur. En particulier, la passe de HighLevelSynthesis transpiler pass choisira une meilleure décomposition pour chaque MCXGate d'un circuit lorsqu'un qubit auxiliaire inactif dans l'état 0|0\rangle est disponible.

    Cependant, dans certains cas, qubits_initially_zero doit être fixé à False, par exemple lors de la transposition pour des backends qui n'initialisent pas correctement les qubits, ou lors de l'appel manuel de passes de transposition sur des sous-circuits d'un circuit quantique plus important.

  • Le constructeur de la passe HighLevelSynthesis accepte maintenant un argument supplémentaire : qubits_initially_zero. S'il est défini à True, la passe suppose que les qubits sont initialement dans l'état 0|0\rangle. De plus, la passe garde la trace des qubits auxiliaires propres et sales tout au long de l'exécution, et transmet cette information aux plugins en utilisant les kwargs num_clean_ancillas et num_dirty_ancillas.

  • Amélioration de la gestion des qubits ancillaires dans la passe de HighLevelSynthesis transpiler. Par exemple, un circuit peut avoir des portes personnalisées dont les définitions comprennent MCXGates. Désormais, les algorithmes de synthèse pour les MCXGatepeuvent utiliser les qubits ancillaires disponibles sur le circuit global mais en dehors des définitions des portes personnalisées.

  • Ajout d'une nouvelle méthode DAGCircuit.control_flow_op_nodes() qui fournit un chemin rapide pour obtenir tous les DAGOpNode dans un DAGCircuit qui contiennent a ControlFlowOp. Cela était possible avant d'utiliser la méthode DAGCircuit.op_nodes() et en passant la classe ControlFlowOp comme filtre, mais cette nouvelle fonction effectuera l'opération plus rapidement.

  • La majorité des passes de transpilateur utilisées dans les gestionnaires de passes prédéfinies sont renvoyées par generate_preset_pass_manager() et utilisés en interne par transpile() ont été portés en Rust. Cela a permis d'améliorer considérablement les performances d'exécution de chaque passage, ce qui a conduit à une amélioration significative de l'efficacité opérationnelle globale du transpondeur. La liste des passes portées en Rust dans cette version est la suivante :

  • Ajout d'une nouvelle passe de transpilation, RemoveIdentityEquivalent qui est utilisée pour supprimer les portes qui sont équivalentes à une identité jusqu'à une certaine tolérance. Par exemple, si vous avez un circuit comme :

    _images/release_notes-7.png

    l'exécution de la passe permettrait d'éliminer le CPhaseGate:

    from qiskit.circuit import QuantumCircuit
    from qiskit.transpiler.passes import RemoveIdentityEquivalent
    
    qc = QuantumCircuit(2)
    qc.cp(1e-20, 0, 1)
    
    removal_pass = RemoveIdentityEquivalent()
    result = removal_pass(qc)
    result.draw("mpl")
    _images/release_notes-8.png
  • La passe ConsolidateBlocks exécutera maintenant l'équivalent de la passe Collect2qBlocks en interne s'il n'a pas été exécuté dans un gestionnaire de passe avant la passe. Précédemment, Collect2qBlocks ou Collect1qRuns devait être exécuté avant ConsolidateBlocks pour que ConsolidateBlocks pour faire quoi que ce soit. En effectuant la collecte en interne, les frais généraux liés au passage sont réduits. Si Collect2qBlocks ou Collect1qRuns sont exécutées avant ConsolidateBlocksles exécutions collectées par ces passes de l'ensemble des propriétés sont utilisées et il n'y a pas de changement de comportement pour la passe.

  • Le RemoveDiagonalGatesBeforeMeasure le passage du transpondeur a été amélioré pour inclure plus de portes diagonales : PhaseGate, CPhaseGate, CSGate, CSdgGate et CCZGate. En outre, le code du RemoveDiagonalGatesBeforeMeasure a été porté à Rust, et est maintenant x20 plus rapide pour un circuit de 20 qubits.

Fonctionnalités de visualisation

  • La fonction timeline_drawer() la fonction de visualisation a un nouvel argument target, qui permet de spécifier un objet pour la visualisation Target pour la visualisation. Par défaut, la fonction utilise la fonction Instruction.duration pour obtenir la durée d'une instruction donnée, mais le fait de spécifier la cible permet d'exploiter les détails temporels à l'intérieur de la cible.

Problèmes connus

  • Lors de l'utilisation des formats 10, 11 ou 12 de QPY avec des circuits contenant des ParameterExpressionsi la version du paquet symengine installée dans l'environnement qui a généré la charge utile (qpy.dump()) ne correspond pas à la version de symengine installée dans l'environnement où la charge utile est chargée (qpy.load()), vous obtiendrez une erreur. Si vous rencontrez cette erreur, installez la version symengine indiquée dans le message d'erreur avant d'appeler qpy.load(). Les versions 13 ou ultérieures du format QPY (ou antérieures à 10) ne présentent pas ce problème. Par conséquent, si vous sérialisez ParameterExpression dans le cadre de votre circuit ou tout autre objet ScheduleBlock il est recommandé d'utiliser la version 13 pour éviter ce problème à l'avenir.

Mise à niveau

  • Les classes suivantes utilisent maintenant l'opération X\sqrt{X} pour diagonaliser l'opérateur Pauli-Y : PauliEvolutionGate, EvolvedOperatorAnsatz, et PauliFeatureMap. Auparavant, ces classes utilisaient soit HSH S soit RX(π/2)R_X(-\pi/2) comme transformation de base. L'utilisation de l'opération X\sqrt{X}, représentée par l'icône SXGate est plus efficace car elle n'utilise qu'une seule porte implémentée en tant que singleton.

    Si vous vous êtes appuyé sur l'utilisation précédente des portes, nous vous recommandons de construire les circuits avec Qiskit 1.2 et de les exporter avec qpy.dump()ou d'écrire un fichier personnalisé TransformationPassqui effectuera la traduction vers la porte de changement de base souhaitée.

  • La version minimale supportée de Python est maintenant 3.9, elle a été augmentée par rapport à la version minimale supportée précédente de 3.8. Ce changement était nécessaire car le projet en amont cPython ne prend plus en charge Python 3.8.

Notes sur la mise à niveau des circuits

  • Le cours QuantumVolume générera des circuits avec différentes matrices unitaires et permutations pour une valeur de départ donnée de la version précédente de Qiskit. Ceci est dû à l'utilisation d'un nouveau générateur de nombres aléatoires interne pour la génération du circuit qui génère le circuit plus rapidement. Si vous avez besoin d'un circuit exact avec la même graine, vous pouvez utiliser la version précédente de Qiskit et générer le circuit avec l'argument flatten=True et exporter le circuit avec qpy.dump() puis le charger avec cette version.

Notes de mise à niveau des primitives

  • Lors de l'utilisation de BackendSamplerV2les métadonnées des circuits ne sont plus effacées avant de transmettre les circuits à la méthode run() de l'instance enveloppée BackendV2 enveloppée. Si vous vous basiez auparavant sur ce comportement, vous pouvez effacer manuellement les métadonnées avant d'appeler BackendSamplerV2.run() en appelant circuit.metadata.clear()

Notes de mise à niveau QPY

  • La fonction qpy.dump() émet désormais le format version 13 par défaut. Cela signifie que les payloads générés par défaut avec cette fonction ne sont compatibles qu'avec Qiskit 1.3.0 ou une version ultérieure. Si la charge utile doit être chargée par une version antérieure de Qiskit, utilisez le drapeau version sur qpy.dump() pour émettre la version appropriée. Pour plus de détails, voir Compatibilité QPY.

Notes de mise à niveau du transpilateur

  • DAGNode (et ses sous-classes DAGInNode, DAGOutNode, et DAGOpNode) ne renvoient plus de références au même objet sous-jacent à partir des méthodes DAGCircuit les méthodes d'analyse des objets. Il n'a jamais été garanti auparavant que tous les nœuds renvoyés seraient des références partagées au même objet. Cependant, avec la migration du DAGCircuit vers Rust, une nouvelle instance de DAGNode est générée à la volée lorsqu'un nœud est renvoyé à Python. Ces objets seront considérés comme égaux à l'aide de == ou de contrôles similaires reposant sur __eq__ , mais ne seront plus identifiés comme étant le même objet.

  • Les DAGOpNode renvoyées par la fonction DAGCircuit ne sont plus des références partagées aux données sous-jacentes stockées dans le DAG. Dans la version précédente, il était possible de faire quelque chose comme :

    for node in dag.op_nodes():
        node.op = new_op

    cependant, ce type de mutation a toujours été peu judicieux, car il pouvait rompre la mise en cache interne du DAG et entraîner une corruption de la structure des données. Vous devriez plutôt utiliser l'API fournie par DAGCircuit pour les mutations telles que DAGCircuit.substitute_node() ou DAGCircuit.substitute_node_with_dag(). Par exemple, le bloc de code ci-dessus deviendrait

    for node in dag.op_nodes():
      dag.substitute_node(node, new_op)

    Ceci est similaire à une note de mise à jour de 1.2.0 où il a été noté une mutation de l'attribut DAGOpNode.op et non de l'attribut DAGOpNode lui-même. Cependant, dans 1.3, cette règle s'applique à l'objet tout entier, et pas seulement à l'attribut interne op . En général, ce type de mutation a toujours été mal fondé et n'a pas été soutenu, mais il aurait pu fonctionner dans certains cas.

  • Les transpile() suppose maintenant que les qubits sont initialement dans l'état 0|0\rangle. Pour éviter cette hypothèse, on peut fixer l'argument qubits_initially_zero à False.

Remarques concernant la dépréciation

  • Le module qiskit.pulse et toutes ses fonctionnalités associées sont maintenant obsolètes et seront supprimées dans Qiskit 2.0.0. Cela s'explique par le fait que le principal fournisseur de backend prenant en charge les impulsions est IBM et que l'accès au niveau des impulsions n'est actuellement pris en charge que sur un sous-ensemble de backends de IBM et n'est pas pris en charge sur leurs architectures plus récentes. De même, elle a annoncé que l 'accès au niveau de l'impulsion serait supprimé en 2025. Si le plus grand fournisseur qui utilise la fonction ne soutient plus l'accès à l'impulsion, l'importance de la fonction pour Qiskit est considérablement réduite et mise en balance avec les frais généraux de maintenance du paquet qu'elle supprime.

    La dépréciation inclut tout le code de pulse dans qiskit.pulse ainsi que les fonctionnalités dépendantes ou liées à pulse, telles que la visualisation de pulse, la sérialisation et la prise en charge de l'étalonnage personnalisé. Pour plus de détails, voir les sections de dépréciation ci-dessous.

    Le paquet Pulse dans son ensemble, ainsi que les composants directement liés dans Qiskit, seront déplacés vers le référentiel Qiskit Dynamics pour permettre la simulation de l'impulsion et du contrôle de bas niveau. Qiskit 1.x continuera à prendre en charge l'application qiskit.pulse jusqu'à ce qu'il arrive en fin de vie.

Circuits obsolètes

  • L'attribut Instruction.condition et la méthode Instruction.c_if() méthode. Ils seront supprimés dans Qiskit 2.0, ainsi que toutes les utilisations dans le modèle de données de Qiskit. Cette fonctionnalité a été remplacée par la classe IfElseOp qui peut être utilisée pour décrire une condition classique dans un circuit. Par exemple, un circuit utilisant Instruction.c_if() comme :

    from qiskit.circuit import QuantumCircuit
    
    qc = QuantumCircuit(2, 2)
    qc.h(0)
    qc.x(0).c_if(0, 1)
    qc.z(1.c_if(1, 0)
    qc.measure(0, 0)
    qc.measure(1, 1)

    peut être réécrit ainsi :

    qc = QuantumCircuit(2, 2)
    qc.h(0)
    with qc.if_test((qc.clbits[0], True)):
        qc.x(0)
    with qc.if_test((qc.clbits[1], False)):
        qc.z(1)
    qc.measure(0, 0)
    qc.measure(1, 1)

    La passe ConvertConditionsToIfOps désormais obsolète, peut être utilisée pour automatiser cette conversion pour les circuits existants.


  • Dans le cadre de la dépréciation du package Qiskit Pulse, les dépendances suivantes sont également dépréciées :

  • Les QuantumCircuit.unit et QuantumCircuit.duration ont été dépréciés et seront supprimés dans Qiskit 2.0.0. Ces attributs ont été utilisés pour suivre la durée estimée et l'unité de cette durée à exécuter sur le circuit. Toutefois, les valeurs de ces attributs ont toujours été limitées, car elles ne sont correctement renseignées que si le transpondeur est exécuté avec les paramètres corrects. La durée n'était également qu'une estimation basée sur le chemin le plus long sur la somme des durées de DAGCircuit et n'aurait jamais pris en compte correctement le flux de contrôle ou les conditionnels dans le circuit.

  • Les DAGCircuit.unit et DAGCircuit.duration ont été dépréciés et seront supprimés dans Qiskit 2.0.0. Ces attributs ont été utilisés pour suivre la durée estimée et l'unité de cette durée à exécuter sur le circuit. Toutefois, les valeurs de ces attributs ont toujours été limitées, car elles ne sont correctement renseignées que si le transpondeur est exécuté avec les paramètres corrects. La durée n'était également qu'une estimation basée sur le chemin le plus long sur la somme des durées de DAGCircuit et n'aurait jamais pris en compte correctement le flux de contrôle ou les conditionnels dans le circuit.

  • Les Instruction.duration et Instruction.unit ont été dépréciés et seront supprimés dans Qiskit 2.0.0. Cela inclut la définition des arguments unit ou duration pour toute classe ou sous-classe de qiskit.circuit.Instruction ou d'une sous-classe. Ces attributs ont été utilisés pour associer une durée d'exécution personnalisée et une unité pour cette durée à une instruction individuelle. Cependant, la source de vérité de la durée d'une porte est le BackendV2 Target qui contient la durée de chaque instruction prise en charge par le backend. La durée d'une instruction n'est pas quelque chose de typiquement ajustable par l'utilisateur et c'est une propriété immuable du backend. Si vous utilisiez auparavant cette capacité pour expérimenter différentes durées pour les portes, vous pouvez faire muter le champ InstructionProperties.duration dans un champ Target pour définir une durée personnalisée pour une instruction sur un backend (l'unité est toujours en secondes dans le champ Target).

Avertissements aux fournisseurs

  • La méthode BasicSimulator.configuration() est obsolète et sera supprimée à l'adresse 2.0.0. Cette méthode renvoie une instance providers.models.BackendConfiguration qui fait partie du modèle BackendV1 obsolète. Ce modèle a été remplacé par BackendV2où les contraintes sont stockées directement dans l'instance de backend ou dans la base de données sous-jacente Target (backend.target).

    Voici un guide rapide pour accéder aux attributs les plus courants de BackendConfiguration dans le BackendV2 modèle :

    BackendV1 model (deprecated) ------------> BackendV2 model
    ----------------------------               ---------------
    backend.configuration().backend_name       backend.name
    backend.configuration().backend_version    backend.backend_version
    backend.configuration().n_qubits           backend.num_qubits
    backend.configuration().num_qubits         backend.num_qubits
    backend.configuration().basis_gates        backend.target.operation_names (*)
    backend.configuration().coupling_map       backend.target.build_coupling_map()
    backend.configuration().local              No representation
    backend.configuration().simulator          No representation
    backend.configuration().conditional        No representation
    backend.configuration().open_pulse         No representation     
    backend.configuration().memory             No representation      
    backend.configuration().max_shots          No representation      

    (*) Notez que Backend.target.operation_names inclut basis_gates et des instructions supplémentaires sans porte, dans certaines implémentations il peut être nécessaire de filtrer la sortie.

    Voir ce guide pour plus d'informations sur la migration vers le modèle BackendV2 modèle.


  • Dans le cadre de la dépréciation du package Qiskit Pulse, toutes les fonctionnalités liées à Pulse dans qiskit.providers.BackendV2 la classe sont en cours de dépréciation. Cela comprend les méthodes suivantes :

    Par conséquent, les méthodes de canal correspondantes dans les qiskit.providers.BackendV2Converter et qiskit.providers.fake_provider.GenericBackendV2 sont également obsolètes.

    En outre, les arguments pulse_channels et calibrate_instructions de la méthode BackendV2 sont dépréciés.

  • L'argument defaults est supprimé de la fonction qiskit.providers.convert_to_target() fonction.

Dépréciations QPY

Dépréciations du transcompilateur

  • Déclassé StochasticSwap qui a été remplacée par SabreSwap. Si la classe est appelée à partir de la fonction transpile, le changement serait, par exemple, le suivant :

    from qiskit import transpile
    from qiskit.circuit import QuantumCircuit
    from qiskit.transpiler import CouplingMap
    from qiskit.providers.fake_provider import GenericBackendV2
    
    
    qc = QuantumCircuit(4)
    qc.h(0)
    qc.cx(0, range(1, 4))
    qc.measure_all()
    
    cmap = CouplingMap.from_heavy_hex(3)
    backend = GenericBackendV2(num_qubits=cmap.size(), coupling_map=cmap)
    
    tqc = transpile(
        qc,
        routing_method="stochastic",
        layout_method="dense",
        seed_transpiler=12342,
        target=backend.target
    )

    pour :

    tqc = transpile(
        qc,
        routing_method="sabre",
        layout_method="sabre",
        seed_transpiler=12342,
        target=backend.target
    )

    Alors que pour un gestionnaire de laissez-passer, le changement serait le suivant :

    passmanager = PassManager(StochasticSwap(coupling, 20, 13))
    new_qc = passmanager.run(qc)

    pour :

    passmanager = PassManager(SabreSwap(backend.target, "basic"))
    new_qc = passmanager.run(qc)
  • La passe de transpilation ConvertConditionsToIfOps a été déprécié et sera supprimé dans Qiskit 2.0.0. Cette classe est désormais obsolète car le modèle de données sous-jacent pour lequel cette passe est convertie a été obsolète et sera supprimé dans Instruction.condition à partir duquel cette passe est convertie est obsolète et sera supprimée à l'adresse 2.0.0.

  • Fournir des portes personnalisées par le biais de l'argument basis_gates est obsolète à la fois pour transpile() et generate_preset_pass_manager(). Cette fonctionnalité sera supprimée dans Qiskit 2.0. Les portes personnalisées sont toujours prises en charge dans le modèle Target et peuvent être fournies par l'intermédiaire de l'argument target . On peut construire une Target à partir de zéro ou utiliser la méthode Target.from_configuration() avec l'argument custom_name_mapping . Par exemple :

    from qiskit.circuit.library import XGate
    from qiskit.transpiler.target import Target
    
    basis_gates = ["my_x", "cx"]
    custom_name_mapping = {"my_x": XGate()}
    target = Target.from_configuration(
        basis_gates=basis_gates, num_qubits=2, custom_name_mapping=custom_name_mapping
    )

  • Dans le cadre de la dépréciation du package Qiskit Pulse, les aspects liés à Pulse dans la qiskit.transpiler.Target classe sont en cours de dépréciation. Exemples :


    De plus, les passes suivantes du transpiler sont également en cours de dépréciation :

  • L'argument inst_map dans generate_preset_pass_manager(), from_configuration(), PassManagerConfig et generate_scheduling() est obsolète.

  • L'argument calibration dans les méthodes d'initialisation InstructionProperties() dans les méthodes d'initialisation est obsolète.

  • Les éléments suivants transpile() et generate_preset_pass_manager() sont dépréciés au profit de la définition d'un argument personnalisé Target: instruction_durations, timing_constraints, et backend_properties. Ces arguments peuvent être utilisés pour construire une cible avec Target.from_configuration():

    Target.from_configuration(
         ...
         backend_properties = backend_properties,
         instruction_durations = instruction_durations,
         timing_constraints = timing_constraints
    )
  • La méthode PassManagerConfig.from_backend() cessera de prendre en charge les entrées de type BackendV1 dans le paramètre backend dans une version ultérieure, au plus tôt à l'adresse 2.0. BackendV1 est obsolète et les implémentations devraient passer à BackendV2.

Divers. Dépréciations

Corrections des erreurs

  • Correction d'une régression de performance dans QuantumCircuit.assign_parameters() introduite dans Qiskit 1.2.0 lors de l'appel de la méthode dans une boucle serrée, qui faisait que seul un petit nombre de paramètres d'un circuit fortement paramétré était lié à chaque itération. Si possible, il est encore plus performant d'appeler assign_parameters() qu'une seule fois, avec toutes les affectations en même temps, car cela réduit la proportion de temps consacrée à la normalisation de l'entrée et à la vérification des erreurs.

  • Pour BasicSimulatorl'entrée basis_gates de l'instance de configuration renvoyée par la méthode configuration() est désormais une liste et non plus une instance dict_keys , ce qui correspond au type attendu et permet de copier en profondeur l'instance de configuration.

  • Correction d'un problème avec DAGCircuit.apply_operation_back() et DAGCircuit.apply_operation_front() où auparavant, si vous mettiez un objet Clbit à l'entrée de l'argument qargs , il était accepté silencieusement. Cette erreur a été corrigée de manière à ce que la différence de type soit correctement identifiée et qu'une exception soit levée.

  • Correction d'un décorateur manquant dans C3SXGate qui le faisait échouer si Gate.to_matrix() était appelé. La matrice de la porte est maintenant retournée comme prévu.

  • Correction d'un bogue dans QuantumCircuit.assign_parameters()qui se produisait lors de l'affectation de paramètres à des portes standard dont la définition a déjà été déclenchée. Dans ce cas, les nouvelles valeurs n'ont pas été correctement propagées dans les instances de la porte. Alors que le circuit lui-même était toujours compilé comme prévu, l'inspection des opérations individuelles montrait toujours l'ancien paramètre.

    Par exemple :

    from qiskit.circuit.library import EfficientSU2
    
    circuit = EfficientSU2(2, flatten=True)
    circuit.assign_parameters([1.25] * circuit.num_parameters, inplace=True)
    print(circuit.data[0].operation.params)  # would print θ[0] instead of 1.25

    Correction #13478.

  • Correction d'un bug avec l'enchevêtrement "circular" et "sca" pour les circuits et leurs dérivés NLocal et ses dérivés. Pour les blocs d'intrication de plus de 2 qubits, l'intrication circulaire manquait auparavant de certaines connexions. Par exemple, pour 4 qubits et une taille de bloc de 3, le code précédemment utilisé :

    [(2, 3, 0), (0, 1, 2), (1, 2, 3)]

    mais ajoute maintenant correctement les connexions (3, 0, 1) , c'est-à-dire :

    [(2, 3, 0), (3, 0, 1), (0, 1, 2), (1, 2, 3)]

    Ainsi, les enchevêtrements "circular" et "sca" utilisent des blocs d'enchevêtrement num_qubits par couche.

  • Ajouter d'autres portes de Clifford à la passe de CollectCliffords transpiler pass. En particulier, nous avons ajouté les portes ECRGate, DCXGate, iSwapGate, SXGate et SXdgGate à cette passe de transpileur.

  • Correction d'un bug dans QuantumCircuit.decompose() où les objets qui pouvaient être synthétisés avec HighLevelSynthesis étaient d'abord synthétisés puis décomposés immédiatement (c'est-à-dire qu'ils étaient décomposés deux fois au lieu d'une). Cela a affecté des portes telles que MCXGate ou Cliffordentre autres.

  • Correction d'un bogue dans QuantumCircuit.decompose()où les objets de haut niveau sans définition n'étaient pas décomposés s'ils étaient explicitement définis via l'argument "gates_to_decompose" . Par exemple, l'opération suivante n'effectuait pas de décomposition auparavant, mais elle fonctionne à présent comme prévu :

    from qiskit import QuantumCircuit
    from qiskit.quantum_info import Clifford
    from qiskit.transpiler.passes import Decompose
    
    cliff = Clifford(HGate())
    circuit = QuantumCircuit(1)
    circuit.append(cliff, [0])
    
    decomposed = Decompose(gates_to_decompose=["clifford"])(circuit)
  • Auparavant, la passe de HighLevelSynthesis synthétisait une instruction pour laquelle un plugin de synthèse est disponible, que l'instruction soit déjà supportée par la cible ou qu'elle fasse partie de l'instruction explicitement passée basis_gates. Ce comportement est désormais corrigé, de sorte que ces instructions déjà prises en charge ne sont plus synthétisées.

  • La passe de transpilation InverseCancellation va maintenant rechercher dans ControlFlowOp les opérations présentes dans un QuantumCircuit. Auparavant, le passeport ignorait les paires de portes inversées à l'intérieur des blocs de flux de contrôle qui auraient pu être annulés. Voir #13437 pour plus de détails.

  • Correction d'un bogue dans Isometry dû à une assertion inutile, qui conduisait à une erreur dans UnitaryGate.control() lorsque UnitaryGate avait plus de deux qubits.

  • L'attribut QuantumCircuit.parameters sera désormais correctement vide lors de l'utilisation de QuantumCircuit.copy_empty_like() sur un circuit paramétrique. Auparavant, un cache interne était copié sans être invalidé. Correction #12617.

  • QuantumCircuit.depth() traitera désormais correctement les opérations qui n'ont pas d'opérandes, telles que GlobalPhaseGate.

  • QuantumCircuit.depth() comptera désormais les variables et les clbits utilisés dans les expressions en temps réel dans le cadre du calcul de la profondeur.

  • Corrige le passage du SolovayKitaev lors du chargement des approximations de base à partir d'un fichier .npy existant. Auparavant, le chargement d'une approximation stockée qui permettait des réductions supplémentaires (par exemple, en raison d'annulations de portes) pouvait entraîner un échec de l'exécution. En outre, la différence de phase globale du produit de porte U(2) et de la représentation SO(3) a été perdue au cours d'une procédure de sauvegarde et de rechargement. Corrections Qiskit/qiskit#12576.

  • Correction d'un bug lorsque SparsePauliOp.paulis est défini comme étant un PauliList avec une phase non nulle, où les appels ultérieurs à plusieurs méthodes SparsePauliOp produisaient des résultats incorrects. Maintenant, lorsque SparsePauliOp.paulis est réglé sur un PauliList avec une phase non nulle, la phase est absorbée dans SparsePauliOp.coeffset la phase de l'entrée PauliList est mise à zéro.

  • Correction d'un bogue dans qiskit.visualization.pulse_v2.interface.draw qui ne dessinait pas les horaires de pouls lorsque la fonction de dessin était appelée avec un argument BackendV2 en argument. Comme le backend V2 ne signale pas les fréquences des canaux matériels, le dessin généré indiquera "no freq" (pas de fréquence) sous l'étiquette de chaque canal.

  • Correction d'un problème avec dag_drawer() et DAGCircuit.draw() lors de la visualisation d'une instance DAGCircuit contenant des Var pour lesquels le visualiseur soulevait une exception. Ce comportement a été corrigé et la visualisation attendue sera générée.

  • La passe VF2Layout lèverait une exception si on lui fournissait une instance Target sans contraintes de connectivité. Ce serait le cas pour les cibles d'Aer 0.13. Le problème est maintenant corrigé.

  • Correction d'une erreur lors de l'appel de la méthode Gate.repeat(). Voir #11990 pour plus de détails.

  • Correction d'un bogue qui faisait que Statevector.expectation_value() de produire des résultats incorrects pour l'opérateur d'identité lorsque le vecteur d'état n'était pas normalisé.

  • Le constructeur GenericBackendV2 permettait de créer des backends malformés parce qu'il acceptait des portes de base qui ne pouvaient pas être allouées dans la taille de backend spécifiée. En d'autres termes, un backend avec un seul qubit ne doit pas accepter une base avec des portes à deux qubits.

  • ParameterExpression a été mis à jour de manière à ce que les instances entièrement liées qui se comparent à des instances des types numériques intégrés de Python (comme float et int) aient également des valeurs de hachage qui correspondent à celles des autres instances. Cette modification garantit que ces types peuvent être utilisés de manière interchangeable comme clés de dictionnaire. Voir #12488.

  • L'analyseur OpenQASM 2 (qiskit.qasm2) peut maintenant gérer les conditionnelles avec des entiers qui ne tiennent pas dans un entier de 64 bits. Correction #12773.

  • Les portes personnalisées (celles qui découlent d'une déclaration gate ) dans les programmes importés de OpenQASM 2 auront désormais une mise en œuvre Gate.to_matrix() implémentation. Auparavant, ils n'avaient pas de définition matricielle, ce qui signifie que les allers-retours sur le site OpenQASM 2 pouvaient perdre inutilement la possibilité de dériver la matrice de la porte. Notez cependant que la matrice est calculée en trouvant récursivement les matrices des définitions des portes internes, comme le fait Operator ce qui peut être moins performant qu'avant l'aller-retour.

  • Précédemment, DAGCircuit.replace_block_with_op() permettait de placer une opération n-qubit sur un bloc de m qubits, laissant le DAG dans un état invalide. Ce comportement a été corrigé, et la tentative soulèvera une erreur de type DAGCircuitError.

  • Fixe Operator.power() lorsqu'elle est appelée avec des puissances non entières sur une matrice dont la forme de Schur n'est pas diagonale (par exemple, la plupart des matrices non unitaires).

  • Operator.power() renverra désormais de manière plus fiable la valeur principale attendue d'une puissance de matrice fractionnaire d'une matrice unitaire avec une valeur propre 1-1. C'est délicat en général, car les effets d'arrondi en virgule flottante peuvent faire en sorte qu'une matrice ait une valeur propre du côté négatif de la coupure de la branche (même si sa relation mathématique exacte ne le ferait pas), et l'imprécision dans divers appels BLAS peut faussement trouver le mauvais côté de la coupure de la branche.

    Operator.power() déplace maintenant l'emplacement de la coupure de branche pour les puissances de matrice à une petite rotation complexe de 1-1. Cela ne résout pas le problème, mais le déplace à un endroit où il est beaucoup moins susceptible d'être perceptible pour les types d'opérateurs qui apparaissent habituellement. Utilisez le nouveau paramètre branch_cut_rotation pour mieux contrôler cela.

    Voir #13305.

  • Correction d'un non-déterminisme basé sur le processus dans SparsePauliOp.to_matrix(). L'ordre exact des opérations en virgule flottante dans la sommation variait auparavant d'un processus à l'autre, mais il sera désormais identique entre les différentes invocations du même script. Voir #13413.

  • Target.has_calibration() a été mis à jour afin qu'il ne soulève pas d'exception pour une instruction qui a été ajoutée à la cible avec None pour ses propriétés d'instruction. Corrige #12525.

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