Skip to main content
IBM Quantum Platform

Note di rilascio di Qiskit 0.35


0.35.0

Terra 0.20.0

Preludio

I punti salienti della release Qiskit Terra 0.20.0 sono:

  • L'introduzione di moduli multithread scritti in Rust per accelerare le prestazioni di alcune porzioni di Qiskit Terra e migliorare la scalabilità con un numero maggiore di qubit. Tuttavia, quando si costruisce Qiskit dai sorgenti è ora necessario un compilatore Rust.
  • Maggiore supporto nativo per lavorare con gli elementi Target nel transpiler. Diversi passaggi supportano ora il lavoro diretto con un oggetto Target il che rende il transpiler più robusto nei tipi di backend a cui può rivolgersi.
  • L'introduzione del qiskit.primitives modulo. Queste API forniscono diversi livelli di astrazione per calcolare gli output di interesse da QuantumCircuit e utilizzare i backend. Ad esempio, l'interfaccia BaseEstimator definisce un'interfaccia astratta per stimare il valore di aspettativa di un'osservabile. Questo può essere utilizzato per costruire algoritmi e applicazioni di livello superiore che si basano sulla stima dei valori di aspettativa senza doversi preoccupare dell'implementazione del calcolo del valore di aspettativa. Questo disaccoppiamento consente all'implementazione di migliorare la velocità e la qualità, pur aderendo all'interfaccia astratta definita. Allo stesso modo, il sistema BaseSampler calcola distribuzioni di quasi-probabilità dalle misure dei circuiti. Altre primitive saranno introdotte in futuro.

Questa versione non supporta più Python 3.6. Con questa versione, sono necessari i siti da Python 3.7 a Python 3.10.

