Skip to main content
IBM Quantum Platform

Notes de publication de Qiskit 0.35


0.35.0

Terra 0.20.0

Prélude

Les points forts de la version Qiskit Terra 0.20.0 sont les suivants :

  • L'introduction de modules multithreads écrits en Rust pour accélérer les performances de certaines parties de Qiskit Terra et améliorer la mise à l'échelle avec un plus grand nombre de qubits. Cependant, lors de la construction de Qiskit à partir des sources, un compilateur Rust est maintenant nécessaire.
  • Plus de support natif pour travailler avec un Target dans le transpileur. Plusieurs passes permettent maintenant de travailler directement avec un objet Target ce qui rend le transpileur plus robuste dans les types de backends qu'il peut cibler.
  • L'introduction du qiskit.primitives module. Ces API offrent différents niveaux d'abstraction pour le calcul des résultats d'intérêt à partir de QuantumCircuit et l'utilisation de backends. Par exemple, l'interface BaseEstimator définit une interface abstraite permettant d'estimer la valeur attendue d'un observable. Cela peut ensuite être utilisé pour construire des algorithmes et des applications de plus haut niveau qui sont construits en utilisant l'estimation des valeurs d'espérance sans avoir à se soucier de la mise en œuvre du calcul de la valeur d'espérance. Ce découplage permet à la mise en œuvre d'améliorer la vitesse et la qualité tout en respectant l'interface abstraite définie. De même, l'outil BaseSampler calcule des distributions de quasi-probabilité à partir de mesures de circuits. D'autres primitives seront introduites à l'avenir.

Cette version ne prend plus en charge Python 3.6. Avec cette version, Python 3.7 à Python 3.10 sont nécessaires.

