Skip to main content
IBM Quantum Platform

Taglio del circuito per la riduzione della profondità

Stima di utilizzo: Otto minuti con un processore Eagle (NOTA: questa è solo una stima). Il tempo di esecuzione potrebbe variare)


Sfondo

Questa esercitazione mostra come costruire un Qiskit pattern per tagliare le porte di un circuito quantistico per ridurre la profondità del circuito. Per una discussione più approfondita sul taglio dei circuiti, visita la documentazione del componente aggiuntivo Qiskit sul taglio dei circuiti.


Requisiti

Prima di iniziare questa esercitazione, assicuratevi di aver installato quanto segue:

  • Qiskit SDK v2.0 o versioni successive, con supporto alla visualizzazione
  • Qiskit Runtime v0.22 o successivamente (pip install qiskit-ibm-runtime)
  • Taglio dei circuiti Add-on Qiskit v0.9.0 e o successive (pip install qiskit-addon-cutting)

Configura

import numpy as np

from qiskit.circuit.library import EfficientSU2
from qiskit.quantum_info import PauliList, Statevector, SparsePauliOp
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager

from qiskit_addon_cutting import (
    cut_gates,
    generate_cutting_experiments,
    reconstruct_expectation_values,
)

from qiskit_ibm_runtime import QiskitRuntimeService, SamplerV2

Fase 1: mappare gli input classici su un problema quantistico

