Esegui il tuo primo circuito sull'hardware
Il codice presente in questa pagina è stato sviluppato utilizzando i seguenti requisiti. Si consiglia di utilizzare queste versioni o versioni più recenti.
qiskit[all]~=2.5.1 qiskit-ibm-runtime~=0.47.0
Questo esempio è composto da due parti. Per prima cosa creerai un semplice programma quantistico "Hello world" e lo eseguirai su un'unità di elaborazione quantistica (QPU). Poiché la ricerca quantistica effettiva richiede programmi molto più robusti, nella seconda sezione ( Scalabilità a un numero elevato di qubit ) si procederà a scalare il programma semplice fino al livello di utilità.
Installa e autentica
-
Se non hai ancora installato Qiskit, consulta le istruzioni nella guida Quickstart.
-
Installa il client Compute di IBM Quantum per eseguire i lavori sull'hardware quantistico:
pip install qiskit-ibm-runtime -
Configurare un ambiente per eseguire i notebook Jupyter in locale:
pip install jupyter
-
-
Configura la tua autenticazione per accedere all'hardware quantistico tramite il piano Open gratuito.
(Se hai ricevuto un invito via e-mail per partecipare a un account, segui invece la procedura per gli utenti invitati.)
-
Vai su IBM Quantum Platform per accedere o creare un account.
ImportanteSe ti connetti tramite un server proxy, devi utilizzare v0.44.0
qiskit-ibm-runtimeo una versione successiva. -
Genera la tua chiave API (chiamata anche token API) sulla dashboard, quindi copiala in un luogo sicuro.
-
Vai alla pagina Istanze e trova l'istanza che desideri utilizzare. Passa con il mouse sul suo CRN e clicca per copiarlo.
-
Salva le tue credenziali localmente con questo codice:
from qiskit_ibm_runtime import QiskitRuntimeService QiskitRuntimeService.save_account( # For `token`, use the 44-character API_KEY you created # and saved from the IBM Quantum Platform Home dashboard token="<your-api-key>", instance="<CRN>", # Optional )
-
-
Ora puoi utilizzare questo codice Python ogni volta che desideri effettuare l'autenticazione al servizio IBM Quantum Compute:
from qiskit_ibm_runtime import QiskitRuntimeService # Run every time you need the service service = QiskitRuntimeService()
Se stai utilizzando un computer pubblico o un altro ambiente non protetto, segui invece le istruzioni per l'autenticazione manuale per mantenere al sicuro le tue credenziali di autenticazione.
Creare ed eseguire un semplice programma quantistico
I quattro passaggi per scrivere un programma quantistico utilizzando i modelli Qiskit sono:
-
Mappare il problema in un formato nativo quantistico.
-
Ottimizzare i circuiti e gli operatori.
-
Eseguire utilizzando una funzione primitiva quantistica.
-
Analizza i risultati.
Passo 1. Mappare il problema in un formato nativo quantistico
In un programma quantistico, i circuiti quantistici sono il formato nativo in cui rappresentare le istruzioni quantistiche, mentre gli operatori rappresentano gli osservabili da misurare. Quando si crea un circuito, di solito si crea un nuovo QuantumCircuit oggetto, quindi si aggiungono le istruzioni in sequenza.
La seguente cella di codice crea un circuito che produce uno stato di Bell, ovvero uno stato in cui due qubit sono completamente intrecciati tra loro.
Il Qiskit SDK utilizza la numerazione LSb 0 bit in cui la cifra ha valore o . Per ulteriori dettagli, consultare l' argomento Ordinamento dei bit in Qiskit SDK.
from qiskit import QuantumCircuit
from qiskit.quantum_info import SparsePauliOp
from qiskit.transpiler import generate_preset_pass_manager
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime import EstimatorOptions
from qiskit_ibm_runtime import EstimatorV2 as Estimator
from matplotlib import pyplot as plt
# Uncomment the next line if you want to use a simulator:
# from qiskit_ibm_runtime.fake_provider import FakeBelemV2
# Create a new circuit with two qubits
qc = QuantumCircuit(2)
# Add a Hadamard gate to qubit 0
qc.h(0)
# Perform a controlled-X gate on qubit 1, controlled by qubit 0
qc.cx(0, 1)
# Return a drawing of the circuit using MatPlotLib ("mpl").
# These guides are written by using Jupyter notebooks, which
# display the output of the last line of each cell.
# If you're running this in a script, use `print(qc.draw())` to
# print a text drawing.
qc.draw("mpl")Output:
Vedi QuantumCircuit nella documentazione tutte le operazioni disponibili.
Quando si creano circuiti quantistici, è necessario considerare anche quale tipo di dati si desidera ottenere al termine dell'esecuzione. Qiskit offre due modi per ottenere i dati: è possibile ottenere un output campionario per un insieme di qubit che si sceglie di misurare, oppure è possibile ottenere il valore atteso di un osservabile. Prepara il tuo carico di lavoro per misurare il circuito in uno di questi due modi utilizzando le primitive (spiegate in dettaglio nel Passo 3 ).
Questo esempio misura i valori attesi utilizzando il qiskit.quantum_info sottomodulo, specificato tramite operatori (oggetti matematici utilizzati per rappresentare un'azione o un processo che modifica uno stato quantistico). La seguente cella di codice crea sei operatori di Pauli a due qubit: IZ, IX, ZI, XI ZZ, e XX.
# Set up six different observables.
observables_labels = ["IZ", "IX", "ZI", "XI", "ZZ", "XX"]
observables = [SparsePauliOp(label) for label in observables_labels]Qui, qualcosa come ZZ l'operatore è una scorciatoia per il prodotto tensoriale, che significa misurare Z sul qubit 1 e Z sul qubit 0 insieme, e ottenere informazioni sulla correlazione tra il qubit 1 e il qubit 0. Valori attesi come questo sono solitamente scritti anche come .
Se lo stato è intrecciato, allora la misurazione di dovrebbe essere diversa dalla misurazione di . Per lo stato intrecciato specifico creato dal nostro circuito descritto sopra, la misurazione di dovrebbe essere 1 e la misurazione di dovrebbe essere zero.
Passo 2. Ottimizzare i circuiti e gli operatori
Quando si eseguono circuiti su un dispositivo, è importante ottimizzare l'insieme di istruzioni contenute nel circuito e ridurre al minimo la profondità complessiva (approssimativamente il numero di istruzioni) del circuito. Ciò garantisce i migliori risultati possibili riducendo gli effetti di errori e rumori. Inoltre, le istruzioni del circuito devono essere conformi all'architettura del set di istruzioni (ISA) del dispositivo backend e devono tenere conto dei gate di base e della connettività dei qubit del dispositivo.
Il codice seguente istanzia un dispositivo reale a cui inviare un lavoro e trasforma il circuito e gli osservabili in modo che corrispondano all'ISA di quel backend. È necessario che tu abbia già salvato le tue credenziali.
service = QiskitRuntimeService()
backend = service.least_busy(simulator=False, operational=True)
# Convert to an ISA circuit and layout-mapped observables.
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_circuit = pm.run(qc)
isa_circuit.draw("mpl", idle_wires=False)Output:
Passaggio 3. Eseguire utilizzando le primitive quantistiche
I computer quantistici possono produrre risultati casuali, quindi solitamente si raccoglie un campione dei risultati eseguendo il circuito più volte. È possibile stimare il valore dell'osservabile utilizzando la Estimator classe. Estimator è una delle due primitive; l'altra è Sampler, che può essere utilizzata per ottenere dati da un computer quantistico. Questi oggetti dispongono di un run() metodo che esegue la selezione di circuiti, grandezze osservabili e parametri (se applicabile), utilizzando un blocco unificato primitivo ( PUB ).
# Construct the Estimator instance.
estimator = Estimator(mode=backend)
estimator.options.resilience_level = 1
estimator.options.default_shots = 5000
mapped_observables = [
observable.apply_layout(isa_circuit.layout) for observable in observables
]
# One pub, with one circuit to run against five different observables.
job = estimator.run([(isa_circuit, mapped_observables)])
# Use the job ID to retrieve your job data later
print(f">>> Job ID: {job.job_id()}")Output:
>>> Job ID: d9mqa588csec73fagtu0
Dopo aver inviato un lavoro, puoi attendere che venga completato nell'istanza Python corrente oppure utilizzare job_id per recuperare i dati in un secondo momento. (Per ulteriori dettagli, consultare la sezione relativa al recupero dei lavori )
Al termine dell'operazione, esaminare il risultato tramite l'attributo result() dell'operazione.
# This is the result of the entire submission. You submitted one Pub,
# so this contains one inner result (and some metadata of its own).
job_result = job.result()
# This is the result from our single pub, which had six observables,
# so contains information on all six.
pub_result = job.result()[0]Quando si esegue un programma quantistico su un dispositivo reale, il carico di lavoro deve attendere in coda prima di essere eseguito. Per risparmiare tempo, puoi invece utilizzare il codice seguente per eseguire questo piccolo carico di lavoro in modalità di fake_provider test locale qiskit-ibm-runtime . Si noti che ciò è possibile solo per un circuito di piccole dimensioni. Quando passerai alla sezione successiva, dovrai utilizzare un dispositivo reale.
# Use the following code instead if you want to run on a simulator:
from qiskit_ibm_runtime.fake_provider import FakeBelemV2
backend = FakeBelemV2()
estimator = Estimator(backend)
# Convert to an ISA circuit and layout-mapped observables.
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_circuit = pm.run(qc)
mapped_observables = [
observable.apply_layout(isa_circuit.layout) for observable in observables
]
job = estimator.run([(isa_circuit, mapped_observables)])
result = job.result()
# This is the result of the entire submission. You submitted one Pub,
# so this contains one inner result (and some metadata of its own).
job_result = job.result()
# This is the result from our single pub, which had five observables,
# so contains information on all five.
pub_result = job.result()[0]Passaggio 4. Analizza i risultati
La fase di analisi è in genere quella in cui è possibile elaborare i risultati utilizzando, ad esempio, la mitigazione dell'errore di misurazione o l'estrapolazione del rumore zero (ZNE). È possibile inserire questi risultati in un altro flusso di lavoro per ulteriori analisi o preparare un grafico dei valori e dei dati chiave. In generale, questo passaggio è specifico per il tuo problema. Per questo esempio, traccia ciascuno dei valori attesi misurati per il nostro circuito.
I valori attesi e le deviazioni standard relativi alle grandezze osservabili specificate in Estimator sono accessibili tramite gli attributi e PubResult.data.stds del PubResult.data.evs risultato del processo. Per ottenere i risultati da Sampler, utilizzare la PubResult.data.meas.get_counts() funzione, che restituirà un dict di misurazioni sotto forma di stringhe di bit come chiavi e conteggi come valori corrispondenti. Per ulteriori informazioni, consulta la guida introduttiva a Sampler.
# Plot the result
values = pub_result.data.evs
errors = pub_result.data.stds
# plotting graph
plt.plot(observables_labels, values, "-o")
plt.xlabel("Observables")
plt.ylabel("Values")
plt.show()Output:
Si noti che per i qubit 0 e 1, i valori attesi indipendenti sia di X che di Z sono 0, mentre le correlazioni (XX e ZZ) sono 1. Questo è un tratto distintivo dell'entanglement quantistico.
Scalabilità a un numero elevato di qubit
Nel campo dell'informatica quantistica, il lavoro su scala industriale è fondamentale per compiere progressi in questo settore. Questo tipo di lavoro richiede calcoli su scala molto più ampia, con circuiti che possono utilizzare oltre 100 qubit e oltre 1000 gate. Questo esempio mostra come è possibile eseguire operazioni su scala industriale su IBM® QPU creando e analizzando uno stato GHZ a 100 qubit. Utilizza il flusso di lavoro dei modelli Qiskit e termina misurando il valore atteso per ciascun qubit.
Passo 1. Mappare il problema
Scrivi una funzione che restituisca un QuantumCircuit che prepara uno stato GHZ a -qubit (essenzialmente uno stato di Bell esteso), quindi utilizza tale funzione per preparare uno stato GHZ a 100-qubit e raccogliere gli osservabili da misurare.
def get_qc_for_n_qubit_GHZ_state(n: int) -> QuantumCircuit:
"""This function will create a qiskit.QuantumCircuit (qc)
for an n-qubit GHZ state.
Args:
n (int): Number of qubits in the n-qubit GHZ state
Returns:
QuantumCircuit: Quantum circuit that generate the n-qubit GHZ state,
assuming all qubits start in the 0 state
"""
if isinstance(n, int) and n >= 2:
qc = QuantumCircuit(n)
qc.h(0)
for i in range(n - 1):
qc.cx(i, i + 1)
else:
raise Exception("n is not a valid input")
return qc
# Create a new circuit with 100 qubits in the GHZ state
n = 100
qc = get_qc_for_n_qubit_GHZ_state(n)Successivamente, mappare gli operatori di interesse. Questo esempio utilizza gli ZZ operatori tra i qubit per esaminare il comportamento man mano che si allontanano. Valori di aspettativa sempre più imprecisi (corrotti) tra qubit distanti rivelerebbero il livello di rumore presente.
# ZZII...II, ZIZI...II, ... , ZIII...IZ
operator_strings = [
"Z" + "I" * i + "Z" + "I" * (n - 2 - i) for i in range(n - 1)
]
operators = [SparsePauliOp(operator) for operator in operator_strings]Passo 2. Ottimizzare il problema per l'esecuzione su hardware quantistico
Il codice seguente trasforma il circuito e gli osservabili per adattarli all'ISA del backend. È necessario che tu abbia già salvato le tue credenziali.
service = QiskitRuntimeService()
backend = service.least_busy(
simulator=False, operational=True, min_num_qubits=100
)
pm = generate_preset_pass_manager(optimization_level=1, backend=backend)
isa_circuit = pm.run(qc)
isa_operators_list = [op.apply_layout(isa_circuit.layout) for op in operators]Passaggio 3. Eseguire su hardware
Invia il lavoro e attiva la soppressione degli errori utilizzando una tecnica volta a ridurre gli errori denominata “disaccoppiamento dinamico ”. Il livello di resilienza indica il grado di resilienza da implementare per far fronte agli errori. Livelli più elevati producono risultati più accurati, a scapito di tempi di elaborazione più lunghi. Per ulteriori spiegazioni sulle opzioni impostate nel codice riportato di seguito, consultare la sezione “Tecniche di mitigazione e soppressione degli errori ”.
options = EstimatorOptions()
options.resilience_level = 1
options.dynamical_decoupling.enable = True
options.dynamical_decoupling.sequence_type = "XY4"
# Create an Estimator object
estimator = Estimator(backend, options=options)# Submit the circuit to Estimator
job = estimator.run([(isa_circuit, isa_operators_list)])
job_id = job.job_id()
print(job_id)Output:
d9mqnjmh4e6s738vioqg
Passaggio 4. Risultati della post-elaborazione
Una volta completato il lavoro, traccia i risultati e nota che diminuisce all'aumentare di , anche se in una simulazione ideale tutti i dovrebbero essere pari a 1.
# data
data = list(range(1, len(operators) + 1)) # Distance between the Z operators
result = job.result()[0]
values = result.data.evs # Expectation value at each Z operator.
values = [
v / values[0] for v in values
] # Normalize the expectation values to evaluate how they decay with distance.
# plotting graph
plt.plot(data, values, marker="o", label="100-qubit GHZ state")
plt.xlabel("Distance between qubits $i$")
plt.ylabel(r"$\langle Z_i Z_0 \rangle / \langle Z_1 Z_0 \rangle $")
plt.legend()
plt.show()Output:
Il grafico precedente mostra che all'aumentare della distanza tra i qubit, il segnale decade a causa della presenza di rumore.
Passi successivi
- Prova uno di questi tutorial:
- Stima dell'energia dello stato fondamentale della catena di Heisenberg con VQE
- Risolvi i problemi di ottimizzazione utilizzando QAOA
- Addestrare modelli di kernel quantistici per attività di apprendimento automatico
- Trova le istruzioni dettagliate per l'installazione nella guida Install Qiskit.
- Se preferisci non installare Qiskit localmente, leggi le opzioni disponibili per utilizzare Qiskit in un ambiente di sviluppo online.
- Per salvare più credenziali di accesso o specificare altre opzioni dell'account, consulta le istruzioni dettagliate nella guida Salva le tue credenziali di accesso.