Nouvelles fonctions

  • Ajout d'une nouvelle méthode de construction pour la classe Operator pour créer une nouvelle classe, Operator.from_circuit() pour créer un nouvel objet Operator à partir d'un QuantumCircuit. Alors que cela était possible normalement en utilisant le constructeur par défaut, la méthode Operator.from_circuit() fournit des options supplémentaires pour ajuster la façon dont l'opérateur est créé. Cela permet principalement de permuter l'ordre des qubits sur la base d'un ensemble Layout. Par exemple :

    from qiskit.circuit import QuantumCircuit
    from qiskit import transpile
    from qiskit.transpiler import CouplingMap
    from qiskit.quantum_info import Operator
    
    circuit = QuantumCircuit(3)
    circuit.h(0)
    circuit.cx(0, 1)
    circuit.cx(1, 2)
    
    cmap = CouplingMap.from_line(3)
    out_circuit = transpile(circuit, initial_layout=[2, 1, 0], coupling_map=cmap)
    operator = Operator.from_circuit(out_circuit)

    la variable operator aura les qubits permutés en fonction de la disposition, de sorte qu'elle sera identique à ce qui est renvoyé par Operator(circuit) avant la transpilation.

  • Ajout d'une nouvelle méthode DAGCircuit.copy_empty_like() à la classe DAGCircuit classe. Cette méthode est utilisée pour créer une nouvelle copie d'un objet existant avec la même structure mais sans aucune instruction DAGCircuit existant avec la même structure mais vide de toute instruction. Cette méthode est identique à la méthode privée _copy_circuit_metadata(), mais elle fait désormais partie de l'API publique de la classe.

  • Les classes de faux backend et de faux fournisseurs qui étaient auparavant disponibles sur qiskit.test.mock sont désormais également accessibles dans un nouveau module : qiskit.providers.fake_provider. Ce nouveau module remplace le module précédent qiskit.test.mock qui sera supprimé dans Qiskit 0.21.0.

  • Ajout d'une nouvelle classe de porte, LinearFunctionqui encode efficacement une fonction linéaire (c'est-à-dire une fonction qui peut être représentée par une séquence de CXGate et SwapGate ).

  • Ajout d'une nouvelle passe de transposition CollectLinearFunctions qui collecte des blocs de CXGate et SwapGate dans un circuit, et remplace chaque bloc par une porte LinearFunction porte.

  • Ajout d'une nouvelle passe de transposition LinearFunctionsSynthesis qui synthétise toutes les portes LinearFunction en utilisant l' algorithme Patel-Markov-Hayes. Combiné avec le passage du transpondeur, il permet de collecter des blocs consécutifs CollectLinearFunctions il est possible de collecter des blocs de données consécutifs CXGate et SwapGate dans un circuit, et de les resynthétiser en utilisant l' algorithme de Patel-Markov-Hayes.

  • Ajout d'une nouvelle passe de transpilation LinearFunctionsToPermutations qui remplace un LinearFunction par un circuit Permutation chaque fois que c'est possible.

  • FlowController (telles que ConditionalController) peuvent désormais être imbriquées dans une instance PassManager lors de l'utilisation de la méthode PassManager.append() méthode. Cela permet d'utiliser une logique imbriquée pour contrôler l'exécution des passes dans le système PassManager. Par exemple :

    from qiskit.transpiler import ConditionalController, PassManager
    from qiskit.transpiler.passes import (
      BasisTranslator, GatesInBasis, Optimize1qGatesDecomposition, FixedPoint, Depth
    )
    from qiskit.circuit.equivalence_library import SessionEquivalenceLibrary as sel
    
    pm = PassManager()
    
    def opt_control(property_set):
        return not property_set["depth_fixed_point"]
    
    def unroll_condition(property_set):
        return not property_set["all_gates_in_basis"]
    
    depth_check = [Depth(), FixedPoint("depth")]
    opt = [Optimize1qGatesDecomposition(['rx', 'ry', 'rz', 'rxx'])]
    unroll = [BasisTranslator(sel, ['rx', 'ry', 'rz', 'rxx'])]
    unroll_check = [GatesInBasis(['rx', 'ry', 'rz', 'rxx'])]
    flow_unroll = [ConditionalController(unroll, condition=unroll_condition)]
    
    pm.append(depth_check + opt + unroll_check + flow_unroll, do_while=opt_control)

    L'objet pm PassManager n'exécutera la passe BasisTranslator (dans l'étape unroll ) à chaque itération de la boucle si la condition unroll_condition est remplie.

  • Les constructeurs pour les ZFeatureMap et ZZFeatureMap disposent d'un nouveau mot-clé parameter_prefix. Ce nouvel argument est utilisé pour définir le préfixe des paramètres du circuit d'encodage des données. Par exemple :

    from qiskit.circuit.library import ZFeatureMap
    
    feature_map = ZFeatureMap(feature_dimension=4, parameter_prefix="my_prefix")
    feature_map.decompose().draw('mpl')

    le circuit généré ZFeatureMap le circuit généré a préfixé tous ses paramètres internes avec le préfixe "my_prefix".

  • La passe de TemplateOptimization le transpiler pass peut maintenant travailler avec des Gate qui ont des paramètres ParameterExpression paramètres. Un exemple illustratif de l'utilisation de Parameteravec TemplateOptimization est le suivant :

    from qiskit import QuantumCircuit, transpile, schedule
    from qiskit.circuit import Parameter
    
    from qiskit.transpiler import PassManager
    from qiskit.transpiler.passes import TemplateOptimization
    
    # New contributions to the template optimization
    from qiskit.transpiler.passes.calibration import RZXCalibrationBuilder, rzx_templates
    
    from qiskit.test.mock import FakeCasablanca
    backend = FakeCasablanca()
    
    phi = Parameter('φ')
    
    qc = QuantumCircuit(2)
    qc.cx(0,1)
    qc.p(2*phi, 1)
    qc.cx(0,1)
    print('Original circuit:')
    print(qc)
    
    pass_ = TemplateOptimization(**rzx_templates.rzx_templates(['zz2']))
    qc_cz = PassManager(pass_).run(qc)
    print('ZX based circuit:')
    print(qc_cz)
    
    # Add the calibrations
    pass_ = RZXCalibrationBuilder(backend)
    cal_qc = PassManager(pass_).run(qc_cz.bind_parameters({phi: 0.12}))
    
    # Transpile to the backend basis gates
    cal_qct = transpile(cal_qc, backend)
    qct = transpile(qc.bind_parameters({phi: 0.12}), backend)
    
    # Compare the schedule durations
    print('Duration of schedule with the calibration:')
    print(schedule(cal_qct, backend).duration)
    print('Duration of standard with two CNOT gates:')
    print(schedule(qct, backend).duration)

    sorties

    Original circuit:
    
    q_0: ──■──────────────■──
         ┌─┴─┐┌────────┐┌─┴─┐
    q_1: ┤ X ├┤ P(2*φ) ├┤ X ├
         └───┘└────────┘└───┘
    ZX based circuit:
                                             ┌─────────────┐            »
    q_0: ────────────────────────────────────┤0            ├────────────»
         ┌──────────┐┌──────────┐┌──────────┐│  Rzx(2.0*φ) │┌──────────┐»
    q_1:Rz(-π/2) ├┤ Rx(-π/2) ├┤ Rz(-π/2) ├┤1            ├┤ Rx(-2*φ) ├»
         └──────────┘└──────────┘└──────────┘└─────────────┘└──────────┘»
    «
    «q_0: ────────────────────────────────────────────────
    «     ┌──────────┐┌──────────┐┌──────────┐┌──────────┐
    «q_1:Rz(-π/2) ├┤ Rx(-π/2) ├┤ Rz(-π/2) ├┤ P(2.0*φ)
    «     └──────────┘└──────────┘└──────────┘└──────────┘
    Duration of schedule with the calibration:
    1600
    Duration of standard with two CNOT gates:
    6848
  • Les DAGOpNode, DAGInNode et DAGOutNode définissent maintenant une méthode personnalisée __repr__ qui produit une représentation. Selon la documentation de Python, la sortie est une représentation sous forme de chaîne qui est à peu près équivalente à la chaîne de Python utilisée pour créer un objet équivalent.

  • Les performances de la méthode SparsePauliOp.simplify() a été grandement améliorée en remplaçant l'utilisation de numpy.unique pour calculer les éléments uniques d'un tableau par une nouvelle fonction similaire implémentée en Rust qui ne trie pas le tableau au préalable.

  • Ajout d'une nouvelle méthode equiv() à la classe SparsePauliOp pour tester l'équivalence d'un SparsePauliOp avec un autre objet SparsePauliOp objet. Contrairement à l'opérateur == qui compare les opérateurs par élément, equiv() compare si deux opérateurs sont équivalents ou non. Par exemple :

    op = SparsePauliOp.from_list([("X", 1), ("Y", 1)])
    op2 = SparsePauliOp.from_list([("X", 1), ("Y", 1), ("Z", 0)])
    op3 = SparsePauliOp.from_list([("Y", 1), ("X", 1)])
    
    print(op == op2)  # False
    print(op == op3)  # False
    print(op.equiv(op2))  # True
    print(op.equiv(op3))  # True
  • Ajout de nouvelles fausses classes de backend à partir d'instantanés des systèmes IBM Quantum basés sur l'interface BackendV2 et a fourni un Target pour chaque backend. BackendV2 de tous les backends existants sont ajoutées, à l'exception de trois anciens backends FakeRueschlikon, FakeTenerife et FakeTokyo qui ne disposent pas de fichiers snapshots, nécessaires à la création d'une nouvelle classe de backend basé sur BackendV2.

    Ces nouveaux backends V2 permettront de tester et de développer de nouvelles fonctionnalités introduites par BackendV2 et Target telles que l'amélioration du transpileur.

  • Ajout d'une nouvelle classe de porte XXMinusYYGate à la bibliothèque de circuits (qiskit.circuit.library) pour l'interaction XX-YY. Cette porte peut être utilisée pour implémenter la porte bSwap et ses pouvoirs. Elle apparaît également dans la simulation de modèles fermioniques supraconducteurs.

  • Ajout d'une nouvelle classe de porte, XXPlusYYGateà la bibliothèque de circuits (qiskit.circuit.library). Cette porte est une interaction XX+YY paramétrée à 2 qubits, également connue sous le nom de porte XY, et est basée sur la porte décrite dans https://arxiv.org/abs/1912.04424.

  • Les faux backends FakeBogota, FakeManila, FakeRome, et FakeSantiago qui se trouvent dans le module qiskit.providers.fake_provider peuvent maintenant être utilisés comme backends dans les expériences Pulse puisqu'ils incluent maintenant un backend PulseDefaults créé à partir d'un instantané des propriétés de la machine IBM Quantum équivalente.

  • La passe ConsolidateBlocks a un nouveau mot-clé argument sur son constructeur, target. Cet argument est utilisé pour spécifier un objet Target représentant la cible de compilation pour la passe. S'il est spécifié, il remplace le kwarg basis_gates . Si une cible est spécifiée, le pass respectera les portes et les qubits pour les instructions définies dans la cible Target lorsqu'il décidera des portes à consolider en unitaire.

  • La classe Target dispose d'une nouvelle méthode, instruction_supported() qui permet d'interroger la cible pour savoir si une instruction (la combinaison d'une opération et du ou des qubits sur lesquels elle est exécutée) est prise en charge par le backend modélisé par la classe Target.

  • Ajout d'un nouveau kwarg, metadata_serializer, à la fonction qpy.dump() pour spécifier une sous-classe personnalisée de JSONEncoder à utiliser lors de la sérialisation de l'attribut QuantumCircuit.metadata et un double kwarg, metadata_deserializer , à la fonction qpy.load() pour spécifier une sous-classe JSONDecoder . Par défaut, les boutons dump() et load() tenteront de sérialiser et de désérialiser JSON avec l'encodeur et le décodeur json par défaut de la stdlib. Puisque QuantumCircuit.metadata peut contenir n'importe quel dictionnaire Python, même ceux dont le contenu n'est pas sérialisable en JSON par l'encodeur par défaut, il en résultera des circuits qui ne pourront pas être sérialisés. Le nouvel argument metadata_serializer pour dump() permet aux utilisateurs de spécifier un JSONEncoder personnalisé qui sera utilisé avec l'appel interne json.dump() pour sérialiser le QuantumCircuit.metadata dictionnaire. Il peut ensuite être associé au nouvel argument metadata_deserializer de la fonction qpy.load() pour décoder ces encodages JSON personnalisés. Si metadata_serializer est spécifié sur dump() mais que metadata_deserializer n'est pas spécifié sur load() le QPY sera chargé, mais les métadonnées du circuit risquent de ne pas être entièrement reconstituées.

    Par exemple, si vous voulez définir une sérialisation personnalisée pour les métadonnées et la charger ensuite, vous pouvez faire quelque chose comme :

    from qiskit.qpy import dump, load
    from qiskit.circuit import QuantumCircuit, Parameter
    import json
    import io
    
    class CustomObject:
        """Custom string container object."""
    
        def __init__(self, string):
            self.string = string
    
        def __eq__(self, other):
            return self.string == other.string
    
    class CustomSerializer(json.JSONEncoder):
        """Custom json encoder to handle CustomObject."""
    
        def default(self, o):
            if isinstance(o, CustomObject):
                return {"__type__": "Custom", "value": o.string}
            return json.JSONEncoder.default(self, o)
    
    class CustomDeserializer(json.JSONDecoder):
        """Custom json decoder to handle CustomObject."""
    
        def __init__(self, *args, **kwargs):
            super().__init__(*args, object_hook=self.object_hook, **kwargs)
    
        def object_hook(self, o):
            """Hook to override default decoder."""
            if "__type__" in o:
                obj_type = o["__type__"]
                if obj_type == "Custom":
                    return CustomObject(o["value"])
            return o
    
    theta = Parameter("theta")
    qc = QuantumCircuit(2, global_phase=theta)
    qc.h(0)
    qc.cx(0, 1)
    qc.measure_all()
    circuits = [qc, qc.copy()]
    circuits[0].metadata = {"key": CustomObject("Circuit 1")}
    circuits[1].metadata = {"key": CustomObject("Circuit 2")}
    with io.BytesIO() as qpy_buf:
        dump(circuits, qpy_buf, metadata_serializer=CustomSerializer)
        qpy_buf.seek(0)
        new_circuits = load(qpy_buf, metadata_deserializer=CustomDeserializer)
  • La passe DenseLayout a un nouveau mot-clé argument sur son constructeur, target. Cet argument est utilisé pour spécifier un objet Target représentant la cible de compilation pour la passe. S'il est spécifié, il remplace les autres arguments du constructeur, coupling_map et backend_prop.

  • La classe Target a une nouvelle méthode, operation_names_for_qargs(). Cette méthode est utilisée pour obtenir les noms des opérations (c'est-à-dire la clé de consultation dans la cible) pour les opérations sur un tuple qargs donné.

  • Un nouveau laissez-passer DynamicalDecouplingPadding a été ajouté au module qiskit.transpiler.passes module. Ce nouveau laissez-passer remplace le laissez-passer existant DynamicalDecoupling existante pour fonctionner avec le nouveau flux de travail d'ordonnancement dans le transpondeur. Il s'agit d'une sous-classe de la passe BasePadding et dépend de l'exécution préalable des passes d'ordonnancement et d'analyse de l'alignement dans le cadre d'un processus d'ordonnancement et d'analyse de l'alignement PassManager. Cette nouvelle passe peut prendre un argument pulse_alignment qui représente une contrainte matérielle pour la synchronisation du début de la forme d'onde. L'espacement entre les portes comprenant une séquence de découplage dynamique est maintenant ajusté pour satisfaire cette contrainte afin que le circuit puisse être exécuté sur du matériel avec la contrainte. Cette valeur se trouve généralement à l'adresse BackendConfiguration.timing_constraints. En outre, la passe dispose également d'une option extra_slack_distribution qui permet de contrôler comment distribuer le mou supplémentaire lorsque la durée de la séquence de découplage dynamique créée est plus courte que le temps d'inactivité de votre circuit que vous souhaitez remplir avec la séquence. La valeur par défaut est middle , ce qui est identique au comportement conventionnel. La nouvelle stratégie split_edges répartit uniformément le jeu supplémentaire entre le début et la fin de la séquence, au lieu de l'ajouter à l'intervalle au milieu de la séquence. Cela pourrait permettre une meilleure annulation du bruit, en particulier lorsque pulse_alignment > 1.

  • La classe Z2Symmetries expose maintenant les tolérances de seuil utilisées pour couper les petites parties réelles et imaginaires des coefficients. Cela permet de contrôler la manière dont les coefficients de l'opérateur conique sont simplifiés. Par exemple :

    from qiskit.opflow import Z2Symmetries
    from qiskit.quantum_info import Pauli
    
    z2_symmetries = Z2Symmetries(
        symmetries=[Pauli("IIZI"), Pauli("IZIZ"), Pauli("ZIII")],
        sq_paulis=[Pauli("IIXI"), Pauli("IIIX"), Pauli("XIII")],
        sq_list=[1, 0, 3],
        tapering_values=[1, -1, -1],
        tol=1e-10,
    )

    Par défaut, les coefficients sont hachés avec une tolérance de tol=1e-14.

  • Ajout d'une méthode chop() à la classe SparsePauliOp qui tronque les parties réelles et imaginaires des coefficients individuellement. Cette méthode est différente de celle qui consiste à ne supprimer un coefficient que si sa valeur absolue est proche de 0 SparsePauliOp.simplify() qui ne supprime un coefficient que si sa valeur absolue est proche de 0. Par exemple :

    >>> from qiskit.quantum_info import SparsePauliOp
    >>> op = SparsePauliOp(["X", "Y", "Z"], coeffs=[1+1e-17j, 1e-17+1j, 1e-17])
    >>> op.simplify()
    SparsePauliOp(['X', 'Y'],
                  coeffs=[1.e+00+1.e-17j, 1.e-17+1.e+00j])
    >>> op.chop()
    SparsePauliOp(['X', 'Y'],
                  coeffs=[1.+0.j, 0.+1.j])

    Notez que la méthode chop ne cumule pas les coefficients d'un même Paulis, par exemple

    >>> op = SparsePauliOp(["X", "X"], coeffs=[1+1e-17j, 1e-17+1j)
    >>> op.chop()
    SparsePauliOp(['X', 'X'],
                  coeffs=[1.+0.j, 0.+1.j])
  • Ajout d'un nouveau kwarg, target, au constructeur de la passe de GatesInBasis transpiler pass. Ce nouvel argument peut être utilisé pour spécifier optionnellement un objet Target qui représente le backend. Lorsqu'il est défini, ce paramètre Target sera utilisé pour déterminer si un DAGCircuit contient des portes en dehors de l'ensemble de base et l'argument basis_gates ne sera pas utilisé.

  • Ajout d'une prise en charge partielle de l'exécution sur les plates-formes ppc64le et s390x Linux. Cette version commencera à publier des binaires précompilés pour les plateformes ppc64le et s390x Linux sur toutes les versions de Python. Cependant, contrairement aux autres plateformes supportées, toutes les dépendances en amont de Qiskit ne supportent pas encore ces plateformes. Un compilateur C/C++ peut donc être nécessaire pour construire et installer ces dépendances et un simple pip install qiskit-terra avec un environnement Python fonctionnel ne sera pas suffisant pour installer Qiskit. En outre, ces mêmes contraintes nous empêchent de tester les roues précompilées avant de les publier, de sorte que les mêmes garanties concernant la prise en charge des plates-formes qui existent pour les autres plates-formes ne s'appliquent pas ici.

  • Les Gradient et QFI peuvent maintenant calculer la partie imaginaire des gradients de la valeur d'espérance. En cas d'utilisation d'une base de mesure différente, c'est-à-dire -Y au lieu de Z, nous pouvons mesurer la partie imaginaire des gradients La base de mesure peut être définie à l'aide de l'argument aux_meas_op .

    Pour les gradients, aux_meas_op = Z calcule 0.5Re[(⟨ψ(ω)|)O(θ)|dωψ(ω)〉] et aux_meas_op = -Y calcule 0.5Im[(⟨ψ(ω)|)O(θ)|dωψ(ω)〉]. Pour les QFI, aux_meas_op = Z calcule 4Re[(dω⟨<ψ(ω)|)(dω|ψ(ω)〉)] et aux_meas_op = -Y calcule 4Im[(dω⟨<ψ(ω)|)(dω|ψ(ω)〉)]. Par exemple :

    from qiskit import QuantumRegister, QuantumCircuit
    from qiskit.opflow import CircuitStateFn, Y
    from qiskit.opflow.gradients.circuit_gradients import LinComb
    from qiskit.circuit import Parameter
    
    a = Parameter("a")
    b = Parameter("b")
    params = [a, b]
    
    q = QuantumRegister(1)
    qc = QuantumCircuit(q)
    qc.h(q)
    qc.rz(params[0], q[0])
    qc.rx(params[1], q[0])
    op = CircuitStateFn(primitive=qc, coeff=1.0)
    
    aux_meas_op = -Y
    
    prob_grad = LinComb(aux_meas_op=aux_meas_op).convert(operator=op, params=params)
  • La classe InstructionDurations permet désormais de travailler avec les paramètres d'une instruction. Chaque entrée d'un objet InstructionDurations consiste désormais en un tuple de (inst_name, qubits, duration, parameters, unit). Cela permet à un InstructionDurations de définir les durées d'une instruction pour une certaine valeur de paramètre afin de tenir compte des différentes durées pour différentes valeurs de paramètre sur une instruction qui prend un paramètre numérique.

  • Ajout d'une nouvelle valeur pour l'argument du mot-clé style dans la fonction de dessinateur de circuits circuit_drawer() et QuantumCircuit.draw() de la fonction et de la méthode "tiroir", iqx_dark. Lorsque style est configuré pour iqx_dark avec le tiroir mpl , la visualisation de sortie utilisera une palette de couleurs similaire à la palette de couleurs en mode sombre utilisée par le compositeur IBM Quantum. Par exemple :

    from qiskit.circuit import QuantumCircuit
    from matplotlib.pyplot import show
    
    circuit = QuantumCircuit(2)
    circuit.h(0)
    circuit.cx(0, 1)
    circuit.p(0.2, 1)
    
    circuit.draw("mpl", style="iqx-dark")
  • Plusieurs vérificateurs de dépendances paresseuses ont été ajoutés au nouveau module qiskit.utils.optionalsqui peut être utilisé pour vérifier si certaines fonctionnalités de Qiskit sont disponibles. Par exemple, vous pouvez demander si Qiskit a détecté la présence de matplotlib en demandant if qiskit.utils.optionals.HAS_MATPLOTLIB. Ces objets ne tentent d'importer leurs dépendances que lorsqu'ils sont interrogés, de sorte que vous pouvez les utiliser dans le code d'exécution sans affecter le temps d'importation.

  • Le temps d'importation pour qiskit a été considérablement amélioré, en particulier pour ceux qui ont installé de nombreuses dépendances optionnelles de Qiskit Terra.

  • La fonction marginal_counts() permet désormais de marginaliser le champ memory d'un objet d'entrée Result d'un objet. Par exemple, si l'argument d'entrée result est un objet qiskit Result obtenu à partir d'une mesure de 4 qubits, nous pouvons marginaliser le premier qubit avec :

    print(result.results[0].data.memory)
    marginal_result = marginal_counts(result, [0])
    print(marginal_result.results[0].data.memory)

    La sortie est la suivante :

    ['0x0', '0x1', '0x2', '0x3', '0x4', '0x5', '0x6', '0x7']
    ['0x0', '0x1', '0x0', '0x1', '0x0', '0x1', '0x0', '0x1']
  • Les éléments internes de l'algorithme StochasticSwap ont été réimplémentés pour être multithreadés et sont maintenant écrits dans le langage de programmation Rust au lieu de Cython. Cela permet d'augmenter considérablement les performances du compilateur et, par extension, celles de la passe transpile() lorsqu'il est exécuté avec optimization_level 0, 1 et 2. Par défaut, la passe utilisera jusqu'au nombre de CPU logiques de votre système local, mais vous pouvez contrôler le nombre de threads utilisés par la passe en fixant la variable d'environnement RAYON_NUM_THREADS à une valeur entière. Par exemple, l'adresse RAYON_NUM_THREADS=4 permet d'exécuter le programme StochasticSwap avec 4 threads.

  • Une nouvelle variable d'environnement QISKIT_FORCE_THREADS est disponible pour permettre aux utilisateurs de contrôler directement si les parties du code de Qiskit potentiellement multithreadées s'exécuteront dans plusieurs threads. Actuellement, cela n'est utilisé que par la passe de transposition StochasticSwap mais il sera probablement utilisé par d'autres parties de Qiskit dans le futur. Lorsque cette variable ENV est définie à TRUE , tout code multithread dans Qiskit Terra utilisera toujours plusieurs threads, indépendamment de toute autre condition d'exécution qui aurait pu entraîner l'utilisation d'une variante à un seul thread. Par exemple, en StochasticSwap si la passe est exécutée dans le cadre d'un appel de transpile() avec > 1 circuit qui est exécuté en parallèle avec multiprocessing via parallel_map() l'outil StochasticSwap n'utilisera pas de threads multiples afin d'éviter une sursouscription potentielle des ressources de l'unité centrale. Cependant, si vous souhaitez utiliser plusieurs threads dans la passe ainsi que plusieurs processus, vous pouvez définir QISKIT_FORCE_THREADS=TRUE.

  • De nouvelles classes de faux backend sont disponibles à l'adresse qiskit.providers.fake_provider. Il s'agit notamment des versions simulées de ibm_cairo, ibm_hanoi, ibmq_kolkata, ibm_nairobi et ibm_washington. Comme pour les autres faux backends, ceux-ci comprennent des instantanés de données d'étalonnage et d'erreur provenant du système réel et peuvent être utilisés pour des tests, des compilations et des simulations au niveau local.

  • Introduction d'une nouvelle classe StatePreparation. Cette classe permet aux utilisateurs de préparer un état désiré de la même manière que Initialize sans que la réinitialisation soit automatiquement appliquée.

    Par exemple, pour préparer un qubit dans l'état (01)/2(|0\rangle - |1\rangle) / \sqrt{2} :

    import numpy as np
    from qiskit import QuantumCircuit
    
    circuit = QuantumCircuit(1)
    circuit.prepare_state([1/np.sqrt(2), -1/np.sqrt(2)], 0)
    circuit.draw()

    Le résultat est le suivant :

         ┌─────────────────────────────────────┐
    q_0: ┤ State Preparation(0.70711,-0.70711)
         └─────────────────────────────────────┘
  • La passe de Optimize1qGates le transpileur supporte maintenant l'optimisation de U1Gate, U2Gate, et PhaseGate avec des paramètres non liés dans un circuit. Auparavant, si ces portes avaient des paramètres non liés, la passe ne les utilisait pas. Par exemple :

    from qiskit import QuantumCircuit
    from qiskit.circuit import Parameter
    from qiskit.transpiler import PassManager
    from qiskit.transpiler.passes import Optimize1qGates, Unroller
    
    phi = Parameter('φ')
    alpha = Parameter('α')
    
    qc = QuantumCircuit(1)
    qc.u1(2*phi, 0)
    qc.u1(alpha, 0)
    qc.u1(0.1, 0)
    qc.u1(0.2, 0)
    
    pm = PassManager([Unroller(['u1', 'cx']), Optimize1qGates()])
    nqc = pm.run(qc)

    sera combiné au circuit avec une seule porte à qubit unique :

    qc = QuantumCircuit(1)
    qc.u1(2*phi + alpha + 0.3, 0)
  • Les méthodes Pauli.evolve() et PauliList.evolve() disposent désormais d'un nouveau mot-clé, frame, qui est utilisé pour effectuer une évolution d'un Pauli par un Clifford. Si frame='h' (valeur par défaut), l'évolution de l'image de Heisenberg d'un Pauli par un Clifford ( P=CPCP' = C^\dagger P C ) est effectuée, et si frame='s' , l'évolution de l'image de Schrödinger d'un Pauli par un Clifford ( P=CPCP' = C P C^\dagger ) est effectuée. Cette dernière option permet un calcul plus rapide et est également utile dans certains cas. Cette nouvelle option accélère considérablement le calcul de la méthode de décomposition de Clifford dans decompose_clifford .

  • Ajout d'un nouveau module à Qiskit : qiskit.primitives. Le module primitif est celui dans lequel sont définies les API qui fournissent différentes abstractions autour du calcul de certaines fonctions communes à partir de QuantumCircuit , ce qui permet d'abstraire les détails de l'exécution sous-jacente sur Backend. Cela permet aux algorithmes et aux applications de niveau supérieur de se concentrer sur l'exécution du calcul sans avoir à se préoccuper de l'exécution et du traitement des résultats, et de disposer d'une interface normalisée pour les calculs courants. Par exemple, l'estimation d'une valeur d'espérance d'un circuit quantique et d'un observable peut être effectuée par n'importe quelle classe mettant en œuvre cette classe et consommée de manière normalisée, quelle que soit la mise en œuvre sous-jacente BaseEstimator et consommée de manière normalisée, quelle que soit l'implémentation sous-jacente. Les applications peuvent alors être écrites en utilisant directement l'interface primitive.

    Pour commencer, le module contient deux types de primitives, les Sampler (voir BaseSampler pour la définition de la classe abstraite) et Estimator (voir BaseEstimator pour la définition de la classe abstraite). Les implémentations de référence sont incluses dans le module qiskit.primitives et sont construites à l'aide du module qiskit.quantum_info qui réalisent une simulation idéale de l'opération primitive. On s'attend à ce que les fournisseurs proposent leurs propres implémentations de ces interfaces pour les fournisseurs qui peuvent efficacement mettre en œuvre le protocole de manière native (généralement en utilisant un moteur d'exécution classique). En outre, à l'avenir, pour les fournisseurs qui ne proposent pas d'implémentation native des primitives, une méthode sera fournie qui permettra de construire des objets primitifs à partir d'un fichier Backend.

  • Ajout d'un nouveau module, qiskit.qpyqui contient la fonctionnalité précédemment exposée dans qiskit.circuit.qpy_serialization. Les fonctions publiques précédemment exposées à l'adresse qiskit.circuit.qpy_serialization, dump() et load() sont désormais disponibles à partir de ce nouveau module (bien qu'elles soient toujours accessibles à partir de qiskit.circuit.qpy_serialization , mais cela sera supprimé dans une prochaine version). Ce nouveau module a été ajouté dans l'intérêt de l'orientation future du format de fichier QPY, qui, dans les versions ultérieures, permettra la représentation de pulse Schedule et ScheduleBlock en plus des objets QuantumCircuit objets qu'il prend en charge aujourd'hui.

  • Ajout d'un nouvel attribut, qubit_properties à la classe Target classe. Cet attribut contient une liste d'objets QubitProperties pour chaque qubit de la cible. Par exemple :

    target.qubit_properties[2]

    contiendra le QubitProperties pour le qubit numéro 2 de la cible.

    Pour les BackendV2 auteurs, si vous définissiez auparavant QubitProperties directement dans votre implémentation BackendV2 en surchargeant l'implémentation BackendV2.qubit_properties() cela fonctionnera toujours. Toutefois, si vous déplacez la définition vers l'objet sous-jacent Target et que vous supprimez l'implémentation spécialisée de BackendV2.qubit_properties() ce qui permettra d'utiliser les propriétés des qubits dans le transpileur et de maintenir la compatibilité API avec votre ancienne implémentation.

  • Ajout d'une nouvelle fonction, qiskit.algorithms.eval_observables()qui est utilisée pour évaluer les observables à partir d'une borne QuantumCircuit. Elle provient d'une méthode privée, _eval_aux_ops(), de la classe qiskit.algorithms.VQE mais la nouvelle fonction eval_observables() est désormais plus générale et peut donc être utilisée dans d'autres algorithmes, par exemple les algorithmes d'évolution temporelle.

  • La stratégie de recherche de base dans BasisTranslator a été modifiée en une variante de la recherche de Dijkstra, ce qui améliore considérablement les performances d'exécution de la passe lorsqu'elle tente de cibler une base inaccessible.

  • La passe de DenseLayout est désormais multithreadée, ce qui améliore grandement les performances d'exécution de la passe. Par défaut, il utilisera le nombre de CPU logiques de votre système local, mais vous pouvez contrôler le nombre de threads utilisés par la passe en fixant la variable d'environnement RAYON_NUM_THREADS à une valeur entière. Par exemple, l'adresse RAYON_NUM_THREADS=4 permet d'exécuter la passe DenseLayout avec 4 threads.

  • Les calculs internes de Statevector.expectation_value() et DensityMatrix.expectation_value() ont été réimplémentés dans le langage de programmation Rust. Cette nouvelle implémentation est multithreadée et, par défaut, pour un fichier Statevector ou DensityMatrix >= 19 qubits, un pool de threads est créé avec le nombre de CPU logiques disponibles sur le système local. Vous pouvez contrôler le nombre de threads utilisés en définissant la variable d'environnement RAYON_NUM_THREADS sur une valeur entière. Par exemple, le paramètre RAYON_NUM_THREADS=4 n'utilisera que 4 threads dans le pool de threads.

  • Ajout d'un nouveau constructeur SparsePauliOp.from_sparse_list() qui prend un itérable, où les éléments représentent des termes de Pauli qui sont eux-mêmes épars, de sorte que "XIIIIIIIIIIIIIIIX" peut maintenant être écrit comme ("XX", [0, 16]). Par exemple, l'opérateur

H=X0Z3+2Y1Y4H = X_0 Z_3 + 2 Y_1 Y_4

peut maintenant être construit comme suit

op = SparsePauliOp.from_sparse_list([("XZ", [0, 3], 1), ("YY", [1, 4], 2)], num_qubits=5)
# or equivalently, as previously
op = SparsePauliOp.from_list([("IZIIX", 1), ("YIIYI", 2)])

Cela facilite la construction d'opérateurs très épars sur de nombreux qubits, comme c'est souvent le cas pour les hamiltoniens d'Ising.

  • La passe UnitarySynthesis dispose d'un nouveau mot-clé dans son constructeur, target. Ceci peut être utilisé pour spécifier optionnellement un objet Target qui représente la cible de compilation pour la passe. Lorsqu'elle est spécifiée, elle remplace les valeurs définies pour basis_gates, coupling_map et backend_props.

  • La classe UnitarySynthesisPlugin a un nouvel attribut optionnel que les implémentations peuvent ajouter, supports_target. Si un plugin a cet attribut défini sur True , un objet Target sera transmis dans la charge utile options sous le champ target . On s'attend à ce que cet objet Target soit utilisé à la place de coupling_map, gate_lengths, basis_gates, et gate_errors.

  • Introduction d'un nouveau flux de travail pour la construction d'objets pour la programmation PassManager d'objets pour l'ordonnancement QuantumCircuit dans le transpondeur. Dans le nouveau flux de travail, les passes d'ordonnancement et d'alignement sont toutes des objets qui ne font que mettre à jour l'ensemble des propriétés du gestionnaire de passes AnalysisPass qui ne font que mettre à jour l'ensemble des propriétés du gestionnaire de passes, en particulier le nouvel élément de l'ensemble des propriétés node_start_time, qui contient l'heure de début absolue de chaque opnode. Un autre TransformationPass distinct, tel que PadDelay est ensuite utilisé pour appliquer l'ordonnancement au DAG. Ce nouveau flux de travail est à la fois plus efficace et permet de corriger les contraintes de temps supplémentaires exposées par un backend.

    Auparavant, la chaîne de passage était mise en œuvre sous la forme de scheduling -> alignment , qui étaient tous deux des passages de transformation, de sorte que plusieurs instances étaient recréées lors de chaque passage DAGCircuit instances recréées lors de chaque passe. En outre, une programmation a été effectuée à chaque passage pour obtenir l'heure de début des instructions. La chaîne de passe requise devient alors scheduling -> alignment -> padding où la mise à jour n'intervient qu'à la fin avec la passe DAGCircuit ne se produit qu'à la fin avec la passe padding .

    Pour ceux qui créent des objets personnalisés PassManager qui impliquent un ordonnancement des circuits, vous devrez ajuster votre PassManager pour insérer l'une des passes BasePadding (actuellement soit PadDelay ou PadDynamicalDecoupling peut être utilisé) à la fin de la chaîne de passes d'ordonnancement. Sans la passe de remplissage, les passes d'ordonnancement ne seront pas reflétées dans le circuit de sortie de la méthode de la méthode personnalisée run() de votre méthode personnalisée PassManager.

    Par exemple, si vous construisiez auparavant votre PassManager avec quelque chose comme :

    from qiskit.transpiler import PassManager
    from qiskit.transpiler.passes import TimeUnitConversion, ALAPSchedule, ValidatePulseGates, AlignMeasures
    
    pm = PassManager()
    scheduling = [
        ALAPSchedule(instruction_durations), PadDelay()),
        ValidatePulseGates(granularity=timing_constraints.granularity, min_length=timing_constraints.min_length),
        AlignMeasures(alignment=timing_constraints.acquire_alignment),
    ]
    pm.append(scheduling)

    vous pouvez utiliser à la place :

    from qiskit.transpiler import PassManager
    from qiskit.transpiler.passes import TimeUnitConversion, ALAPScheduleAnalysis, ValidatePulseGates, AlignMeasures, PadDelay
    
    pm = PassManager()
    scheduling = [
        ALAPScheduleAnalysis(instruction_durations), PadDelay()),
        ConstrainedReschedule(acquire_alignment=timing_constraints.acquire_alignment, pulse_alignment=timing_constraints.pulse_alignment),
        ValidatePulseGates(granularity=timing_constraints.granularity, min_length=timing_constraints.min_length),
        PadDelay()
    ]
    pm.append(scheduling)

    qui sera à la fois plus efficace et alignera les instructions en fonction des contraintes matérielles.

  • Ajout d'un nouveau pass transpiler ConstrainedReschedule pass. La passe ConstrainedReschedule prend en compte les contraintes d'alignement du matériel qui peuvent être définies dans un objet, et BackendConfigurationpulse_alignment et acquire_alignment. Cette nouvelle classe remplace l'ancienne classe AlignMeasures car elle effectue le même alignement (via le jeu de propriétés) pour les instructions de mesure en plus de l'alignement général des instructions. En définissant l'argument de la contrainte acquire_alignment pour la passe ConstrainedReschedule il est possible de remplacer directement AlignMeasures lorsqu'il est associé à une nouvelle passe BasePadding .

  • Ajout de deux nouvelles passes de transpilateur ALAPScheduleAnalysis et ASAPScheduleAnalysis qui supplantent les passes ALAPSchedule et ASAPSchedule dans le cadre de la refonte du flux de travail du transpileur pour schedling. Les nouvelles passes effectuent le même ordonnancement, mais dans l'ensemble des propriétés et en s'appuyant sur une passe BasePadding pour ajuster le circuit sur la base de toutes les analyses d'alignement de l'ordonnancement.

    Le comportement standard de ces passes aligne également l'ordre temporel sur l'ordre topologique des nœuds du DAG. Ce changement peut affecter le résultat de l'ordonnancement s'il comprend des opérations conditionnelles ou la mesure simultanée de deux qubits avec le même registre classique (cas limite). Pour reproduire le comportement conventionnel, réglez clbit_write_latency sur une longueur identique à celle de l'instruction de mesure.

    Par exemple, considérons la programmation d'un circuit d'entrée comme :

         ┌───┐┌─┐
    q_0: ┤ X ├┤M├──────────────
         └───┘└╥┘   ┌───┐
    q_1: ──────╫────┤ X ├──────
               ║    └─╥─┘   ┌─┐
    q_2: ──────╫──────╫─────┤M├
               ║ ┌────╨────┐└╥┘
    c: 1/══════╩═╡ c_0=0x1 ╞═╩═
               0 └─────────┘ 0
    from qiskit import QuantumCircuit
    from qiskit.transpiler import InstructionDurations, PassManager
    from qiskit.transpiler.passes import ALAPScheduleAnalysis, PadDelay, SetIOLatency
    from qiskit.visualization.timeline import draw
    
    circuit = QuantumCircuit(3, 1)
    circuit.x(0)
    circuit.measure(0, 0)
    circuit.x(1).c_if(0, 1)
    circuit.measure(2, 0)
    
    durations = InstructionDurations([("x", None, 160), ("measure", None, 800)])
    
    pm = PassManager(
        [
          SetIOLatency(clbit_write_latency=800, conditional_latency=0),
          ALAPScheduleAnalysis(durations),
          PadDelay(),
        ]
    )
    draw(pm.run(circuit))

    Comme vous pouvez le voir sur la ligne de temps, la mesure sur q_2 commence avant la porte X conditionnelle sur q_1, ce qui semble contraire à l'ordre topologique du nœud. C'est également un comportement attendu car l'accès en écriture de clbit se fait sur le front de fin de l'instruction de mesure, et l'accès en lecture de la porte conditionnelle se fait sur le front de début de l'instruction. Ainsi, l'ordre topologique est préservé sur le timeslot du registre classique, ce qui n'est pas pris en compte par la vue chronologique. Toutefois, cela suppose une conception particulière de la microarchitecture, et le circuit n'est pas nécessairement programmé de cette manière.

    En utilisant la configuration par défaut des passes, le circuit est programmé comme ci-dessous.

    from qiskit import QuantumCircuit
    from qiskit.transpiler import InstructionDurations, PassManager
    from qiskit.transpiler.passes import ALAPScheduleAnalysis, PadDelay
    from qiskit.visualization.timeline import draw
    
    circuit = QuantumCircuit(3, 1)
    circuit.x(0)
    circuit.measure(0, 0)
    circuit.x(1).c_if(0, 1)
    circuit.measure(2, 0)
    
    durations = InstructionDurations([("x", None, 160), ("measure", None, 800)])
    
    pm = PassManager([ALAPScheduleAnalysis(durations), PadDelay()])
    draw(pm.run(circuit))

    Notez que clbit est verrouillé pendant toute la durée de l'intervalle d'instruction de mesure. Ce comportement est basé sur le Qiskit Pulse, dans lequel l'instruction d'acquisition prend AcquireChannel et MemorySlot qui ne sont pas autorisés à se chevaucher avec d'autres instructions, c'est-à-dire que l'accès simultané à la mémoire à partir des différentes instructions est interdit. Cela permet également de toujours aligner l'ordre temporel sur l'ordre topologique des nœuds.

  • Ajout d'une nouvelle passe de transpilation PadDynamicalDecoupling qui remplace la passe DynamicalDecoupling dans le cadre de la refonte du flux de travail du transpileur pour l'ordonnancement. Cette nouvelle passe insère des séquences de découplage dynamique dans le circuit en fonction de l'analyse de l'ordonnancement et de l'alignement effectuée lors des passes précédentes.

  • La fonction de plot_gate_map() fonction de visualisation et les fonctions construites au-dessus d'elle, plot_error_map() et plot_circuit_layout()ont un nouveau mot-clé, qubit_coordinates. Cet argument prend une séquence de coordonnées 2D à utiliser pour tracer chaque qubit dans le backend visualisé. Si elle est spécifiée, cette séquence doit avoir une longueur égale au nombre de qubits sur le backend et elle sera utilisée à la place du comportement par défaut.

  • La fonction de plot_gate_map() fonction de visualisation et les fonctions construites au-dessus d'elle, plot_error_map() et plot_circuit_layout()sont maintenant capables de tracer n'importe quel backend et pas seulement ceux dont le nombre de qubits est égal à l'un des backends de IBM. Elle s'appuie sur la fonction retworkx spring_layout() pour générer la mise en page de la visualisation. Si la présentation par défaut ne fonctionne pas avec le graphe de couplage particulier d'un backend, vous pouvez utiliser la fonction qubit_coordinates pour définir une présentation personnalisée.

  • La fonction de plot_gate_map() fonction de visualisation et les fonctions construites au-dessus d'elle, plot_error_map() et plot_circuit_layout()sont maintenant capables de fonctionner avec un backend basé sur BackendV2 sont maintenant en mesure de fonctionner avec un backend basé sur le Auparavant, ces fonctions ne fonctionnaient qu'avec les backends basés sur BaseBackend ou BackendV1 ou avec des backends basés sur la technologie

  • Ajout d'une nouvelle passe de transpilateur, SetIOLatency. Cette passe prend deux arguments clbit_write_latency et conditional_latency pour définir la latence des E/S pour les bits classiques et les conditions classiques sur un backend. Cette passe définira ensuite ces valeurs dans l'ensemble des propriétés du gestionnaire de passe afin de permettre aux passes d'ordonnancement et d'alignement suivantes de corriger ces latences et de fournir une sortie d'ordonnancement plus précise d'un circuit dynamique.

  • Un nouveau passeur de transpondeur PadDelay a été ajoutée. Cette passe remplit les temps morts sur les fils des qubits avec des instructions Delay instructions. Cette passe fait partie du nouveau flux de travail pour l'ordonnancement des passes dans le transpileur et dépend d'une passe d'analyse d'ordonnancement (telle que ALAPScheduleAnalysis ou ASAPScheduleAnalysis) et de toutes les passes d'alignement (telles que ConstrainedReschedule) à exécuter avant PadDelay.

  • La passe VF2Layout transpiler a un nouvel argument clé, target , qui est utilisé pour fournir un Target pour la passe. Lorsqu'il est spécifié, le Target sera utilisé par le pass pour toutes les informations sur le périphérique cible. Si elle est spécifiée, l'option target aura la priorité sur les arguments coupling_map et properties .

  • Permettre l'utilisation de callables comme optimiseurs dans VQE et QAOA. Maintenant, l'optimiseur peut être soit l'un des optimiseurs de Qiskit, tel que SPSA soit un appelable avec la signature suivante :

    from qiskit.algorithms.optimizers import OptimizerResult
    
    def my_optimizer(fun, x0, jac=None, bounds=None) -> OptimizerResult:
        # Args:
        #     fun (callable): the function to minimize
        #     x0 (np.ndarray): the initial point for the optimization
        #     jac (callable, optional): the gradient of the objective function
        #     bounds (list, optional): a list of tuples specifying the parameter bounds
    
        result = OptimizerResult()
        result.x = # optimal parameters
        result.fun = # optimal function value
        return result

    La signature ci-dessus permet également de passer directement n'importe quel minimiseur SciPy, par exemple en tant que

    from functools import partial
    from scipy.optimize import minimize
    
    optimizer = partial(minimize, method="L-BFGS-B")