Implementeremo il nostro modello Qiskit utilizzando i quattro passaggi descritti nella documentazione. In questo caso, simuleremo i valori di aspettativa su un circuito di una certa profondità tagliando le porte che risultano in porte di scambio ed eseguendo sottoesperimenti su circuiti meno profondi. Il taglio dei gate è rilevante per le fasi 2 (ottimizzazione del circuito per l'esecuzione quantistica mediante la scomposizione di gate distanti) e 4 (post-elaborazione per ricostruire i valori di aspettativa sul circuito originale). Nel primo passo, genereremo un circuito dalla libreria di circuiti Qiskit e definiremo alcuni osservabili.

  • Ingresso: Parametri classici per definire un circuito
  • Uscita: Circuito astratto e osservabili
circuit = EfficientSU2(num_qubits=4, entanglement="circular").decompose()
circuit.assign_parameters([0.4] * len(circuit.parameters), inplace=True)
observables = PauliList(["ZZII", "IZZI", "IIZZ", "XIXI", "ZIZZ", "IXIX"])
circuit.draw("mpl", scale=0.8, style="iqp")

Output:

Output of the previous code cell

Fase 2: Ottimizzazione del problema per l'esecuzione su hardware quantistico

  • Ingresso: Circuito astratto e osservabili
  • Output: Circuito target e osservabili prodotti dal taglio di porte distanti per ridurre la profondità del circuito transpilato

Abbiamo scelto un layout iniziale che richiede due scambi per eseguire i gate tra i qubit 3 e 0 e altri due scambi per riportare i qubit alle loro posizioni iniziali. Abbiamo scelto optimization_level=3, che è il massimo livello di ottimizzazione disponibile con un gestore di passaggi preimpostato.

service = QiskitRuntimeService()
backend = service.least_busy(
    operational=True, min_num_qubits=circuit.num_qubits, simulator=False
)

pm = generate_preset_pass_manager(
    optimization_level=3, initial_layout=[0, 1, 2, 3], backend=backend
)
transpiled_qc = pm.run(circuit)
Mappa di accoppiamento che mostra i qubit che dovranno essere scambiati
print(f"Transpiled circuit depth: {transpiled_qc.depth()}")
transpiled_qc.draw("mpl", scale=0.4, idle_wires=False, style="iqp", fold=-1)

Output:

Transpiled circuit depth: 103
Output of the previous code cell

Trova e taglia i gate distanti: sostituiremo i gate distanti (gate che collegano qubit non locali, 0 e 3) con TwoQubitQPDGate oggetti specificandone gli indici. cut_gates sostituirà i gate negli indici specificati con TwoQubitQPDGate oggetti e restituirà anche un elenco di QPDBasis istanze, una per ogni decomposizione del gate. L'oggetto QPDBasis contiene informazioni su come scomporre i gate tagliati in operazioni a singolo qubit.

# Find the indices of the distant gates
cut_indices = [
    i
    for i, instruction in enumerate(circuit.data)
    if {circuit.find_bit(q)[0] for q in instruction.qubits} == {0, 3}
]

# Decompose distant CNOTs into TwoQubitQPDGate instances
qpd_circuit, bases = cut_gates(circuit, cut_indices)

qpd_circuit.draw("mpl", scale=0.8)

Output:

Output of the previous code cell

Generare i sottoesperimenti da eseguire sul backend : generate_cutting_experiments accetta un circuito contenente istanze e osservabili di TwoQubitQPDGate come PauliList.

Per simulare il valore di aspettativa del circuito completo, vengono generati molti sottoesperimenti dalla distribuzione congiunta di quasiprobabilità delle porte scomposte e poi eseguiti su uno o più backend. Il numero di campioni prelevati dalla distribuzione è controllato da num_samples, e per ogni campione unico viene fornito un coefficiente combinato. Per maggiori informazioni sulle modalità di calcolo dei coefficienti, consultare il materiale esplicativo.

# Generate the subexperiments and sampling coefficients
subexperiments, coefficients = generate_cutting_experiments(
    circuits=qpd_circuit, observables=observables, num_samples=np.inf
)

A titolo di confronto, vediamo che i sottoesempi QPD saranno meno profondi dopo il taglio di porte distanti : Ecco un esempio di un sottoesperimento scelto arbitrariamente e generato dal circuito QPD. La sua profondità è stata ridotta di oltre la metà. Molti di questi sottoesperimenti probabilistici devono essere generati e valutati per ricostruire un valore di aspettativa del circuito più profondo.

# Transpile the decomposed circuit to the same layout
transpiled_qpd_circuit = pm.run(subexperiments[100])

print(f"Original circuit depth after transpile: {transpiled_qc.depth()}")
print(
    f"QPD subexperiment depth after transpile: {transpiled_qpd_circuit.depth()}"
)
transpiled_qpd_circuit.draw(
    "mpl", scale=0.6, style="iqp", idle_wires=False, fold=-1
)

Output:

Original circuit depth after transpile: 103
QPD subexperiment depth after transpile: 46
Output of the previous code cell

D'altra parte, il taglio comporta la necessità di un campionamento supplementare. Qui tagliamo tre porte CNOT, con un overhead di campionamento pari a 939^3. Per maggiori informazioni sull'overhead di campionamento generato dal taglio del circuito, consultare la documentazione di Circuit Knitting Toolbox.

print(f"Sampling overhead: {np.prod([basis.overhead for basis in bases])}")

Output:

Sampling overhead: 729.0

Passaggio 3: eseguire utilizzando Qiskit primitives

Eseguire i circuiti di destinazione ("sottoesperimenti") utilizzando la primitiva Sampler.

  • Ingresso: Circuiti target
  • Output: Distribuzioni di quasi-probabilità
# Transpile the subexperiments to the backend's instruction set architecture (ISA)
isa_subexperiments = pm.run(subexperiments)

# Set up the IBM Quantum Sampler primitive.  For a fake backend, this will use a local simulator.
sampler = SamplerV2(backend)

# Submit the subexperiments
job = sampler.run(isa_subexperiments)
# Retrieve the results
results = job.result()
print(job.job_id())

Output:

czypg1r6rr3g008mgp6g

Fase 4: Post-elaborazione e restituzione del risultato nel formato classico desiderato

Utilizzare i risultati del sottoesperimento, le sottoosservabili e i coefficienti di campionamento per ricostruire il valore di aspettativa del circuito originale.

Input: Distribuzioni di quasi-probabilità Output: Valori di aspettativa ricostruiti

reconstructed_expvals = reconstruct_expectation_values(
    results,
    coefficients,
    observables,
)
# Reconstruct final expectation value
final_expval = np.dot(reconstructed_expvals, [1] * len(observables))
print("Final reconstructed expectation value")
print(final_expval)

Output:

Final reconstructed expectation value
1.0751342773437473
ideal_expvals = [
    Statevector(circuit).expectation_value(SparsePauliOp(observable))
    for observable in observables
]
print("Ideal expectation value")
print(np.dot(ideal_expvals, [1] * len(observables)).real)

Output:

Ideal expectation value
1.2283177520039992

Sondaggio tutorial

Vi invitiamo a partecipare a questo breve sondaggio per fornire un feedback su questa esercitazione. Le vostre indicazioni ci aiuteranno a migliorare la nostra offerta di contenuti e l'esperienza degli utenti.

Collegamento al sondaggio

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