Nuove funzioni

  • Aggiunto un nuovo metodo costruttore per la classe Operator classe, Operator.from_circuit() per creare un nuovo Operator da un oggetto QuantumCircuit. Mentre questo era possibile normalmente usando il costruttore predefinito, il metodo Operator.from_circuit() fornisce ulteriori opzioni per regolare la creazione dell'operatore. In primo luogo questo permette di permutare l'ordine dei qubit in base a un set Layout. Ad esempio:

    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 variabile operator avrà i qubit permutati in base alla disposizione, in modo da essere identica a quella restituita da Operator(circuit) prima della transpilazione.

  • Aggiunto un nuovo metodo DAGCircuit.copy_empty_like() alla classe DAGCircuit della classe. Questo metodo viene utilizzato per creare una nuova copia di un oggetto esistente con la stessa struttura ma DAGCircuit esistente con la stessa struttura, ma vuoto di istruzioni. Questo metodo è uguale al metodo privato _copy_circuit_metadata(), ma ora fa parte dell'API pubblica della classe.

  • Le classi fake backend e fake provider, precedentemente disponibili in qiskit.test.mock , sono ora accessibili anche in un nuovo modulo: qiskit.providers.fake_provider. Questo nuovo modulo sostituisce il precedente qiskit.test.mock che sarà deprecato in Qiskit 0.21.0.

  • Aggiunta di una nuova classe di gate, LinearFunctionche codifica in modo efficiente una funzione lineare (cioè una funzione che può essere rappresentata da una sequenza di CXGate e SwapGate gate).

  • Aggiunto un nuovo passaggio del transpiler CollectLinearFunctions che raccoglie i blocchi di elementi consecutivi CXGate e SwapGate in un circuito, e sostituisce ogni blocco con una LinearFunction gate.

  • Aggiunto un nuovo passaggio del transpiler LinearFunctionsSynthesis che sintetizza qualsiasi LinearFunction gates utilizzando l' algoritmo di Patel-Markov-Hayes. In combinazione con il passaggio CollectLinearFunctions consente di raccogliere blocchi di dati consecutivi e di CXGate e SwapGate in un circuito e di risintetizzarli utilizzando l' algoritmo di Patel-Markov-Hayes.

  • Aggiunto un nuovo passaggio del transpiler LinearFunctionsToPermutations che sostituisce un elemento LinearFunction con un Permutation quando possibile.

  • FlowController (come ad esempio ConditionalController) possono ora essere annidate all'interno di un'istanza PassManager quando si usa il metodo PassManager.append() quando si utilizza il metodo Ciò consente di utilizzare una logica annidata per controllare l'esecuzione dei passaggi nel file PassManager. Ad esempio:

    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'oggetto pm PassManager eseguirà il passaggio BasisTranslator (nel passo unroll ) in ogni iterazione del ciclo se unroll_condition è soddisfatta.

  • I costruttori per le classi ZFeatureMap e ZZFeatureMap hanno un nuovo argomento di parola chiave parameter_prefix. Questo nuovo argomento viene utilizzato per impostare il prefisso dei parametri del circuito di codifica dei dati. Ad esempio:

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

    il circuito generato ZFeatureMap tutti i suoi parametri interni sono preceduti dal prefisso "my_prefix".

  • Il TemplateOptimization può ora lavorare con oggetti Gate che hanno ParameterExpression parametri. Un esempio illustrativo dell'uso di Parameters con TemplateOptimization è il seguente:

    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)

    output

    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
  • Il DAGOpNode, DAGInNode e DAGOutNode definiscono ora un metodo personalizzato __repr__ che produce una rappresentazione. Secondo la documentazione di Python, l'output è una rappresentazione di stringa che è approssimativamente equivalente alla stringa Python usata per creare un oggetto equivalente.

  • Le prestazioni del metodo SparsePauliOp.simplify() sono state notevolmente migliorate sostituendo l'uso di numpy.unique per calcolare gli elementi unici di un array con una nuova funzione simile implementata in Rust che non esegue il preordinamento dell'array.

  • Aggiunto un nuovo metodo equiv() alla classe SparsePauliOp per verificare l'equivalenza di un elemento SparsePauliOp con un altro SparsePauliOp oggetto. A differenza dell'operatore == che confronta gli operatori in modo elementare, equiv() confronta se due operatori sono equivalenti o meno. Ad esempio:

    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
  • Aggiunte nuove classi di backend fasulle da istantanee dei sistemi IBM Quantum basate sull'interfaccia BackendV2 e fornito una classe Target per ogni backend. BackendV2 sono state aggiunte versioni basate su tutti i backend esistenti, ad eccezione di tre vecchi backend FakeRueschlikon, FakeTenerife e FakeTokyo che non hanno file di snapshot disponibili, necessari per creare una nuova classe di backend fittizia basata su BackendV2.

    Questi nuovi backend falsi di V2 consentiranno di testare e sviluppare le nuove funzionalità introdotte da BackendV2 e Target come il miglioramento del transpiler.

  • Aggiunta di una nuova classe di gate XXMinusYYGate alla libreria dei circuiti (qiskit.circuit.library) per l'interazione XX-YY. Questo gate può essere utilizzato per implementare il gate bSwap e le sue potenze. Si presenta anche nella simulazione di modelli fermionici superconduttori.

  • Aggiunta di una nuova classe di gate, XXPlusYYGatealla libreria dei circuiti (qiskit.circuit.library). Questo gate è un'interazione XX+YY parametrata a 2 qubit, nota anche come gate XY, e si basa sul gate descritto in https://arxiv.org/abs/1912.04424.

  • I falsi backend FakeBogota, FakeManila, FakeRome e FakeSantiago , che si trovano nel modulo qiskit.providers.fake_provider , possono ora essere utilizzati come backend negli esperimenti Pulse, in quanto ora includono una macchina PulseDefaults creato da un'istantanea delle proprietà della macchina equivalente IBM Quantum.

  • Il passaggio ConsolidateBlocks ha un nuovo argomento di parola chiave nel suo costruttore, target. Questo argomento viene usato per specificare un oggetto Target che rappresenta il target di compilazione per il passaggio. Se viene specificato, sostituisce il kwarg di basis_gates . Se viene specificato un target, il passaggio rispetterà le porte e i qubit per le istruzioni definite nel target Target quando decide quali porte consolidare in un'unità.

  • La classe Target ha un nuovo metodo, instruction_supported() che serve a interrogare il target per vedere se un'istruzione (la combinazione di un'operazione e dei qubit su cui viene eseguita) è supportata dal backend modellato dall'oggetto Target.

  • Aggiunto un nuovo kwarg, metadata_serializer, alla funzione qpy.dump() per specificare una sottoclasse personalizzata di JSONEncoder da utilizzare per la serializzazione dell'attributo QuantumCircuit.metadata e un doppio kwarg metadata_deserializer alla funzione qpy.load() per specificare una sottoclasse JSONDecoder . Per impostazione predefinita, i campi dump() e load() tenteranno di serializzare e deserializzare JSON con il codificatore e il decodificatore json predefiniti di stdlib. Poiché QuantumCircuit.metadata può contenere qualsiasi dizionario Python, anche quelli con contenuti non serializzabili JSON dal codificatore predefinito, porterà a circuiti che non possono essere serializzati. Il nuovo argomento metadata_serializer per dump() consente agli utenti di specificare un JSONEncoder personalizzato che sarà usato con la chiamata interna json.dump() per la serializzazione del QuantumCircuit.metadata dizionario. Questo può essere abbinato al nuovo parametro metadata_deserializer della funzione qpy.load() per decodificare le codifiche JSON personalizzate. Se metadata_serializer è specificato su dump() ma metadata_deserializer non è specificato su load() il QPY verrà caricato, ma i metadati del circuito potrebbero non essere ricostruiti completamente.

    Ad esempio, se si vuole definire una serializzazione personalizzata per i metadati e poi caricarla, si può fare qualcosa di simile:

    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)
  • Il passaggio DenseLayout ha un nuovo argomento di parola chiave nel suo costruttore, target. Questo argomento viene usato per specificare un oggetto Target che rappresenta il target di compilazione per il passaggio. Se viene specificato, sostituisce gli altri argomenti del costruttore, coupling_map e backend_prop.

  • La classe Target ha un nuovo metodo, operation_names_for_qargs(). Questo metodo viene usato per ottenere i nomi delle operazioni (cioè la chiave di ricerca nella destinazione) per le operazioni su una data tupla qargs .

  • È stato aggiunto un nuovo passaggio DynamicalDecouplingPadding al modulo qiskit.transpiler.passes al modulo. Questo nuovo passaggio sostituisce quello esistente DynamicalDecoupling per lavorare con il nuovo flusso di pianificazione del transpiler. È una sottoclasse del passaggio BasePadding e dipende dal fatto che i passaggi di scheduling e di analisi dell'allineamento siano stati eseguiti prima di esso in una PassManager. Questo nuovo passaggio può accettare un argomento pulse_alignment che rappresenta un vincolo hardware per la tempistica di avvio della forma d'onda. La distanza tra le porte che compongono una sequenza di disaccoppiamento dinamico viene ora regolata per soddisfare questo vincolo, in modo che il circuito possa essere eseguito su hardware con il vincolo. Questo valore si trova solitamente in BackendConfiguration.timing_constraints. Inoltre, il passaggio ha anche un'opzione extra_slack_distribution per controllare come distribuire l'allentamento extra quando la durata della sequenza di disaccoppiamento dinamico creata è inferiore al tempo di inattività del circuito che si desidera riempire con la sequenza. L'impostazione predefinita è middle , identica al comportamento convenzionale. La nuova strategia split_edges suddivide uniformemente l'allentamento extra all'inizio e alla fine della sequenza, anziché aggiungerlo all'intervallo a metà della sequenza. In questo modo si può ottenere una migliore cancellazione del rumore, soprattutto quando pulse_alignment > 1.

  • La classe Z2Symmetries espone ora le tolleranze di soglia utilizzate per tagliare le piccole parti reali e immaginarie dei coefficienti. In questo modo è possibile controllare come vengono semplificati i coefficienti dell'operatore conico. Ad esempio:

    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,
    )

    Per impostazione predefinita, i coefficienti vengono tagliati con una tolleranza di tol=1e-14.

  • Aggiunto un metodo chop() alla classe SparsePauliOp che tronca singolarmente le parti reali e immaginarie dei coefficienti. Questo è diverso dal metodo SparsePauliOp.simplify() che rimuove un coefficiente solo se il valore assoluto è prossimo a 0. Ad esempio:

    >>> 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])

    Si noti che il metodo chop non accumula i coefficenti dello stesso Paulis, ad es.

    >>> op = SparsePauliOp(["X", "X"], coeffs=[1+1e-17j, 1e-17+1j)
    >>> op.chop()
    SparsePauliOp(['X', 'X'],
                  coeffs=[1.+0.j, 0.+1.j])
  • Aggiunto un nuovo kwarg, target, al costruttore per il passaggio di GatesInBasis per il passaggio del transpiler. Questo nuovo argomento può essere usato per specificare facoltativamente un oggetto Target che rappresenta il backend. Se impostato, questo parametro Target verrà utilizzato per determinare se un elemento DAGCircuit contiene porte al di fuori dell'insieme di basi e l'argomento basis_gates non verrà utilizzato.

  • Aggiunto il supporto parziale per l'esecuzione sulle piattaforme ppc64le e s390x Linux. Questo rilascio avvierà la pubblicazione di binari precompilati per le piattaforme ppc64le e s390x Linux su tutte le versioni Python. Tuttavia, a differenza di altre piattaforme supportate, non tutte le dipendenze upstream di Qiskit supportano ancora queste piattaforme. Quindi potrebbe essere necessario un compilatore C/C++ per costruire e installare queste dipendenze e un semplice pip install qiskit-terra con un ambiente Python funzionante non sarà sufficiente per installare Qiskit. Inoltre, questi stessi vincoli ci impediscono di testare le ruote precompilate prima di pubblicarle, quindi le stesse garanzie sul supporto della piattaforma che esistono per le altre piattaforme non si applicano qui.

  • Il Gradient e QFI possono ora calcolare la parte immaginaria dei gradienti del valore di aspettativa. Quando si utilizza una base di misurazione diversa, ad es. -Y invece di Z, possiamo misurare la parte immaginaria dei gradienti La base di misura può essere impostata con l'argomento aux_meas_op .

    Per i gradienti, aux_meas_op = Z calcola 0.5Re[(⟨ψ(ω)|)O(θ)|dωψ(ω)〉] e aux_meas_op = -Y calcola 0.5Im[(⟨ψ(ω)|)O(θ)|dωψ(ω)〉]. Per i QFI, aux_meas_op = Z calcola 4Re[(dω⟨<ψ(ω)|)(dω|ψ(ω)〉)] e aux_meas_op = -Y calcola 4Im[(dω⟨<ψ(ω)|)(dω|ψ(ω)〉)]. Ad esempio:

    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 supporta ora il lavoro con i parametri di un'istruzione. Ogni voce di un InstructionDurations consiste ora in una tupla di (inst_name, qubits, duration, parameters, unit). Ciò consente a un'istruzione di InstructionDurations di definire la durata di un'istruzione con un certo valore di parametro, per tenere conto di durate diverse con valori di parametro diversi su un'istruzione che richiede un parametro numerico.

  • Aggiunto un nuovo valore per l'argomento della parola chiave style nella funzione cassetto del circuito circuit_drawer() e QuantumCircuit.draw() metodo, iqx_dark. Quando style è impostato su iqx_dark con il backend del cassetto mpl , la visualizzazione di output userà uno schema di colori simile a quello della modalità scura usato dal compositore IBM Quantum. Ad esempio:

    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")
  • Al nuovo modulo sono stati aggiunti diversi controllori di dipendenze pigre qiskit.utils.optionalsche possono essere utilizzati per verificare se alcune funzionalità di Qiskit sono disponibili. Ad esempio, è possibile chiedere se Qiskit ha rilevato la presenza di matplotlib chiedendo if qiskit.utils.optionals.HAS_MATPLOTLIB. Questi oggetti tentano di importare le loro dipendenze solo quando vengono interrogati, in modo da poterli usare nel codice di runtime senza influenzare il tempo di importazione.

  • Il tempo di importazione di qiskit è stato notevolmente migliorato, soprattutto per chi ha installato molte delle dipendenze opzionali di Qiskit Terra.

  • La funzione marginal_counts() supporta ora la marginalizzazione del campo memory di un oggetto di input Result di un oggetto di input. Ad esempio, se l'argomento di ingresso result è un oggetto qiskit Result ottenuto da una misura a 4 qubit, possiamo marginalizzare sul primo qubit con:

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

    L'output è:

    ['0x0', '0x1', '0x2', '0x3', '0x4', '0x5', '0x6', '0x7']
    ['0x0', '0x1', '0x0', '0x1', '0x0', '0x1', '0x0', '0x1']
  • L'interno dell'algoritmo StochasticSwap sono stati reimplementati per essere multithread e sono ora scritti nel linguaggio di programmazione Rust invece che in Cython. Questo aumenta in modo significativo le prestazioni in fase di esecuzione del passaggio del compilatore e per estensione transpile() quando viene eseguito con optimization_level 0, 1 e 2. Per impostazione predefinita, il passaggio utilizzerà fino al numero di CPU logiche del sistema locale, ma è possibile controllare il numero di thread utilizzati dal passaggio impostando la variabile d'ambiente RAYON_NUM_THREADS su un valore intero. Ad esempio, impostando RAYON_NUM_THREADS=4 il programma StochasticSwap con 4 thread.

  • È disponibile una nuova variabile d'ambiente QISKIT_FORCE_THREADS che consente agli utenti di controllare direttamente se le porzioni di codice potenzialmente multithread di Qiskit verranno eseguite in più thread. Attualmente è utilizzato solo dal passaggio StochasticSwap ma probabilmente in futuro sarà utilizzato anche da altre parti di Qiskit. Quando questa variabile env è impostata su TRUE , qualsiasi codice multithread in Qiskit Terra utilizzerà sempre più thread, indipendentemente da qualsiasi altra condizione di runtime che avrebbe potuto far sì che la funzione utilizzasse una variante a thread singolo. Ad esempio, in StochasticSwap se il passaggio viene eseguito come parte di una chiamata transpile() con > 1 circuito che viene eseguito in parallelo con multiprocessing tramite parallel_map() il StochasticSwap non utilizzerà thread multipli per evitare di sovrascrivere potenzialmente le risorse della CPU. Tuttavia, se si desidera utilizzare più thread nel passaggio insieme a più processi, è possibile impostare QISKIT_FORCE_THREADS=TRUE.

  • Le nuove classi di backend fasulle sono disponibili all'indirizzo qiskit.providers.fake_provider. Questi includono le versioni simulate di ibm_cairo, ibm_hanoi, ibmq_kolkata, ibm_nairobi e ibm_washington. Come per gli altri backend fasulli, questi includono istantanee dei dati di calibrazione e di errore presi dal sistema reale e possono essere usati per test, compilazione e simulazione locali.

  • Introduzione di una nuova classe StatePreparation. Questa classe consente agli utenti di preparare uno stato desiderato allo stesso modo di Initialize senza che il reset venga applicato automaticamente.

    Ad esempio, per preparare un qubit nello stato (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()

    L'output è il seguente:

         ┌─────────────────────────────────────┐
    q_0: ┤ State Preparation(0.70711,-0.70711)
         └─────────────────────────────────────┘
  • Il Optimize1qGates il passaggio del transpiler ora supporta l'ottimizzazione di U1Gate, U2Gate, e PhaseGate con parametri non vincolati in un circuito. In precedenza, se questi gate avevano parametri non vincolati, il passaggio non li utilizzava. Ad esempio:

    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)

    saranno combinati al circuito con un solo gate a un solo qubit:

    qc = QuantumCircuit(1)
    qc.u1(2*phi + alpha + 0.3, 0)
  • I metodi Pauli.evolve() e PauliList.evolve() hanno ora un nuovo argomento chiave, frame, che viene utilizzato per eseguire un'evoluzione di un Pauli da parte di un Clifford. Se frame='h' (predefinito) esegue l'evoluzione del quadro di Heisenberg di un Pauli da parte di un Clifford ( P=CPCP' = C^\dagger P C ), e se frame='s' esegue l'evoluzione del quadro di Schrödinger di un Pauli da parte di un Clifford ( P=CPCP' = C P C^\dagger ). Quest'ultima opzione consente un calcolo più rapido ed è utile in alcuni casi. Questa nuova opzione rende il calcolo del metodo di decomposizione greedy Clifford in decompose_clifford molto più veloce.

  • Aggiunto un nuovo modulo a Qiskit: qiskit.primitives. Il modulo delle primitive è quello in cui vengono definite le API che forniscono diverse astrazioni per il calcolo di alcune funzioni comuni da QuantumCircuit che astrae i dettagli dell'esecuzione sottostante su Backend. Ciò consente agli algoritmi e alle applicazioni di livello superiore di concentrarsi sull'esecuzione dei calcoli, senza doversi preoccupare dell'esecuzione e dell'elaborazione dei risultati, e di disporre di un'interfaccia standardizzata per i calcoli comuni. Ad esempio, la stima di un valore di aspettativa di un circuito quantistico e di un'osservabile può essere eseguita da qualsiasi classe che implementa la classe e consumata in modo standardizzato, indipendentemente dall'implementazione sottostante BaseEstimator classe e consumata in modo standardizzato, indipendentemente dall'implementazione sottostante. Le applicazioni possono quindi essere scritte utilizzando direttamente l'interfaccia primitiva.

    Per iniziare, il modulo contiene due tipi di primitive, la Sampler (vedere BaseSampler per la definizione della classe astratta) e Estimator (vedere BaseEstimator per la definizione della classe astratta). Le implementazioni di riferimento sono incluse nel modulo qiskit.primitives e sono costruite utilizzando il modulo qiskit.quantum_info che eseguono una simulazione ideale delle operazioni primitive. L'aspettativa è che i pacchetti dei provider offrano le proprie implementazioni di queste interfacce per i provider che possono implementare in modo efficiente il protocollo in modo nativo (tipicamente utilizzando un runtime classico). Inoltre, in futuro, per i provider che non offrono un'implementazione nativa delle primitive, sarà fornito un metodo che consentirà di costruire oggetti primitivi a partire da un oggetto Backend.

  • Aggiunto un nuovo modulo, qiskit.qpyche contiene le funzionalità precedentemente esposte in qiskit.circuit.qpy_serialization. Le funzioni pubbliche precedentemente esposte su qiskit.circuit.qpy_serialization, dump() e load() sono ora disponibili in questo nuovo modulo (anche se sono ancora accessibili da qiskit.circuit.qpy_serialization , ma questo sarà deprecato in una prossima versione). Questo nuovo modulo è stato aggiunto nell'interesse della direzione futura del formato di file QPY, che nelle versioni future supporterà la rappresentazione di pulse Schedule e ScheduleBlock oltre agli oggetti QuantumCircuit oggetti che supporta oggi.

  • Aggiunto un nuovo attributo, qubit_properties alla classe Target classe. Questo attributo contiene un elenco di QubitProperties oggetti per ogni qubit del target. Ad esempio:

    target.qubit_properties[2]

    conterrà il valore QubitProperties per il qubit numero 2 nel target.

    Per BackendV2 autori, se in precedenza si definiva QubitProperties direttamente nella propria implementazione BackendV2 sovrascrivendo il parametro BackendV2.qubit_properties() questo funzionerà ancora bene. Tuttavia, se si sposta la definizione all'oggetto sottostante Target e si rimuove l'implementazione specializzata BackendV2.qubit_properties() che consentirà di utilizzare le proprietà dei qubit nel transpiler e di mantenere la compatibilità dell'API con l'implementazione precedente.

  • Aggiunta di una nuova funzione, qiskit.algorithms.eval_observables()che viene utilizzata per valutare gli osservabili, dato un limite QuantumCircuit. Ha origine da un metodo privato, _eval_aux_ops(), della classe qiskit.algorithms.VQE ma la nuova funzione eval_observables() è ora più generale e può essere utilizzata in altri algoritmi, ad esempio in quelli di evoluzione temporale.

  • La strategia di ricerca delle basi nel BasisTranslator nel passaggio del transpiler è stata modificata in una variante della ricerca di Dijkstra che migliora notevolmente le prestazioni di runtime del passaggio quando si cerca di puntare a una base irraggiungibile.

  • Il passaggio DenseLayout il passaggio del transpiler è ora multithread, il che migliora notevolmente le prestazioni in fase di esecuzione del passaggio. Per impostazione predefinita, utilizza il numero di CPU logiche del sistema locale, ma è possibile controllare il numero di thread utilizzati dal passaggio impostando la variabile d'ambiente RAYON_NUM_THREADS su un valore intero. Ad esempio, impostando RAYON_NUM_THREADS=4 si eseguirà il DenseLayout con 4 thread.

  • I calcoli interni di Statevector.expectation_value() e DensityMatrix.expectation_value() sono stati reimplementati nel linguaggio di programmazione Rust. Questa nuova implementazione è multithread e, per impostazione predefinita, per un oggetto Statevector o DensityMatrix >= 19 qubit verrà creato un pool di thread con il numero di CPU logiche disponibili sul sistema locale. È possibile controllare il numero di thread utilizzati impostando la variabile d'ambiente RAYON_NUM_THREADS su un valore intero. Ad esempio, impostando RAYON_NUM_THREADS=4 si utilizzeranno solo 4 thread nel pool di thread.

  • Aggiunto un nuovo SparsePauliOp.from_sparse_list() che prende un iterabile, dove gli elementi rappresentano termini di Pauli che sono a loro volta sparsi, così che "XIIIIIIIIIIIIIIIX" può ora essere scritto come ("XX", [0, 16]). Ad esempio, l'operatore

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

può ora essere costruito come

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)])

