Skip to main content
IBM Quantum Platform

Hardware di sistema

Note

Masao Tokunari e Tamiya Onodera (14 giugno 2024)

Questo corso si basa su un corso dal vivo tenuto presso l'Università di Tokyo.

Il pdf di questa lezione è stato diviso in due parti. Scarica la parte 1 e scarica la parte 2. Si noti che alcuni frammenti di codice potrebbero diventare deprecati, poiché si tratta di immagini statiche.


1. Introduzione

Questa lezione esplora il moderno hardware per il calcolo quantistico.

Inizieremo verificando alcune versioni e importando alcuni pacchetti rilevanti.

import statistics

from qiskit_ibm_runtime import QiskitRuntimeService

2. Backend e Target

Qiskit fornisce un'API per ottenere le informazioni, sia statiche che dinamiche, su un dispositivo quantistico. Utilizziamo un'istanza Backend per interfacciarci con un dispositivo, che include un'istanza Target, un modello astratto di macchina che riassume le caratteristiche pertinenti, come l'architettura del set di istruzioni (ISA) ed eventuali proprietà o vincoli associati. Utilizziamo queste istanze di backend per ottenere alcune delle informazioni che si vedono nella pagina delle risorse di calcolo su IBM Quantum® Platform. Innanzitutto, si crea un'istanza di backend per un dispositivo di interesse. Di seguito, sceglieremo "ibm_kyoto", "ibm_kawasaki" o la macchina Eagle meno occupata. Il vostro accesso alle QPU potrebbe essere diverso; aggiornate il nome del backend di conseguenza.

service = QiskitRuntimeService()
# backend = service.backend("ibm_kawasaki") # an Eagle, if you have access to ibm_kawasaki
backend = service.least_busy(
    operational=True, simulator=False, min_num_qubits=127
)  # Eagle
backend.name

Output:

'ibm_strasbourg'

Si inizia con alcune informazioni di base (statiche) sul dispositivo.

print(
    f"""
{backend.name}, {backend.num_qubits} qubits
processor type = {backend.processor_type}
basis gates = {backend.basis_gates}
"""
)

Output:


ibm_strasbourg, 127 qubits
processor type = {'family': 'Eagle', 'revision': 3} 
basis gates = ['ecr', 'id', 'rz', 'sx', 'x']

2.1 Esercizio fisico

Cercare di ottenere le informazioni di base su un dispositivo Heron, "ibm_strasbourg". Provate a farlo da soli, ma il codice è stato aggiunto qui sotto per consentirvi di verificarlo.

a_heron = service.backend("ibm_strasbourg")  # a Heron

# your code here
print(
    f"""
{backend.name}, {a_heron.num_qubits} qubits
processor type = {a_heron.processor_type}
basis gates = {a_heron.basis_gates}
"""
)

Output:


ibm_strasbourg, 133 qubits
processor type = {'family': 'Heron', 'revision': '1'} 
basis gates = ['cz', 'id', 'rz', 'sx', 'x']

2.2 Mappa di accoppiamento

Ora disegniamo la mappa di accoppiamento del dispositivo. Come si può vedere, i nodi sono qubit numerati. I bordi indicano le coppie a cui è possibile applicare direttamente il gate di entangling a 2 qubit. La topologia è chiamata "reticolo heavy-hex".

# This function requires that Graphviz is installed. If you need to install Graphviz
# you can refer to:
# https://graphviz.org/download/#executable-packages for instructions.
try:
    fig = backend.coupling_map.draw()
except RuntimeError as ex:
    print(ex)
fig

Output:

Output of the previous code cell

3. Proprietà dei qubit

Il dispositivo Eagle ha 127 qubit. Ricaviamo le proprietà di alcuni di essi.

for qn in range(backend.num_qubits):
    if qn >= 5:
        break
    print(f"{qn}: {backend.qubit_properties(qn)}")

Output:

0: QubitProperties(t1=0.000183686508736532, t2=0.00023613944465408068, frequency=4832100227.116953)
1: QubitProperties(t1=0.00048794378526038294, t2=9.007098375327869e-05, frequency=4736264354.075363)
2: QubitProperties(t1=0.00021247781834456527, t2=7.81037910324034e-05, frequency=4859349851.150393)
3: QubitProperties(t1=0.0002936462084765663, t2=0.00011400214529510604, frequency=4679749549.503852)
4: QubitProperties(t1=0.00044229440258559125, t2=0.0003181648356339447, frequency=4845872064.050596)

Calcoliamo la mediana dei tempi di T1 dei qubit. Confrontate il risultato con quello mostrato per il dispositivo su IBM Quantum Platform.