Problèmes connus

  • Lors de l'exécution parallel_map() (ce qui est fait en interne par des fonctions sensibles aux performances telles que transpile() et assemble()) dans un sous-processus lancé en dehors de parallel_map()il est possible que le traitement parallèle effectué à l'intérieur de parallel_map() se bloque et ne revienne jamais. Cela est dû à des problèmes en amont dans CPython concernant la méthode par défaut pour lancer des sous-processus sur Linux et macOS avec Python 3.7 (voir https://bugs.python.org/issue40379 pour plus de détails). Si vous rencontrez ce problème, vous avez deux options : vous pouvez soit supprimer les processus parallèles imbriqués, car l'appel à parallel_map() à partir d'un processus principal devrait fonctionner correctement; soit vous appelez manuellement le module multiprocessing de la bibliothèque standard CPython pour effectuer une distribution parallèle similaire à partir d'un sous-processus, mais utilisez les méthodes de lancement "spawn" ou "forkserver" pour éviter que les choses ne se bloquent et ne reviennent jamais.

Mise à niveau

  • Les classes Qubit, Clbit et AncillaQubit possèdent désormais l'attribut __slots__ . Cela permet de réduire l'utilisation de la mémoire. Par ailleurs, il n'est plus possible d'y attacher des données arbitraires en tant qu'attributs. Il est très peu probable que cela ait un effet sur le code en aval autre que des avantages en termes de performances.

  • La dépendance principale retworkx a vu sa version requise passer de 0.10.1 à 0.11.0. Cela permet d'améliorer les performances de la passe de transpilation ConsolidateBlocks.

  • La version minimale supportée de symengine est désormais 0.9.0. Cette modification était nécessaire pour améliorer la compatibilité avec le module pickle de Python, qui est utilisé en interne dans le cadre de la répartition parallèle avec le module parallel_map().

  • La valeur par défaut de QISKIT_PARALLEL lors de l'exécution avec Python 3.9 sur Linux est maintenant fixée à TRUE. Cela signifie que lorsque l'on exécute parallel_map() ou des fonctions qui l'appellent en interne, telles que transpile() et assemble()la fonction sera exécutée dans plusieurs processus et devrait avoir de meilleures performances d'exécution. Ce changement a été effectué parce que les problèmes de fiabilité du dispatching parallèle semblent avoir été résolus (voir #6188 pour plus de détails). Si vous rencontrez encore des problèmes à cause de cela, vous pouvez désactiver le multiprocessing et revenir au comportement par défaut précédent en définissant la variable d'environnement QISKIT_PARALLEL à FALSE, ou en définissant l'option parallel à False dans votre fichier de configuration utilisateur (veuillez également déposer un problème afin que nous puissions suivre tous les problèmes liés au multiprocessing).

  • La classe de porte MSGate , précédemment dépréciée, que l'on trouvait dans qiskit.circuit.library a été supprimée. Il était à l'origine obsolète dans la version 0.16.0. Il est préférable d'utiliser la classe GMS car elle permet de créer une porte MS équivalente pour 2 qubits en plus d'une porte MSGate pour n'importe quel nombre de qubits.

  • La méthode mirror() de la classe Instruction a été supprimée. Il était à l'origine obsolète dans la version 0.15.0. Au lieu de cela, vous devez utiliser Instruction.reverse_ops().

  • La méthode num_ancilla_qubits() , précédemment obsolète, de l'élément qiskit.circuit.library.PiecewiseLinearPauliRotations et qiskit.circuit.library.WeightedAdder a été supprimée. Il était à l'origine obsolète dans la version 0.16.0. Les méthodes PiecewiseLinearPauliRotations.num_ancillas() et WeightedAdder.num_ancillas() doivent être utilisées à la place.

  • L'argument reverse du constructeur de la classe PolynomialPauliRotations a été supprimé. Il était à l'origine obsolète dans la version 0.15.0. Au lieu de cela, vous devez utiliser la méthode QuantumCircuit.reverse_bits() pour inverser le circuit PolynomialPauliRotations si nécessaire.

  • L'argument angle , précédemment déprécié, des constructeurs de l'élément C3SXGate et C3XGate a été supprimé. Il était à l'origine obsolète dans la version 0.17.0. Au lieu de cela, pour les portes X fractionnaires à 3 commandes, vous pouvez utiliser la méthode C3XGate.power() .

  • Prise en charge de l'utilisation des objets np.ndarray dans le cadre de l'attribut params d'un objet Gate a été supprimée. Ceci est obsolète depuis Qiskit Terra 0.16.0 et ne fonctionne plus. Au lieu de cela, il faut créer une nouvelle sous-classe de Gate et autoriser explicitement une entrée np.ndarray en surchargeant la méthode validate_parameter() en surchargeant la méthode

  • Un nouveau supplément csp-layout-pass a été ajouté à la cible d'installation de pip install qiskit-terra et est également inclus dans le supplément all . Ceci n'a pas d'effet dans Qiskit Terra 0.20, mais à partir de Qiskit Terra 0.21, les dépendances nécessaires uniquement pour le passage du transpilateur seront déclassées d'exigences à optionnelles CSPLayout seront déclassées d'exigences en optionnelles, et installées par cet extra. Vous pouvez préparer un paquet qui dépend de cette passe en définissant ses exigences (ou la commande pip install ) pour cibler qiskit-terra[csp-layout-pass].

  • La prise en charge de l'exécution avec Python 3.6 a été supprimée. Pour faire fonctionner Qiskit, vous avez besoin d'une version minimale de Python de 3.7.

  • Le AmplitudeEstimator hérite maintenant de la classe ABC de la bibliothèque standard Python. Cela oblige toute sous-classe à implémenter la méthode estimate() alors que cela n'était pas nécessaire auparavant. Cela s'explique par le fait qu'à l'origine, la classe devait toujours être une classe enfant de ABC, car la classe estimate() est nécessaire au fonctionnement d'un objet AmplitudeEstimator objet. Cependant, si vous définissiez auparavant une AmplitudeEstimator qui n'implémentait pas estimate() il en résultera une erreur.

  • L'erreur soulevée par HoareOptimizer si la dépendance optionnelle z3 n'est pas disponible est passée de TranspilerError à MissingOptionalLibraryError (qui est à la fois un QiskitError et un ImportError). Ceci a été fait pour être cohérent avec les autres dépendances optionnelles.

  • Sur Linux, le support minimum de la bibliothèque a été augmenté de manylinux2010 VM à manylinux2014. Cela reflète des changements similaires dans Numpy et Scipy. Il ne devrait pas y avoir d'effet significatif pour la plupart des utilisateurs, à moins que votre système ne contienne encore une très ancienne version de glibc.

  • La fonction marginal_counts() lorsqu'elle est appelée avec un objet Result marginalisera désormais le champ memory des données de l'expérience s'il est défini dans l'entrée Result. Auparavant, le champ memory dans l'entrée n'était pas marginalisé. Cette modification a été apportée parce que le comportement précédent faisait que le champ counts ne correspondait pas au champ memory après l'appel de la fonction marginal_counts() a été appelé. Si le comportement précédent est souhaité, il peut être rétabli en définissant marginalize_memory=None en tant qu'argument de marginal_counts() ce qui ne marginalisera pas le champ memory .

  • Le passage du transpondeur peut donner des résultats différents avec la même valeur de semence StochasticSwap peut donner des résultats différents avec la même valeur de départ. Cela est dû à la réécriture interne de la passe de transposition afin d'améliorer les performances d'exécution. Cependant, cela signifie que si vous avez exécuté transpile() avec optimization_level 0, 1 (la valeur par défaut), ou 2 avec une valeur définie pour seed_transpiler , vous pouvez obtenir une sortie avec un mappage de swap différent après la mise à jour vers Qiskit Terra 0.20.0.

  • Pour construire Qiskit Terra à partir des sources, un compilateur Rust est maintenant nécessaire. Ceci est dû à la réécriture interne de la passe du transpileur qui améliore grandement les performances d'exécution du transpileur StochasticSwap qui améliore considérablement les performances d'exécution du transpileur. Le compilateur rust peut être facilement installé à l'aide de rustup, qui peut être trouvé ici : https://rustup.rs/

  • L'attribut name de la classe PauliEvolutionGate a été modifié pour être toujours "PauliEvolution". Ce changement a été fait pour être cohérent avec les autres portes de Qiskit et permet aux autres parties de Qiskit d'identifier rapidement quand une opération particulière dans un circuit est un PauliEvolutionGate. Par exemple, il permet de dérouler les portes d'évolution de Pauli.

    Auparavant, le nom contenait les opérateurs qui sont évolués, ce qui est maintenant disponible via l'attribut PauliEvolutionGate.label attribut. Si l'on dessine un circuit avec un PauliEvolutionGate est dessiné, la porte indiquera toujours la même information, à savoir quelles portes sont en cours d'évolution.

  • Les méthodes précédemment dépréciées :

    • qiskit.algorithms.VQE.get_optimal_cost
    • qiskit.algorithms.VQE.get_optimal_circuit
    • qiskit.algorithms.VQE.get_optimal_vector
    • qiskit.algorithms.VQE.optimal_params
    • qiskit.algorithms.HamiltonianPhaseEstimationResult.most_likely_phase
    • qiskit.algorithms.PhaseEstimationResult.most_likely_phase

    qui étaient à l'origine dépréciées dans la version de Qiskit Terra 0.18.0 ont été supprimées et ne fonctionneront plus.

  • La classe qiskit.algorithms.VariationalAlgorithm est désormais définie comme une classe de base abstraite (ABC) qui obligera les classes qui en héritent à définir une méthode getter et setter VariationalAlgorithm.initial_point .

  • Le kwarg pass_manager pour la fonction transpile() a été supprimé. Il était à l'origine obsolète dans la version 0.13.0. La meilleure façon de transpiler un circuit avec un objet personnalisé est d'utiliser l'objet PassManager est d'utiliser la méthode run() de l'objet PassManager objet.

  • La classe ParametrizedSchedule , précédemment obsolète, a été supprimée et n'existe plus. Cette classe a été supprimée lors de la publication de la version 0.17.0. Au lieu d'utiliser cette classe, vous pouvez paramétrer directement Schedule ou ScheduleBlock en spécifiant un objet Parameter à l'argument de l'impulsion paramétrique.

  • Le module qiskit.circuit.library.probability_distributions a été supprimé et n'existe plus selon la notice de dépréciation de qiskit-terra 0.17.0 (publiée le 1er avril 2021). Les classes concernées sont UniformDistribution, NormalDistribution et LogNormalDistribution. Ils sont tous déplacés dans la bibliothèque qiskit-finance, dans son module circuit library : qiskit_finance.circuit.library.probability_distributions.

  • L'ancienne classe qiskit.test.mock.fake_mumbai_v2.FakeMumbaiV2 a été renommée FakeMumbaiFractionalCX pour la différencier du faux backend basé sur le dispositif Mumbai, BackendV2 pour le dispositif IBM Mumbai, qiskit.test.mock.backends.FakeMumbaiV2. Si vous utilisiez auparavant la classe FakeMumbaiV2 pour obtenir un faux backend ayant des applications fractionnaires de CXGate définies dans sa cible, vous devez utiliser la classe FakeMumbaiFractionalCX car la classe FakeMumbaiV2 n'aura plus ces définitions de portes supplémentaires dans son fichier Target.

  • Le résolveur utilisé par QuantumCircuit.append() (et par conséquent toutes les méthodes qui ajoutent une instruction à un QuantumCircuit) pour convertir les spécificateurs de bits a été modifié pour le rendre plus rapide et plus fiable. Certaines constructions telles que :

    import numpy as np
    from qiskit import QuantumCircuit
    
    qc = QuantumCircuit(1, 1)
    qc.measure(np.array([0]), np.array([0]))

    fonctionneront désormais alors qu'ils auraient auparavant soulevé une erreur, mais certaines entrées pathologiques telles que :

    from sympy import E, I, pi
    qc.x(E ** (I * pi))

    soulèveront désormais des erreurs alors qu'ils auraient pu réussir occasionnellement (par erreur) auparavant. Pour presque toutes les utilisations correctes, il ne devrait pas y avoir de changement notable, à l'exception d'une accélération générale.

  • La méthode interne semi-publique QuantumCircuit._append() ne vérifie plus les types de ses entrées et suppose qu'il n'y a pas de doublons non valides dans ses listes d'arguments. Cette fonction est utilisée par certaines parties internes de Qiskit et d'autres bibliothèques pour construire des instances aussi rapidement que possible en sautant la vérification des erreurs lorsque les données sont déjà connues pour être correctes QuantumCircuit le plus rapidement possible en sautant la vérification des erreurs lorsque les données sont déjà connues pour être correctes. En général, les utilisateurs ou les fonctions qui reçoivent des données d'utilisateur doivent utiliser la méthode public QuantumCircuit.append() qui résout les spécificateurs de bits entiers, diffuse ses arguments et vérifie l'exactitude des entrées.

  • Cython n'est plus une dépendance de construction de Qiskit Terra et n'a plus besoin d'être installé lors de la construction de Qiskit Terra à partir des sources.

  • Les passmanagers prédéfinis en qiskit.transpiler.preset_passmanagers pour tous les niveaux d'optimisation 2 et 3 tels que générés par level_2_pass_manager() et level_3_pass_manager() ont été modifiés de manière à ce que le gestionnaire de passe soit exécuté par défaut avant la passe de mise en page VF2Layout par défaut avant la passe de mise en page. La passe VF2Layout permet de vérifier rapidement si une disposition parfaite peut être trouvée et remplace ce qui était fait auparavant pour les niveaux d'optimisation 2 et 3 qui utilisaient une combinaison de TrivialLayout et CSPLayout pour essayer de trouver une disposition parfaite. Il en résultera un comportement potentiellement différent lorsque transpile() est appelé par défaut car il supprime un chemin par défaut pour tous les niveaux d'optimisation >=2 d'utilisation d'une disposition triviale (où circuit.qubits[0] est mappé au qubit physique 0, circuit.qubits[1] est mappé au qubit physique 1, etc) en supposant que la disposition triviale est parfaite. Si votre cas d'utilisation dépend de la disposition triviale, vous pouvez explicitement la demander lors de la transpilation en spécifiant layout_method="trivial" lorsque vous appelez transpile().

  • Le gestionnaire de passes prédéfini pour le niveau d'optimisation 1 (lors d'un appel à transpile() avec optimization_level=1 ou lorsqu'aucun argument optimization_level n'est défini) tel que généré par level_1_pass_manager() a été modifié de sorte que VF2Layout est appelé par défaut pour vérifier rapidement si une disposition parfaite peut être trouvée avant que la commande DenseLayout. Cependant, contrairement aux niveaux d'optimisation 2 et 3, une mise en page triviale est toujours tentée avant l'exécution du programme VF2Layout et s'il s'agit d'une correspondance parfaite, la sortie de VF2Layout sera utilisée.

Remarques concernant la dépréciation

  • L'argument max_credits de execute()et toutes les configurations de Qobj (par ex. QasmQobjConfig et PulseQobjConfig), est obsolète et sera supprimée dans une prochaine version. Le système de crédit n'a pas été utilisé sur IBM Quantum depuis deux ans, et l'option n'a aucun effet. Aucune alternative n'est nécessaire. Par exemple, si vous appelez execute() comme :

    job = execute(qc, backend, shots=4321, max_credits=10)

    vous pouvez simplement omettre l'argument max_credits :

    job = execute(qc, backend, shots=4321)
  • L'utilisation d'un entier impair pour l'argument order dans le constructeur de la classe SuzukiTrotter est dépréciée et ne fonctionnera plus dans les versions ultérieures. Les formules de produit utilisées par le SuzukiTrotter ne sont définies que lorsque l'ordre est pair, car les formules de produit de Suzuki sont symétriques.

  • Les kwargs qregs, cregs, layout et global_phase des classes MatplotlibDrawer, TextDrawing et QCircuitImage , ainsi que le kwarg calibrations de la classe MatplotlibDrawer , sont désormais obsolètes et seront supprimés dans une version ultérieure.

Corrections des erreurs

  • Correction d'une erreur dans les fonctions de conversion des circuits circuit_to_gate() et circuit_to_instruction() (et leurs méthodes de circuit associées QuantumCircuit.to_gate() et QuantumCircuit.to_instruction()) lorsqu'elles agissent sur un circuit avec des bits sans registre ou des bits dans plus d'un registre.

  • Correction d'un problème où l'appel à QuantumCircuit.copy() sur les circuits "body" d'une opération de flux de contrôle créée avec l'interface du constructeur provoquait une erreur. Par exemple, le message suivant, qui était auparavant une erreur, sera désormais renvoyé avec succès :

    from qiskit.circuit import QuantumCircuit, QuantumRegister, ClassicalRegister
    
    qreg = QuantumRegister(4)
    creg = ClassicalRegister(1)
    circ = QuantumCircuit(qreg, creg)
    
    with circ.if_test((creg, 0)):
        circ.h(0)
    
    if_else_instruction, _, _ = circ.data[0]
    true_body = if_else_instruction.params[0]
    true_body.copy()
  • Ajout d'une entrée manquante dans la bibliothèque d'équivalence de session standard entre CXGate et CPhaseGate ainsi qu'entre CXGate et CRZGate.

  • Correction d'un problème où l'exécution de l'opérateur == entre deux objets SparsePauliOp provoquait une erreur lorsque les deux opérateurs avaient des nombres de coefficients différents. Par exemple :

    op = SparsePauliOp.from_list([("X", 1), ("Y", 1)])
    op2 = SparsePauliOp.from_list([("X", 1), ("Y", 1), ("Z", 0)])
    print(op == op2)

    Auparavant, cela aurait soulevé un ValueError au lieu de renvoyer False.

  • Correction de la prise en charge dans transpile() pour passer un objet InstructionScheduleMap à l'objet sous-jacent PassManager en fonction de la méthode Target pour BackendV2 sous-jacents. Auparavant, la fonction transpile() n'effectuait pas ce traitement et toutes les passes de transpilation qui ne permettent pas encore de travailler avec un objet Target n'auraient pas accès aux calibrations d'impulsions par défaut pour les instructions d'un objet BackendV2 backend.

  • L'option AmplitudeAmplifier est désormais correctement disponible à partir du module racine qiskit.algorithms directement. Auparavant, il n'était pas inclus dans les classes réexportées du module racine et n'était accessible qu'à partir de qiskit.algorithms.amplitude_amplifiers. Correction #7751.

  • Correction d'un problème avec le backend de mpl pour la fonction de tiroir de circuit circuit_drawer() et la méthode QuantumCircuit.draw() où les portes avec des conditions ne s'affichaient pas correctement lorsqu'un nombre suffisant de portes faisait basculer le tiroir sur une deuxième rangée. Corrigé : #7752.

  • Correction d'un problème où la méthode HHL.construct_circuit() , dans certaines conditions, ne renvoyait pas une valeur correcte QuantumCircuit. Auparavant, la fonction comportait une erreur d'arrondi dans le calcul du nombre de qubits nécessaires pour représenter les valeurs propres, ce qui entraînait une sortie incorrecte du circuit.

  • Correction d'un bug d'endianness dans BaseReadoutMitigator.expectation_value() lorsqu'une chaîne diagonal est transmise. Il sera désormais correctement interprété en little endian de la même manière que le reste de Qiskit Terra, au lieu de big endian.

  • Correction d'un problème avec le quantum_info.partial_trace() lorsque la fonction a été invitée à ne tracer aucun sous-système, elle renverra désormais correctement le DensityMatrix de l'état d'entrée avec toutes les dimensions restantes plutôt que de générer une erreur. Corrigé #7613

  • Correction d'un problème avec le backend de text pour la fonction de tiroir de circuit circuit_drawer() et la méthode QuantumCircuit.draw() lorsque des portes utilisant du texte latéral, telles que les portes CPhaseGate et RZZGate avec des conditions classiques, ne s'affichaient pas correctement. Correction #7532.

  • Correction d'un problème avec la fonction circuit_drawer() et la méthode draw() de la méthode QuantumCircuit. Lors de l'utilisation de l'option reverse_bits avec les options mpl, latex ou text , les bits sans registres ne s'affichaient pas dans le bon ordre. Correction #7303.

  • Correction d'un problème dans la méthode LocalReadoutMitigator.assignment_matrix() qui rejetait auparavant une valeur d'entrée pour l'argument qubits qui n'était pas une séquence triviale de qubits sous la forme : [0, 1, 2, ..., n-1]. Cette erreur a été corrigée de sorte que la méthode accepte désormais n'importe quelle liste d'indices de qubits à mesurer.

  • Correction d'un problème dans le calcul de la valeur d'espérance de la méthode StabilizerState.expectation_value() où la valeur de l'espérance de sortie était incorrecte si l'opérateur d'entrée de l'argument avait une phase non triviale Pauli pour l'argument oper avait une phase non triviale. Correction #7441.

  • Une expression opflow contenant l'identité de Pauli opflow.I ne produit plus de circuit IGate lorsqu'elle est convertie en circuit. Ce changement corrige une différence d'attente; la porte d'identité dans le circuit indique un retard, alors que dans le flux optique, nous nous attendons à une identité mathématique, c'est-à-dire à aucune opération.

  • Les PauliGate n'insère plus de IGate pour Paulis avec l'étiquette "I".

  • PauliSumOp les tests d'égalité gèrent désormais le cas où l'un des éléments comparés est un simple PauliOp. Par exemple, 0 * X + I == I est désormais évalué à True, alors qu'il était False avant cette version.

  • Correction d'un problème avec les ALAPSchedule et ASAPSchedule lors de l'utilisation d'instructions pour lesquelles des calibrations d'impulsions personnalisées (c'est-à-dire des portes d'impulsions) ont été définies. Auparavant, les passes d'ordonnancement n'utilisaient pas la durée de l'étalonnage personnalisé des impulsions pour ces instructions, ce qui entraînait la génération d'un ordonnancement incorrect pour le circuit. Ce problème a été corrigé de sorte que les passes d'ordonnancement utilisent désormais la durée de l'étalonnage de l'impulsion personnalisée pour toute instruction dans le circuit qui a un étalonnage personnalisé.

  • Correction de la prise en charge de l'utilisation de ParameterExpression dans la passe de transposition RZXCalibrationBuilder transpiler pass. Auparavant, si un paramètre d'instruction comprenait une borne ParameterExpression la passe n'était pas en mesure de le gérer correctement.

  • Arrêt de l'analyseur dans QuantumCircuit.from_qasm_str() et from_qasm_file() d'accepter les programmes OpenQASM qui s'identifiaient comme provenant d'une version linguistique autre que 2.0. Cet analyseur ne concerne que OpenQASM 2.0; la prise en charge des circuits importés de OpenQASM 3.0 sera ajoutée dans une prochaine version.

  • L'exportateur OpenQASM 3, qasm3.Exporterévite désormais les noms de registres et de paramètres qui entrent en conflit avec les mots-clés réservés de OpenQASM 3 en générant un nouveau nom unique. Les registres et les paramètres portant le même nom ne seront plus confondus dans le code produit par l'exportateur OpenQASM 3. Correction #7742.

Aer 0.10.3

Pas de modification

Ignis 0.7.0

Pas de modification

IBM 0.18.3 du fournisseur Q

Pas de modification

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