Ciò facilita la costruzione di operatori molto radi su molti qubit, come spesso accade per gli hamiltoniani di Ising.

  • Il passo del transpiler UnitarySynthesis ha un nuovo argomento di parola chiave nel suo costruttore, target. Si può usare per specificare facoltativamente un oggetto Target che rappresenta il target di compilazione per il passaggio. Quando viene specificato, sostituisce i valori impostati per basis_gates, coupling_map e backend_props.

  • La classe UnitarySynthesisPlugin ha un nuovo attributo opzionale che le implementazioni possono aggiungere, supports_target. Se un plugin ha questo attributo impostato su True , un oggetto Target verrà passato nel payload di options sotto il campo target . L'aspettativa è che questo Target sarà utilizzato al posto di coupling_map, gate_lengths, basis_gates e gate_errors.

  • È stato introdotto un nuovo flusso di lavoro per la creazione di oggetti per la schedulazione PassManager oggetti per la programmazione QuantumCircuit oggetti nel transpiler. Nel nuovo flusso di lavoro, i passaggi di pianificazione e allineamento sono tutti oggetti che aggiornano solo l'insieme di proprietà del gestore dei passaggi AnalysisPass che aggiornano solo l'insieme di proprietà del gestore dei passaggi, in particolare la nuova voce dell'insieme di proprietà node_start_time, che contiene l'ora di inizio assoluta di ciascun opnode. Una soluzione separata TransformationPass come PadDelay viene successivamente utilizzato per applicare la schedulazione al DAG. Questo nuovo flusso di lavoro è più efficiente e può correggere i vincoli temporali aggiuntivi esposti da un backend.

    In precedenza, la catena di passaggi veniva implementata come scheduling -> alignment che erano entrambi passaggi di trasformazione, quindi c'erano più istanze ricreate durante ogni passaggio DAGCircuit ricreate durante ogni passaggio. Inoltre, in ogni passaggio è stato effettuato uno scheduling per ottenere l'orario di inizio delle istruzioni. Ora la catena di passaggi richiesta diventa scheduling -> alignment -> padding dove l'aggiornamento avviene solo alla fine con il passaggio DAGCircuit aggiornamento avviene solo alla fine con il passaggio padding .

    Per coloro che creano oggetti personalizzati PassManager che coinvolgono la programmazione dei circuiti, sarà necessario adattare il proprio PassManager per inserire uno dei passaggi di BasePadding (attualmente o PadDelay o PadDynamicalDecoupling può essere utilizzato) alla fine della catena di passaggi di schedulazione. Senza il passaggio di padding, i passaggi di schedulazione non si rifletteranno nel circuito di uscita del metodo run() del metodo personalizzato PassManager.

    Ad esempio, se in precedenza si costruiva il file PassManager con qualcosa come:

    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)

    si può invece utilizzare:

    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)

    che sarà più efficiente e allineerà le istruzioni in base a eventuali vincoli hardware.

  • Aggiunto un nuovo passaggio di transpiler ConstrainedReschedule pass. Il ConstrainedReschedule considera sia i vincoli di allineamento hardware che possono essere definiti in un oggetto BackendConfigurationpulse_alignment e acquire_alignment. Questa nuova classe sostituisce la precedente classe AlignMeasures in quanto esegue lo stesso allineamento (tramite l'insieme di proprietà) per le istruzioni di misura, oltre all'allineamento generale delle istruzioni. Impostando l'argomento del vincolo acquire_alignment per il passo ConstrainedReschedule è un sostituto immediato di AlignMeasures se abbinato a un nuovo passaggio BasePadding .

  • Aggiunti due nuovi passaggi di transpiler ALAPScheduleAnalysis e ASAPScheduleAnalysis che sostituiscono i passaggi ALAPSchedule e ASAPSchedule come parte del flusso di lavoro del transpiler rielaborato per schedling. I nuovi passaggi eseguono lo stesso scheduling, ma nel set di proprietà e affidandosi a un passaggio di BasePadding per regolare il circuito in base a tutte le analisi di allineamento dello scheduling.

    Il comportamento standard di questi passaggi allinea anche l'ordinamento temporale con l'ordinamento topologico dei nodi del DAG. Questa modifica può influenzare il risultato della programmazione se include operazioni condizionali o la misurazione simultanea di due qubit con lo stesso registro classico (edge-case). Per riprodurre il comportamento convenzionale, impostare clbit_write_latency identico alla lunghezza dell'istruzione di misura.

    Ad esempio, si consideri la programmazione di un circuito di ingresso come:

         ┌───┐┌─┐
    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))

    Come si può vedere nella visualizzazione della timeline, la misura su q_2 inizia prima del gate condizionale X su q_1, che sembra essere opposto all'ordine topologico del nodo. Questo comportamento è previsto anche perché l'accesso in scrittura del clbit avviene sul bordo finale dell'istruzione di misura, mentre l'accesso in lettura del gate condizionale avviene sul bordo iniziale dell'istruzione. In questo modo, l'ordinamento topologico viene conservato sul timeslot del registro classico, che non viene catturato dalla visualizzazione della timeline. Tuttavia, questo presuppone un progetto di microarchitettura particolare e non è necessario che il circuito sia programmato in questo modo.

    Utilizzando la configurazione predefinita dei passaggi, il circuito è programmato come segue.

    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))

    Si noti che clbit è bloccato per tutto l'intervallo dell'istruzione di misura. Questo comportamento è stato progettato sulla base del Qiskit Pulse, in cui l'istruzione acquire prende AcquireChannel e MemorySlot che non possono sovrapporsi ad altre istruzioni, cioè è vietato l'accesso simultaneo alla memoria da parte delle diverse istruzioni. In questo modo si allinea sempre l'ordinamento temporale con l'ordinamento topologico dei nodi.

  • Aggiunto un nuovo passaggio del transpiler PadDynamicalDecoupling che sostituisce il passaggio DynamicalDecoupling come parte del flusso di lavoro del transpiler rielaborato per la programmazione. Questo nuovo passaggio inserisce nel circuito sequenze di disaccoppiamento dinamico, in base alle analisi di programmazione e allineamento effettuate nei passaggi precedenti.

  • La funzione plot_gate_map() e le funzioni costruite sopra di essa, plot_error_map() e plot_circuit_layout()hanno un nuovo argomento chiave, qubit_coordinates. Questo argomento accetta una sequenza di coordinate 2D da utilizzare per tracciare ogni qubit nel backend da visualizzare. Se specificata, questa sequenza deve avere una lunghezza pari al numero di qubit del backend e verrà utilizzata al posto del comportamento predefinito.

  • La funzione plot_gate_map() e le funzioni costruite sopra di essa, plot_error_map() e plot_circuit_layout()sono ora in grado di tracciare qualsiasi backend, non solo quelli con un numero di qubit uguale a uno dei backend di IBM. Si affida alla funzione retworkx spring_layout() per generare il layout della visualizzazione. Se il layout predefinito non funziona con il particolare grafico di accoppiamento di un backend, si può usare la funzione qubit_coordinates per impostare un layout personalizzato.

  • La funzione plot_gate_map() e le funzioni costruite sopra di essa, plot_error_map() e plot_circuit_layout()sono ora in grado di funzionare con un backend BackendV2 basato su backend. In precedenza, queste funzioni funzionavano solo con i backend BaseBackend o BackendV1 basati su backend.

  • Aggiunto un nuovo passaggio di transpiler, SetIOLatency. Questo passaggio prende due argomenti clbit_write_latency e conditional_latency per definire la latenza di I/O per i bit classici e le condizioni classiche su un backend. Questo passaggio definirà quindi questi valori nel set di proprietà del gestore del passaggio per consentire ai successivi passaggi di schedulazione e allineamento di correggere queste latenze e fornire un output di schedulazione più preveggente di un circuito dinamico.

  • È stato aggiunto un nuovo passaggio per il transpiler PadDelay è stato aggiunto. Questo passaggio riempie il tempo di inattività dei fili dei qubit con Delay istruzioni. Questo passaggio fa parte del nuovo flusso di lavoro per la programmazione dei passaggi nel transpiler e dipende da un passaggio di analisi di programmazione (come ad esempio ALAPScheduleAnalysis o ASAPScheduleAnalysis) e da eventuali passaggi di allineamento (come ad esempio ConstrainedReschedule) da eseguire prima di PadDelay.

  • Il passaggio VF2Layout ha un nuovo argomento di parola chiave, target , che viene utilizzato per fornire un oggetto Target per il passaggio. Quando viene specificato, il parametro Target sarà utilizzato dal passaggio per tutte le informazioni sul dispositivo di destinazione. Se viene specificata, l'opzione target avrà la priorità sugli argomenti coupling_map e properties .

  • Consentire i callables come ottimizzatori in VQE e QAOA. Ora, l'ottimizzatore può essere uno degli ottimizzatori di Qiskit, come ad esempio SPSA oppure un callable con la seguente firma:

    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 firma di cui sopra permette anche di passare direttamente qualsiasi minimizzatore di SciPy, per esempio come

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

