Hardware
Masao Tokunari y Tamiya Onodera (14 de junio de 2024)
Este curso está basado en un curso en vivo en la Universidad de Tokio.
El PDF de la clase de esta lección se dividió en dos partes. Descargar parte 1 y Descargar parte 2. Ten en cuenta que algunos fragmentos de código pueden estar desactualizados, ya que son imágenes estáticas.
1. Introducción
Esta lección explora el hardware moderno de computación cuántica.
Comenzamos verificando algunas versiones e importando los paquetes relevantes.
# Added by doQumentation — required packages for this notebook
!pip install -q qiskit qiskit-ibm-runtime
import statistics
from qiskit_ibm_runtime import QiskitRuntimeService
2. Backend y Target
Qiskit ofrece una API para obtener tanto información estática como dinámica sobre un dispositivo cuántico. Utilizamos una instancia de Backend como interfaz con un dispositivo. Esta contiene una instancia de Target – un modelo abstracto de máquina que resume las propiedades esenciales, como la Instruction Set Architecture (ISA) y las propiedades y restricciones asociadas. Utilicemos estas instancias de Backend para obtener parte de la información que ves en la página de Compute resources de la plataforma IBM Quantum®. Primero, creamos una instancia de Backend para un dispositivo de nuestra elección. En el siguiente ejemplo utilizamos "ibm_kyoto", "ibm_kawasaki" o la máquina Eagle menos ocupada. Tu acceso a QPUs puede variar – ajusta el nombre del backend en consecuencia.
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
'ibm_strasbourg'
Comencemos con alguna información básica (estática) sobre el dispositivo.
print(
f"""
{backend.name}, {backend.num_qubits} qubits
processor type = {backend.processor_type}
basis gates = {backend.basis_gates}
"""
)
ibm_strasbourg, 127 qubits
processor type = {'family': 'Eagle', 'revision': 3}
basis gates = ['ecr', 'id', 'rz', 'sx', 'x']
2.1 Ejercicio
Intenta obtener la información básica sobre un dispositivo Heron, "ibm_strasbourg". Pruébalo primero por tu cuenta – más abajo encontrarás un código de solución para comparar.
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}
"""
)
ibm_strasbourg, 133 qubits
processor type = {'family': 'Heron', 'revision': '1'}
basis gates = ['cz', 'id', 'rz', 'sx', 'x']
2.2 Coupling Map
Ahora dibujamos el mapa de acoplamiento del dispositivo. Como puedes ver, los nodos representan qubits numerados. Las aristas indican qué pares pueden conectarse directamente con la puerta de entrelazamiento de 2 qubits. La topología se denomina "red 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

3. Propiedades de los qubits
El dispositivo Eagle tiene 127 qubits. Veamos las propiedades de algunos de ellos.
for qn in range(backend.num_qubits):
if qn >= 5:
break
print(f"{qn}: {backend.qubit_properties(qn)}")
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)
Calculemos la mediana de los tiempos T1 de los qubits. Compara el resultado con lo que se muestra para el dispositivo en la 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"
'Median T1: 285.43 μs'
3.1 Ejercicio
Calcula la mediana de los tiempos T2 de los qubits. Pruébalo primero por tu cuenta – más abajo encontrarás un código de solución para comparar.
# 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"
'Median T2: 173.10 μs'
3.2 Errores de puertas y de lectura
Ahora nos centramos en los errores de puertas. Primero examinamos la estructura de datos de la instancia Target. Es un diccionario cuyas claves son nombres de operaciones.
target = backend.target
target.keys()
dict_keys(['measure', 'id', 'sx', 'delay', 'x', 'for_loop', 'rz', 'if_else', 'ecr', 'reset', 'switch_case'])
Los valores también son diccionarios. Veamos algunas entradas del diccionario de valores para la operación 'sx'.
for i, qq in enumerate(target["sx"]):
if i >= 5:
break
print(i, qq, target["sx"][qq])
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)
Hagamos lo mismo para las operaciones 'ecr' y 'measure'.
for i, edge in enumerate(target["ecr"]):
if i >= 5:
break
print(i, edge, target["ecr"][edge])
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])
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)
Como se puede ver, los errores de lectura suelen ser mayores que los errores de las operaciones de 2 qubits, que a su vez son mayores que los errores de las operaciones de 1 qubit.
Ahora que entendemos las estructuras de datos, podemos calcular los errores medianos para las puertas 'sx' y 'ecr'. Compara nuevamente los resultados con la información del dispositivo en la IBM Quantum Platform.
sx_errors = [inst_prop.error for inst_prop in target["sx"].values()]
f"Median SX error: {(statistics.median(sx_errors)):.3e}"
'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}"
'Median ECR error: 6.895e-03'
4. Apéndice
Una característica especialmente popular de Qiskit es su capacidad de visualización. Incluye visualizadores de circuitos, visualizadores de estados y distribuciones, y un visualizador de Target. Los dos primeros ya los has utilizado en los Jupyter notebooks anteriores. Veamos ahora algunas funciones del visualizador de Target.
from qiskit.visualization import plot_gate_map
plot_gate_map(backend, font_size=14)

from qiskit.visualization import plot_error_map
plot_error_map(backend)

# Check Qiskit version
import qiskit
qiskit.__version__
'2.0.2'