t1s = [backend.qubit_properties(qq).t1 for qq in range(backend.num_qubits)]
f"Median T1: {(statistics.median(t1s)*10**6):.2f} \u03bcs"

Output:

'Median T1: 285.43 μs'

3.1 Esercizio fisico

Calcolate la mediana dei tempi di T2 dei qubit. Provate a farlo da soli, ma il codice è stato aggiunto qui sotto per consentirvi di verificarlo.

# Your code here

t2s = [backend.qubit_properties(qq).t2 for qq in range(backend.num_qubits)]
f"Median T2: {(statistics.median(t2s)*10**6):.2f} \u03bcs"

Output:

'Median T2: 173.10 μs'

3.2 Errori di gate e di lettura

Passiamo ora agli errori del cancello. Per cominciare, studiamo la struttura dei dati dell'istanza di destinazione. È un dizionario le cui chiavi sono i nomi delle operazioni.

target = backend.target
target.keys()

Output:

dict_keys(['measure', 'id', 'sx', 'delay', 'x', 'for_loop', 'rz', 'if_else', 'ecr', 'reset', 'switch_case'])

Anche i suoi valori sono dizionari. Vediamo alcuni elementi del valore (dizionario) per l'operazione 'sx'.

for i, qq in enumerate(target["sx"]):
    if i >= 5:
        break
    print(i, qq, target["sx"][qq])

Output:

0 (0,) InstructionProperties(duration=6e-08, error=0.0007401311759115297)
1 (1,) InstructionProperties(duration=6e-08, error=0.0003163759907528654)
2 (2,) InstructionProperties(duration=6e-08, error=0.0003183859004638003)
3 (3,) InstructionProperties(duration=6e-08, error=0.00042235914178831863)
4 (4,) InstructionProperties(duration=6e-08, error=0.011163151923589715)

Facciamo lo stesso per le operazioni "ecr" e "measure".

for i, edge in enumerate(target["ecr"]):
    if i >= 5:
        break
    print(i, edge, target["ecr"][edge])

Output:

0 (0, 14) InstructionProperties(duration=6.6e-07, error=0.01486295709788732)
1 (1, 0) InstructionProperties(duration=6.6e-07, error=0.015201590794522601)
2 (2, 1) InstructionProperties(duration=6.6e-07, error=0.00697838102630724)
3 (2, 3) InstructionProperties(duration=6.6e-07, error=0.008075067943986797)
4 (3, 4) InstructionProperties(duration=6.6e-07, error=0.0630164507876913)
for i, qq in enumerate(target["measure"]):
    if i >= 5:
        break
    print(i, qq, target["measure"][qq])

Output:

0 (0,) InstructionProperties(duration=1.6e-06, error=0.0078125)
1 (1,) InstructionProperties(duration=1.6e-06, error=0.155029296875)
2 (2,) InstructionProperties(duration=1.6e-06, error=0.057373046875)
3 (3,) InstructionProperties(duration=1.6e-06, error=0.02880859375)
4 (4,) InstructionProperties(duration=1.6e-06, error=0.01318359375)

Come si può notare, gli errori di lettura tendono a essere più grandi di quelli dell'operazione a 2 qubit, che a loro volta tendono a essere più grandi dell'operazione a 1 qubit.

Avendo compreso le strutture dei dati, siamo pronti a calcolare gli errori mediani per le porte 'sx' ed 'ecr'. Anche in questo caso, confrontate i risultati con quelli mostrati per il dispositivo sulla piattaforma IBM Quantum.

sx_errors = [inst_prop.error for inst_prop in target["sx"].values()]
f"Median SX error: {(statistics.median(sx_errors)):.3e}"

Output:

'Median SX error: 2.277e-04'
ecr_errors = [inst_prop.error for inst_prop in target["ecr"].values()]
f"Median ECR error: {(statistics.median(ecr_errors)):.3e}"

Output:

'Median ECR error: 6.895e-03'

4. Appendice

Una caratteristica molto apprezzata di Qiskit è la sua capacità di visualizzazione. Include visualizzatori di circuiti, visualizzatori di stati e distribuzione e visualizzatori di obiettivi. I primi due sono già stati utilizzati nei precedenti quaderni di jupyter. Utilizziamo alcune funzionalità del visualizzatore di destinazione.

from qiskit.visualization import plot_gate_map

plot_gate_map(backend, font_size=14)

Output:

Output of the previous code cell
from qiskit.visualization import plot_error_map

plot_error_map(backend)

Output:

Output of the previous code cell
# Check Qiskit version
import qiskit

qiskit.__version__

Output:

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