Problemi noti

  • Quando si esegue parallel_map() (che viene eseguito internamente da funzioni sensibili alle prestazioni come transpile() e assemble()) in un sottoprocesso lanciato al di fuori di parallel_map()è possibile che il dispatch parallelo eseguito all'interno di parallel_map() si blocchi e non ritorni mai. Ciò è dovuto a problemi upstream in CPython relativi al metodo predefinito per lanciare i sottoprocessi su Linux e macOS con Python 3.7 (vedere https://bugs.python.org/issue40379 per maggiori dettagli). Se si verifica questo problema, si hanno due opzioni: si possono rimuovere i processi paralleli annidati, in quanto la chiamata a parallel_map() da un processo principale dovrebbe funzionare bene; oppure si può chiamare manualmente il modulo multiprocessing della libreria standard di CPython per eseguire un dispatch parallelo simile da un sottoprocesso, ma usare i metodi di lancio "spawn" o "forkserver" per evitare che le cose si blocchino e non ritornino mai.

Note sull'aggiornamento

  • Le classi Qubit, Clbit e AncillaQubit hanno ora l'attributo __slots__ . Questo per ridurre l'utilizzo della memoria. Come effetto collaterale, non possono più avere dati arbitrari allegati come attributi. È molto improbabile che questo abbia un effetto sul codice a valle, a parte i vantaggi in termini di prestazioni.

  • La dipendenza del nucleo retworkx ha avuto il suo requisito di versione spostato a 0.11.0, da 0.10.1. Questo migliora le prestazioni del passaggio di transpilazione ConsolidateBlocks.

  • La versione minima supportata di symengine è ora 0.9.0. Questo è stato necessario per migliorare la compatibilità con il modulo Python ' pickle che è usato internamente come parte del dispatch parallelo con parallel_map().

  • Il valore predefinito di QISKIT_PARALLEL quando viene eseguito con Python 3.9 su Linux è ora impostato su TRUE. Ciò significa che quando si esegue parallel_map() o le funzioni che lo chiamano internamente, come ad esempio transpile() e assemble()la funzione verrà eseguita in più processi e dovrebbe avere prestazioni migliori in fase di esecuzione. Questa modifica è stata apportata perché i problemi di affidabilità del dispacciamento parallelo sembrano essere stati risolti (vedere #6188 per maggiori dettagli). Se si riscontrano ancora problemi, è possibile disabilitare il multiprocessing e tornare al comportamento predefinito precedente impostando la variabile d'ambiente QISKIT_PARALLEL su FALSE o impostando l'opzione parallel su False nel file di configurazione dell'utente (si prega inoltre di segnalare un problema in modo da poter tenere traccia di qualsiasi problema relativo al multiprocessing).

  • La classe deprecata MSGate , precedentemente presente in qiskit.circuit.library è stata rimossa. È stato originariamente deprecato nella versione 0.16.0. Si dovrebbe invece utilizzare la classe GMS che consente di creare un gate MS equivalente a 2 qubit, oltre a un MSGate per qualsiasi numero di qubit.

  • Il metodo precedentemente deprecato mirror() della classe Instruction è stato rimosso. È stato originariamente deprecato nella versione 0.15.0. Si dovrebbe invece utilizzare Instruction.reverse_ops().

  • Il metodo num_ancilla_qubits() , precedentemente deprecato, degli elementi qiskit.circuit.library.PiecewiseLinearPauliRotations e qiskit.circuit.library.WeightedAdder è stato rimosso. È stato originariamente deprecato nella versione 0.16.0. Si devono invece utilizzare i metodi PiecewiseLinearPauliRotations.num_ancillas() e WeightedAdder.num_ancillas() .

  • L'argomento reverse , precedentemente deprecato, nel costruttore della classe PolynomialPauliRotations è stato rimosso. È stato originariamente deprecato nella versione 0.15.0. Si deve invece utilizzare il metodo QuantumCircuit.reverse_bits() per invertire il PolynomialPauliRotations circuito, se necessario.

  • L'argomento precedentemente deprecato angle nei costruttori degli oggetti C3SXGate e C3XGate è stato rimosso. È stato originariamente deprecato nella versione 0.17.0. Per le porte X frazionarie a 3 controlli è invece possibile utilizzare il metodo C3XGate.power() .

  • Supporto per l'utilizzo degli oggetti np.ndarray come parte dell'attributo params di un oggetto Gate è stato rimosso. Questa funzione è stata deprecata da quando Qiskit Terra 0.16.0 e ora non funziona più. Si dovrebbe invece creare una nuova sottoclasse di Gate e consentire esplicitamente un input np.ndarray sovraccaricando il metodo validate_parameter() .

  • Un nuovo extra csp-layout-pass è stato aggiunto al target di installazione di pip install qiskit-terra ed è anche incluso nell'extra all . Questo non ha effetto in Qiskit Terra 0.20, ma a partire da Qiskit Terra 0.21, le dipendenze necessarie solo per il passaggio del transpiler saranno declassate da requisiti a opzioni e installate da questo extra CSPLayout saranno declassate da requisiti a opzioni e installate da questo extra. È possibile preparare un pacchetto che dipende da questo passaggio impostando i suoi requisiti (o il comando pip install ) per puntare a qiskit-terra[csp-layout-pass].

  • Il supporto per l'esecuzione con Python 3.6 è stato rimosso. Per eseguire Qiskit è necessaria una versione minima Python di 3.7.

  • La classe AmplitudeEstimator eredita ora dalla classe ABC della libreria standard Python. Ciò richiede a qualsiasi sottoclasse di implementare il metodo estimate() mentre prima non era richiesto. Questo è stato fatto perché l'intento originale della classe era quello di essere sempre una classe figlia di ABC, dato che l'elemento estimate() è necessario per il funzionamento di un AmplitudeEstimator oggetto. Tuttavia, se in precedenza si definiva una sottoclasse AmplitudeEstimator che non implementava estimate() ora si otterrà un errore.

  • L'errore sollevato da HoareOptimizer se la dipendenza opzionale z3 non è disponibile è cambiato da TranspilerError a MissingOptionalLibraryError (che è sia un elemento QiskitError e un ImportError). Questo è stato fatto per essere coerente con le altre dipendenze opzionali.

  • Su Linux, il supporto minimo della libreria è stato aumentato dalla VM manylinux2010 a manylinux2014. Questo rispecchia cambiamenti simili in Numpy e Scipy. Non dovrebbero esserci effetti significativi per la maggior parte degli utenti, a meno che il vostro sistema non contenga ancora una versione molto vecchia di glibc.

  • La funzione marginal_counts() quando viene chiamata con un oggetto Result ora marginalizzerà il campo memory dei dati dell'esperimento se è impostato nell'input Result. In precedenza, il campo memory nell'input non era marginalizzato. Questa modifica è stata apportata perché il comportamento precedente faceva sì che il campo counts non coincidesse con il campo memory dopo che era stato richiamato il campo marginal_counts() è stato chiamato. Se si desidera ripristinare il comportamento precedente, si può impostare marginalize_memory=None come argomento a marginal_counts() che non marginalizzerà il campo memory .

  • Il StochasticSwap può restituire risultati diversi con lo stesso valore di seme impostato. Ciò è dovuto alla riscrittura interna del passaggio del transpiler per migliorare le prestazioni in fase di esecuzione. Tuttavia, questo significa che se si esegue transpile() con optimization_level 0, 1 (il valore predefinito) o 2 con un valore impostato per seed_transpiler , si potrebbe ottenere un output con una diversa mappatura dello swap presente dopo l'aggiornamento a Qiskit Terra 0.20.0.

  • Per compilare Qiskit Terra dai sorgenti è ora necessario un compilatore Rust. Ciò è dovuto alla riscrittura interna del passaggio di StochasticSwap che migliora notevolmente le prestazioni del transpiler in fase di esecuzione. Il compilatore rust può essere facilmente installato usando rustup, che si trova qui: https://rustup.rs/

  • L'attributo name della classe PauliEvolutionGate è stato modificato in modo che sia sempre "PauliEvolution". Questa modifica è stata apportata per essere coerente con le altre porte di Qiskit e consente alle altre parti di Qiskit di identificare rapidamente quando una particolare operazione in un circuito è un'operazione di tipo "a" PauliEvolutionGate. Ad esempio, consente di srotolare le porte dell'evoluzione di Pauli.

    In precedenza, il nome conteneva gli operatori evoluti, che ora sono disponibili tramite l'attributo PauliEvolutionGate.label . Se si disegna un circuito con un PauliEvolutionGate il cancello mostrerà comunque la stessa informazione, ovvero quali cancelli si stanno evolvendo.

  • I metodi precedentemente deprecati:

    • 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

    che erano stati originariamente deprecati nella versione di Qiskit Terra 0.18.0 sono stati rimossi e non funzioneranno più.

  • La classe qiskit.algorithms.VariationalAlgorithm è ora definita come una classe base astratta (ABC) che richiederà alle classi che ereditano da essa di definire sia un metodo getter che setter VariationalAlgorithm.initial_point .

  • Il kwarg pass_manager per la funzione transpile() è stato rimosso. È stato originariamente deprecato nella versione 0.13.0. Il metodo preferito per transpilare un circuito con un oggetto PassManager è utilizzare il metodo run() dell'oggetto PassManager dell'oggetto.

  • La classe ParametrizedSchedule , precedentemente deprecata, è stata rimossa e non esiste più. Questa classe è stata deprecata con la release 0.17.0. Invece di usare questa classe, si possono parametrizzare direttamente i metodi Schedule o ScheduleBlock specificando un oggetto Parameter all'argomento dell'impulso parametrico.

  • Il modulo qiskit.circuit.library.probability_distributions è stato rimosso e non esiste più, come da avviso di deprecazione di qiskit-terra 0.17.0 (rilasciato il 1° aprile 2021). Le classi interessate sono UniformDistribution, NormalDistribution e LogNormalDistribution. Vengono tutti spostati nella libreria qiskit-finance, nel modulo della libreria dei circuiti: qiskit_finance.circuit.library.probability_distributions.

  • La precedente classe qiskit.test.mock.fake_mumbai_v2.FakeMumbaiV2 è stata rinominata in FakeMumbaiFractionalCX per differenziarla dal falso backend basato sul dispositivo di Mumbai, BackendV2 per il dispositivo IBM di Mumbai, qiskit.test.mock.backends.FakeMumbaiV2. Se in precedenza ci si affidava alla classe FakeMumbaiV2 per ottenere un falso backend che avesse applicazioni frazionarie di CXGate definite nel suo target, è necessario usare la classe FakeMumbaiFractionalCX , poiché FakeMumbaiV2 non avrà più quelle definizioni di gate extra nel suo file Target.

  • Il risolutore utilizzato da QuantumCircuit.append() (e di conseguenza tutti i metodi che aggiungono un'istruzione a un oggetto QuantumCircuit) per convertire gli specificatori di bit è stato modificato per renderlo più veloce e affidabile. Alcuni costrutti come:

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

    funzionerà ora dove prima sollevava erroneamente un errore, ma alcuni input patologici come:

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

    ora darà luogo a errori laddove in precedenza potevano avere occasionalmente (erroneamente) successo. Per quasi tutti gli utilizzi corretti, non dovrebbero esserci cambiamenti degni di nota, se non una generale velocizzazione.

  • Il metodo interno semipubblico QuantumCircuit._append() non controlla più i tipi dei suoi input e assume che non ci siano duplicati non validi nei suoi elenchi di argomenti. Questa funzione viene utilizzata da alcune parti interne di Qiskit e di altre librerie per creare istanze il più rapidamente possibile, saltando il controllo degli errori quando si sa che i dati sono già corretti QuantumCircuit il più rapidamente possibile, saltando il controllo degli errori quando si sa che i dati sono già corretti. In generale, gli utenti o le funzioni che accettano dati dell'utente dovrebbero utilizzare il metodo public QuantumCircuit.append() che risolve gli specificatori di bit interi, trasmette i suoi argomenti e verifica la correttezza degli input.

  • Cython non è più una dipendenza di compilazione di Qiskit Terra e non è più necessario installarlo quando si costruisce Qiskit Terra dai sorgenti.

  • I passmanager preimpostati in qiskit.transpiler.preset_passmanagers per tutti i livelli di ottimizzazione 2 e 3, generati da level_2_pass_manager() e level_3_pass_manager() sono stati modificati in modo da eseguire l'opzione VF2Layout per impostazione predefinita prima del passaggio di layout. Il passaggio VF2Layout verifica rapidamente se è possibile trovare un layout perfetto e sostituisce ciò che è stato fatto in precedenza per i livelli di ottimizzazione 2 e 3 che utilizzavano una combinazione di TrivialLayout e CSPLayout per cercare di trovare un layout perfetto. Questo comporterà un comportamento potenzialmente diverso quando transpile() viene richiamato per impostazione predefinita, in quanto rimuove un percorso predefinito per tutti i livelli di ottimizzazione >=2 di utilizzo di un layout banale (in cui circuit.qubits[0] è mappato sul qubit fisico 0, circuit.qubits[1] è mappato sul qubit fisico 1 e così via), assumendo che il layout banale sia perfetto. Se il caso d'uso dipende dal layout banale, è possibile richiederlo esplicitamente in fase di transpiling, specificando layout_method="trivial" quando si chiama il file transpile().

  • Il gestore dei passaggi preimpostato per il livello di ottimizzazione 1 (quando si chiama transpile() con optimization_level=1 o quando non è impostato alcun argomento optimization_level ) come generato da level_1_pass_manager() è stato modificato in modo che VF2Layout viene richiamato per impostazione predefinita per verificare rapidamente se è possibile trovare un layout perfetto prima dell'esecuzione del comando DenseLayout. Tuttavia, a differenza di quanto accade con i livelli di ottimizzazione 2 e 3, prima dell'esecuzione viene ancora tentato un layout banale VF2Layout e se la mappatura è perfetta, viene utilizzato l'output di VF2Layout verrà utilizzato.

Note di deprecazione

  • L'argomento max_credits di execute()e tutte le configurazioni di Qobj (ad es. QasmQobjConfig e PulseQobjConfig), è deprecato e sarà rimosso in una prossima versione. Il sistema di crediti non è più in uso nei backend di IBM Quantum da due anni e l'opzione non ha alcun effetto. Non è necessaria alcuna alternativa. Ad esempio, se si chiama execute() come:

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

    si può semplicemente omettere l'argomento max_credits :

    job = execute(qc, backend, shots=4321)
  • L'utilizzo di un intero dispari per l'argomento order nel costruttore della classe SuzukiTrotter è deprecato e non funzionerà più nelle prossime versioni. Le formule del prodotto utilizzate dal SuzukiTrotter sono definite solo quando l'ordine è pari, poiché le formule del prodotto Suzuki sono simmetriche.

  • I kwarg qregs, cregs, layout e global_phase delle classi MatplotlibDrawer, TextDrawing e QCircuitImage e il kwarg calibrations della classe MatplotlibDrawer sono ora deprecati e saranno rimossi in una release successiva.

Correzioni di bug

  • Corretto un errore nelle funzioni di conversione dei circuiti circuit_to_gate() e circuit_to_instruction() (e i loro metodi di circuito associati QuantumCircuit.to_gate() e QuantumCircuit.to_instruction()) quando si agisce su un circuito con bit senza registro o con bit in più di un registro.

  • È stato risolto un problema per cui la chiamata QuantumCircuit.copy() sui circuiti "body" di un'operazione di flusso di controllo creata con l'interfaccia del costruttore generava un errore. Ad esempio, questo era in precedenza un errore, ma ora viene restituito con successo:

    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()
  • Aggiunta una voce mancante dalla libreria di equivalenza delle sessioni standard tra CXGate e CPhaseGate e tra CXGate e CRZGate.

  • È stato risolto un problema a causa del quale l'esecuzione dell'operatore == tra due oggetti SparsePauliOp dava luogo a un errore quando i due operatori avevano un numero diverso di coefficienti. Ad esempio:

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

    In precedenza, questo sollevava un ValueError invece di restituire False.

  • Corretto il supporto in transpile() per passare un oggetto InstructionScheduleMap all'oggetto sottostante PassManager basato sul metodo Target per BackendV2 basati su backend. In precedenza, la funzione transpile() non effettuava questa elaborazione e tutti i passaggi del transpiler che non supportano ancora il lavoro con un oggetto Target non avrebbero avuto accesso alle calibrazioni degli impulsi predefinite per le istruzioni di un backend BackendV2 backend.

  • L'opzione AmplitudeAmplifier è ora correttamente disponibile dal modulo root qiskit.algorithms direttamente dal modulo root. In precedenza non era incluso nelle classi riesportate dal modulo principale ed era accessibile solo da qiskit.algorithms.amplitude_amplifiers. Corretto #7751.

  • Corretto un problema con il backend di mpl per la funzione cassetto dei circuiti circuit_drawer() e il metodo QuantumCircuit.draw() per cui le porte con condizioni non venivano visualizzate correttamente quando un numero sufficiente di porte provocava il ripiegamento del cassetto su una seconda fila. Corretto: #7752.

  • È stato risolto un problema per cui il metodo HHL.construct_circuit() , in determinate condizioni, non restituiva un risultato corretto QuantumCircuit. In precedenza, la funzione presentava un errore di arrotondamento nel calcolo del numero di qubit necessari per rappresentare gli autovalori, che causava un'uscita errata del circuito.

  • Corretto un bug di endianness in BaseReadoutMitigator.expectation_value() quando veniva passata una stringa diagonal . Ora sarà correttamente interpretato come little endian, come il resto di Qiskit Terra, invece che come big endian.

  • Risolto un problema con il quantum_info.partial_trace() quando alla funzione è stato chiesto di non tracciare alcun sottosistema, ora restituirà correttamente DensityMatrix dello stato di input con tutte le dimensioni rimanenti anziché generare un errore. Corretto #7613

  • Corretto un problema con il backend di text per la funzione cassetto dei circuiti circuit_drawer() e il metodo QuantumCircuit.draw() quando le porte che utilizzano il testo laterale, come i metodi CPhaseGate e RZZGate con condizioni classiche impostate, non venivano visualizzati correttamente. Corretto #7532.

  • Corretto un problema con la funzione circuit_drawer() e il metodo draw() di QuantumCircuit. Quando si utilizza l'opzione reverse_bits con le opzioni mpl, latex o text , i bit senza registri non venivano visualizzati nell'ordine corretto. Corretto #7303.

  • È stato risolto un problema nel metodo LocalReadoutMitigator.assignment_matrix() che in precedenza rifiutava un valore di input per l'argomento qubits che non fosse una sequenza banale di qubit nella forma: [0, 1, 2, ..., n-1]. Il problema è stato corretto in modo che ora il metodo accetti qualsiasi elenco di indici di qubit da misurare.

  • È stato risolto un problema nel calcolo del valore di aspettativa del metodo StabilizerState.expectation_value() nel calcolo del valore di aspettativa del metodo, per cui il valore di aspettativa in uscita non era corretto se l'operatore di ingresso per l'argomento aveva una fase non banale Pauli per l'argomento oper aveva una fase non banale. Corretto #7441.

  • Un'espressione opflow contenente l'identità di Pauli opflow.I non produce più un'espressione IGate quando viene convertita in un circuito. Questo cambiamento risolve una differenza di aspettative; la porta di identità nel circuito indica un ritardo, ma in opflow ci aspettiamo un'identità matematica, cioè nessuna operazione.

  • Il PauliGate non inserisce più un elemento IGate per Paulis con l'etichetta "I".

  • PauliSumOp i test di uguaglianza gestiscono ora il caso in cui uno degli elementi confrontati è un singolo elemento PauliOp. Ad esempio, 0 * X + I == I ora viene valutato come Vero, mentre prima di questa versione era Falso.

  • Corretto un problema con gli elementi ALAPSchedule e ASAPSchedule quando si lavorava con istruzioni in cui erano state impostate calibrazioni di impulsi personalizzate (ad esempio, cancelli di impulsi). In precedenza, i passaggi di programmazione non utilizzavano la durata della calibrazione personalizzata degli impulsi per queste istruzioni, con il risultato di generare una programmazione errata per il circuito. Questo problema è stato risolto in modo che ora i passaggi di programmazione utilizzino la durata della calibrazione dell'impulso personalizzato per qualsiasi istruzione del circuito che abbia una calibrazione personalizzata.

  • Corretto il supporto per l'utilizzo dei parametri delle istruzioni ParameterExpression nei parametri dell'istruzione nel passaggio RZXCalibrationBuilder nel passaggio del transpiler. In precedenza, se un parametro di istruzione includeva un bound ParameterExpression il passaggio non era in grado di gestirlo correttamente.

  • Ha interrotto il parser in QuantumCircuit.from_qasm_str() e from_qasm_file() di accettare programmi OpenQASM che si identificano come provenienti da una versione di linguaggio diversa da 2.0. Questo parser è solo per OpenQASM 2.0; il supporto per i circuiti importati da OpenQASM 3.0 sarà aggiunto in una prossima versione.

  • L'esportatore OpenQASM 3, qasm3.Exporterevita i nomi dei registri e dei parametri che si scontrano con le parole chiave riservate di OpenQASM 3, generando un nuovo nome univoco. I registri e i parametri con lo stesso nome non avranno più conflitti di denominazione nell'output di codice dell'esportatore OpenQASM 3. Corretto #7742.

Aer 0.10.3

Nessuna modifica

Ignis 0.7.0

Nessuna modifica

IBM Q Fornitore 0.18.3

Nessuna modifica

Questa pagina è stata utile?
Segnala un bug, un errore di battitura o richiedi contenuti su GitHub.