Execute seu primeiro circuito no hardware
O código nesta página foi desenvolvido utilizando os seguintes requisitos. Recomendamos usar essas versões ou mais recentes.
qiskit[all]~=2.5.0 qiskit-ibm-runtime~=0.47.0
Este exemplo contém duas partes. Primeiro, você criará um programa quântico simples “Olá, mundo” e o executará em uma unidade de processamento quântico (QPU). Como a pesquisa quântica real requer programas muito mais robustos, na segunda seção ( Escala para um grande número de qubits ), você ampliará o programa simples até o nível de utilidade.
Instalar e autenticar
-
Se você ainda não instalou o Qiskit, consulte as instruções no guia de início rápido.
-
Instale Qiskit Runtime para executar tarefas em hardware quântico:
pip install qiskit-ibm-runtime -
Configure um ambiente para executar notebooks Jupyter localmente:
pip install jupyter
-
-
Configure sua autenticação para acessar o hardware quântico através do Open Plan gratuito.
(Se você recebeu um convite por e-mail para participar de uma conta, siga as etapas para usuários convidados.)
-
Acesse IBM Quantum Platform para fazer login ou criar uma conta.
ImportanteSe você se conectar por meio de um servidor proxy, deverá usar Qiskit Runtime v0.44.0 ou posterior.
-
Gere sua chave API (também chamada de token API ) no painel e copie-a para um local seguro.
-
Acesse a página Instâncias e localize a instância que deseja utilizar. Passe o cursor sobre o CRN e clique para copiá-lo.
-
Salve suas credenciais localmente com este código:
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 )
-
-
Agora você pode usar este Python código sempre que quiser se autenticar no Qiskit Runtime Serviço:
from qiskit_ibm_runtime import QiskitRuntimeService # Run every time you need the service service = QiskitRuntimeService()
Se você estiver usando um computador público ou outro ambiente não seguro, siga as instruções de autenticação manual para manter suas credenciais de autenticação seguras.
Crie e execute um programa quântico simples
As quatro etapas para escrever um programa quântico usando padrões Qiskit são:
-
Mapeie o problema para um formato nativo quântico.
-
Otimize os circuitos e os operadores.
-
Execute usando uma função primitiva quântica.
-
Analise os resultados.
Etapa 1. Mapeie o problema para um formato nativo quântico
Em um programa quântico, os circuitos quânticos são o formato nativo no qual as instruções quânticas são representadas, e os operadores representam os observáveis a serem medidos. Ao criar um circuito, você geralmente cria um novo QuantumCircuit objeto e, em seguida, adiciona instruções a ele em sequência.
A seguinte célula de código cria um circuito que produz um estado Bell, que é um estado em que dois qubits estão totalmente entrelaçados entre si.
O Qiskit SDK usa a numeração de bits LSb 0, em que o dígito tem valor ou . Para obter mais detalhes, consulte a ordem dos bits no Qiskit SDK tópico.
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:
Consulte QuantumCircuit a documentação para ver todas as operações disponíveis.
Ao criar circuitos quânticos, é preciso também levar em conta que tipo de dados você deseja obter após a execução. O Qiskit oferece duas maneiras de retornar dados: você pode obter resultados de amostragem para um conjunto de qubits que decidir medir, ou pode obter o valor esperado de uma observável. Prepare sua carga de trabalho para medir seu circuito de uma dessas duas maneiras usando o Qiskit primitives (explicado em detalhes na Etapa 3 ).
Este exemplo mede valores esperados usando o qiskit.quantum_info submódulo, que é especificado usando operadores (objetos matemáticos usados para representar uma ação ou processo que altera um estado quântico). A seguinte célula de código cria seis operadores Pauli de dois qubits: 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]Aqui, algo como o ZZ operador é uma abreviação do produto tensorial , o que significa medir Z no qubit 1 e Z no qubit 0 juntos e obter informações sobre a correlação entre o qubit 1 e o qubit 0. Valores esperados como este também são normalmente escritos como .
Se o estado estiver entrelaçado, então a medição de deve ser diferente da medição de . Para o estado entrelaçado específico criado pelo nosso circuito descrito acima, a medição de deve ser 1 e a medição de deve ser zero.
Etapa 2. Otimize os circuitos e operadores
Ao executar circuitos em um dispositivo, é importante otimizar o conjunto de instruções que o circuito contém e minimizar a profundidade geral (aproximadamente o número de instruções) do circuito. Isso garante que você obtenha os melhores resultados possíveis, reduzindo os efeitos de erros e ruídos. Além disso, as instruções do circuito devem estar em conformidade com a Arquitetura de Conjunto de Instruções (ISA) do dispositivo backend e devem considerar as portas básicas do dispositivo e a conectividade qubit.
O código a seguir instancia um dispositivo real para enviar um trabalho e transforma o circuito e os observáveis para corresponder à ISA desse backend. É necessário que você já tenha salvo suas credenciais.
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:
Etapa 3. Executar usando os primitivos quânticos
Os computadores quânticos podem produzir resultados aleatórios; por isso, geralmente se coleta uma amostra dos resultados executando o circuito várias vezes. Você pode estimar o valor da observável usando a Estimator classe. Estimator é uma das duas primitivas; a outra é Sampler, que pode ser usada para obter dados de um computador quântico. Esses objetos possuem um run() método que executa a seleção de circuitos, observáveis e parâmetros (se aplicável), utilizando um bloco unificado 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: d9bjj3u6hjac73ffpth0
Depois que um trabalho é enviado, você pode esperar até que ele seja concluído na sua instância atual do Python ou usar o job_id para recuperar os dados posteriormente. (Consulte a seção sobre recuperação de tarefas para obter detalhes.)
Após a conclusão da tarefa, examine sua saída por meio do atributo result() da tarefa.
# 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 você executa seu programa quântico em um dispositivo real, sua carga de trabalho deve aguardar em uma fila antes de ser executada. Para economizar tempo, você pode usar o código a seguir para executar essa pequena carga de trabalho no fake_provider com o modo de Qiskit Runtime teste local. Observe que isso só é possível para um circuito pequeno. Ao ampliar na próxima seção, você precisará usar um dispositivo real.
# 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]Etapa 4. Analise os resultados
A etapa de análise é normalmente onde você pode pós-processar seus resultados usando, por exemplo, mitigação de erros de medição ou extrapolação de ruído zero (ZNE). Você pode inserir esses resultados em outro fluxo de trabalho para análise posterior ou preparar um gráfico dos valores e dados principais. Em geral, esta etapa é específica para o seu problema. Para este exemplo, trace cada um dos valores esperados que foram medidos para o nosso circuito.
Os valores esperados e os desvios-padrão das variáveis observáveis que você especificou ao Estimator podem ser consultados nos atributos e PubResult.data.stds do PubResult.data.evs resultado da tarefa. Para obter os resultados do Sampler, use a PubResult.data.meas.get_counts() função, que retornará um dict conjunto de medições na forma de cadeias de bits como chaves e contagens como seus valores correspondentes. Para obter mais informações, consulte o guia de introdução rápida do 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:
Observe que, para os qubits 0 e 1, os valores esperados independentes de X e Z são 0, enquanto as correlações (XX e ZZ) são 1. Esta é uma característica marcante do entrelaçamento quântico.
Escala para um grande número de qubits
Na computação quântica, o trabalho em escala utilitária é crucial para o progresso nessa área. Esse trabalho requer cálculos em uma escala muito maior, trabalhando com circuitos que podem usar mais de 100 qubits e mais de 1000 portas. Este exemplo demonstra como você pode realizar trabalhos em escala utilitária em IBM® QPUs criando e analisando um estado GHZ de 100 qubits. Ele usa o fluxo de trabalho de padrões Qiskit e termina medindo o valor esperado para cada qubit.
Etapa 1. Mapeie o problema
Escreva uma função que retorne um QuantumCircuit que prepare um estado GHZ de -qubit (essencialmente um estado Bell estendido) e, em seguida, use essa função para preparar um estado GHZ de 100 qubits e coletar os observáveis a serem medidos.
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)Em seguida, mapeie para os operadores de interesse. Este exemplo usa os ZZ operadores entre qubits para examinar o comportamento à medida que eles se distanciam. Valores de expectativa cada vez mais imprecisos (corrompidos) entre qubits distantes revelariam o nível de ruído 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]Etapa 2. Otimize o problema para execução em hardware quântico
O código a seguir transforma o circuito e os observáveis para corresponder à ISA do backend. É necessário que você já tenha salvo suas credenciais.
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]Etapa 3. Executar no hardware
Envie o trabalho e ative a supressão de erros utilizando uma técnica chamada "desacoplamento dinâmico" para reduzir os erros. O nível de resiliência especifica o grau de resiliência a ser implementado contra erros. Níveis mais altos geram resultados mais precisos, mas aumentam o tempo de processamento. Para obter mais informações sobre as opções definidas no código a seguir, consulte Configurar a mitigação de erros para o Qiskit Runtime.
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:
d9bk5brv6alc73ct68ag
Etapa 4. Resultados pós-processamento
Após a conclusão do trabalho, trace os resultados e observe que diminui com o aumento de, mesmo que em uma simulação ideal todos devessem ser 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:
O gráfico anterior mostra que, à medida que a distância entre os qubits aumenta, o sinal enfraquece devido à presença de ruído.
Próximas etapas
- Experimente um destes tutoriais:
- Estimativa da energia do estado fundamental da cadeia de Heisenberg com VQE
- Resolva problemas de otimização usando QAOA
- Treine modelos de kernel quântico para tarefas de aprendizado de máquina
- Encontre instruções detalhadas de instalação no guia Instalar o Qiskit.
- Se você preferir não instalar o Qiskit localmente, leia sobre as opções para usar o Qiskit em um ambiente de desenvolvimento online.
- Para salvar várias credenciais de conta ou especificar outras opções de conta, consulte as instruções detalhadas no guia Salve suas credenciais de login.