Hardware
Masao Tokunari e Tamiya Onodera (14 de junho de 2024)
Este curso é baseado em um curso ao vivo ministrado na Universidade de Tóquio.
O pdf da palestra desta lição foi dividido em duas partes. Faça o download da parte 1 e da parte 2. Observe que alguns trechos de código podem se tornar obsoletos, pois são imagens estáticas.
1. Introdução
Esta lição explora o hardware moderno de computação quântica.
Começaremos verificando algumas versões e importando alguns pacotes relevantes.
import statistics
from qiskit_ibm_runtime import QiskitRuntimeService2. Backend e Destino
O Qiskit fornece uma API para obter as informações, tanto estáticas quanto dinâmicas, sobre um dispositivo quântico. Usamos uma instância de backend para fazer a interface com um dispositivo, que inclui uma instância de destino, um modelo de máquina abstrato que resume os recursos pertinentes, como sua arquitetura de conjunto de instruções (ISA) e quaisquer propriedades ou restrições associadas a ela. Vamos usar essas instâncias de back-end para obter algumas das informações que você vê na página Compute resources (Recursos de computação) em IBM Quantum® Platform. Primeiro, criamos uma instância de backend para um dispositivo de interesse. A seguir, escolhemos "ibm_kyoto", "ibm_kawasaki" ou a máquina Eagle menos ocupada. Seu acesso às QPUs pode ser diferente; atualize o nome do backend de acordo.
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.nameOutput:
'ibm_strasbourg'
Começamos com algumas informações básicas (estáticas) sobre o 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 Exercício
Tente obter as informações básicas sobre um dispositivo Heron, "ibm_strasbourg". Tente fazer isso por conta própria, mas o código foi adicionado abaixo para que você mesmo possa verificar.
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 Mapa de acoplamento
Agora, desenhamos o mapa de acoplamento do dispositivo. Como você pode ver, os nós são qubits numerados. As bordas indicam pares aos quais você pode aplicar diretamente a porta de entrelaçamento de 2 qubits. A topologia é chamada de "heavy-hex lattice".
# 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)
figOutput:
3. Propriedades do qubit
O dispositivo Eagle tem 127 qubits. Vamos obter as propriedades de alguns deles.
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)
Vamos calcular a mediana dos tempos de T1 dos qubits. Compare o resultado com o mostrado para o dispositivo na 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 Exercício
Por favor, calcule a mediana dos tempos de T2 dos qubits. Tente fazer isso por conta própria, mas o código foi adicionado abaixo para que você mesmo possa verificar.
# 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 Erros de porta e leitura
Passamos agora aos erros de porta. Para começar, estudamos a estrutura de dados da instância de destino. É um dicionário cujas chaves são nomes de operações.
target = backend.target
target.keys()Output:
dict_keys(['measure', 'id', 'sx', 'delay', 'x', 'for_loop', 'rz', 'if_else', 'ecr', 'reset', 'switch_case'])
Seus valores também são dicionários. Vejamos alguns dos itens do valor (dicionário) da operação '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)
Vamos fazer o mesmo com as operações "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)
Como você pode ver, os erros de leitura tendem a ser maiores do que os da operação de 2 qubits, que, por sua vez, tendem a ser maiores do que os da operação de 1 qubit.
Depois de entender as estruturas de dados, estamos prontos para calcular os erros medianos para as portas "sx" e "ecr". Novamente, compare os resultados com os mostrados para o dispositivo na IBM Quantum Platform.
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. Apêndice
Um recurso popular do Qiskit é sua capacidade de visualização. Ele inclui visualizadores de circuitos, visualizadores de estado e distribuição e visualizador de alvos. Você já usou os dois primeiros nos notebooks anteriores do jupyter. Vamos usar alguns recursos do visualizador de destino.
from qiskit.visualization import plot_gate_map
plot_gate_map(backend, font_size=14)Output:
from qiskit.visualization import plot_error_map
plot_error_map(backend)Output:
# Check Qiskit version
import qiskit
qiskit.__version__Output:
'2.0.2'