Pular para o conteúdo principal

Seu primeiro experimento quântico

Introdução

No vídeo a seguir, Olivia Lanes guia você pelo conteúdo desta lição. Alternativamente, você pode abrir o vídeo do YouTube desta lição em uma janela separada.

A esta altura, você já executou seu primeiro circuito quântico e aprendeu os fundamentos da computação quântica: como os estados quânticos são representados, como as portas atuam sobre esses estados e como características quânticas como superposição e emaranhamento estão envolvidas. Agora é hora de colocar tudo isso em prática e resolver seu primeiro problema em um computador quântico.

Exploraremos o panorama mais amplo de problemas adequados para o contexto quântico em uma lição futura. Por enquanto, vamos nos concentrar em um problema no domínio da simulação da natureza: usar um computador quântico como um substituto mais limpo e controlável para um sistema quântico natural. Na verdade, essa foi a primeira aplicação que Richard Feynman vislumbrou para os computadores quânticos na década de 1980. Como ele disse de forma famosa: "A natureza não é clássica, droga, e se você quiser fazer uma simulação da natureza, é melhor torná-la mecânica quântica..."

Nesta lição, seguiremos esse princípio para simular a interação entre dois spins, que você pode imaginar como pequenos ímãs. Dependendo do sinal de sua interação, eles podem preferir se alinhar e apontar na mesma direção, ou se anti-alinhar e apontar em direções opostas. Vamos nos concentrar no último caso porque frequentemente leva a um comportamento mais interessante — e mais desafiador. Depois de entendermos esse pequeno sistema de dois qubits, mostraremos como as mesmas ideias escalam, permitindo que os computadores quânticos aproveitem seu escalonamento exponencial ao simular grandes sistemas de spins.

Dois ímãs interagindo

Para este problema, vamos usar dois qubits, um para cada spin em nosso modelo. Cada spin pode estar apontando para cima (estado do qubit 0|0\rangle), para baixo (estado do qubit 1|1\rangle), ou em uma superposição dos dois estados.

Se os spins têm uma interação antiferromagnética, significa que eles querem se anti-alinhar: quando um está para cima, o outro quer estar para baixo, e vice-versa.

Agora suponha que também exista um campo magnético apontando da esquerda para a direita em nosso sistema. Como esse campo aponta transversalmente à direção usual cima-baixo dos spins, ele é chamado de campo transversal. Esse campo pode inverter spins, o que faz com que a configuração de menor energia seja uma superposição específica de arranjos de spins para cima e para baixo, em vez de qualquer padrão de spin definido único.

Podemos descrever todos esses efeitos usando um objeto matemático chamado Hamiltoniano. O Hamiltoniano nos diz a energia do sistema para um dado arranjo de spins:

H=JZ1Z0+hx(X1+X0)H = J Z_1 Z_0 + h_x (X_1 + X_0)

onde JJ é um coeficiente que controla a intensidade da interação entre spins e hxh_x é um coeficiente para a intensidade do campo magnético externo. Z1Z0Z_1 Z_0 recompensa ou penaliza os spins dependendo de se estão alinhados ou anti-alinhados, e X0X_0 e X1X_1 representam o efeito de inversão de spin do campo magnético.

Na física, os sistemas tendem a se estabilizar no estado com a menor energia possível, chamado estado fundamental. Encontrar esse estado de menor energia é um problema comum, mas requer técnicas de otimização que estão além do escopo desta lição.

Em vez disso, faremos uma pergunta mais simples: se prepararmos os spins em um estado específico, qual é a energia desse estado?

Para responder a isso, vamos:

  1. Preparar os spins em um estado de nossa escolha
  2. Medir a energia desse estado usando o Hamiltoniano acima

Este é exatamente o tipo de cálculo que aparece dentro de algoritmos quânticos maiores, como algoritmos variacionais, que você pode explorar em cursos posteriores.

Implementação em Qiskit

Antes de começar a escrever código, precisamos de um pouco de contexto. Quando executamos um circuito quântico, sempre terminamos medindo os qubits. Mas há dois tipos diferentes de perguntas que podemos querer fazer sobre o resultado dessa medição: às vezes, apenas queremos saber qual é o estado do qubit. Outras vezes, queremos saber, dado o estado quântico, qual é o valor de uma quantidade física, como a energia?

No Qiskit, esses dois tipos de perguntas são tratados por duas ferramentas diferentes, chamadas primitivas.

Sampler responde ao primeiro tipo de pergunta. Ele executa o circuito muitas vezes e nos diz com que frequência medimos cada resultado possível, como 00, 01, 10 ou 11. O resultado é um histograma que mostra a probabilidade de cada resultado de medição.

Estimator responde ao segundo tipo de pergunta. Em vez de nos dar um histograma, ele combina muitas medições nos bastidores para calcular um único número, como a energia do estado de acordo com um Hamiltoniano que fornecemos.

Para ajudá-lo a entender quando e por que usaríamos cada uma dessas ferramentas, percorreremos dois fluxos de trabalho completos (chamados de "padrões Qiskit") aplicados ao mesmo sistema de dois qubits.

Fluxo de trabalho dos padrões Qiskit

O fluxo de trabalho dos padrões Qiskit é um framework geral que usamos para resolver problemas quânticos com o Qiskit. Ele divide uma tarefa de computação quântica em quatro etapas:

  1. Mapear o problema para um modelo que possa ser representado por circuitos quânticos
  2. Otimizar o circuito para ser executado em um backend específico
  3. Executar o circuito otimizado no backend selecionado
  4. Pós-processar os dados brutos de medição

Experimento 1: Use Sampler para medir o estado

Mapear

Em geral, a etapa de mapeamento é onde descobrimos como representar um problema do mundo real em termos de qubits, operadores e medições. Em muitas aplicações, esta é a parte mais complicada e envolvida do fluxo de trabalho — até mesmo perguntas simples, como "o que cada qubit representa?", nem sempre têm respostas diretas.

Neste experimento, porém, o mapeamento é deliberadamente simples. Cada grau de liberdade físico é mapeado diretamente em um único qubit. Por causa dessa correspondência um-a-um, a etapa de mapeamento se reduz a escolher o estado quântico que queremos preparar e escrever um circuito que prepara e mede esse estado.

Aqui, vamos preparar um estado de Bell emaranhado, semelhante ao que fizemos na primeira lição deste curso:

Ψ=12(1001)\vert\Psi\rangle = \frac{1}{\sqrt{2}}(\vert 10\rangle - \vert 01\rangle)
# Added by doQumentation — required packages for this notebook
!pip install -q qiskit qiskit-ibm-runtime
# Import Qiskit primitives
from qiskit import QuantumCircuit

# Make state
qc = QuantumCircuit(2)
qc.h(0)
qc.cx(0, 1)
qc.x(1)
qc.z(0)

# Measure state
qc.measure_all()

# Draw circuit
qc.draw("mpl")

Output of the previous code cell

Otimizar

Antes de executarmos nosso circuito em um computador quântico (ou em um simulador, se você esgotou seu tempo gratuito em computadores quânticos reais no mês), precisamos prepará-lo para execução. Essa etapa é chamada de otimização. (Nota: esse uso da palavra "otimização" pode ser confuso. Na computação quântica, problemas de otimização referem-se a uma classe específica de problemas. Aqui, estamos usando otimização para descrever uma etapa de preparação obrigatória pela qual todo circuito quântico passa antes de poder ser executado eficientemente no hardware.)

Durante a otimização:

  1. Escolhemos o backend — seja um computador quântico real ou um simulador.
  2. Atribuímos os qubits do nosso circuito a qubits físicos no dispositivo.
  3. Reescrevemos o circuito usando apenas as portas que o computador quântico pode realmente executar.
  4. Opcionalmente, implementamos técnicas de mitigação e supressão de erros para reduzir os efeitos do ruído.

No Qiskit, isso é tratado automaticamente pelo transpiler. Depois de escolher o backend, o transpiler faz todo o trabalho para preparar seu circuito para execução, sem que você precise ajustar manualmente as portas ou as atribuições de qubits. O transpiler também oferece diferentes níveis de otimização, que podem ajudar a reduzir erros se necessário. A otimização é feita em estágios chamados de "passes". Portanto, essa otimização será tratada pelo pass_manager no código abaixo. Para saber mais sobre erros e mitigação de erros, veja o curso Quantum Computing in Practice de Olivia Lanes.

# Load the Qiskit Runtime service
from qiskit_ibm_runtime import QiskitRuntimeService

## Load the Qiskit Runtime service
# QiskitRuntimeService.save_account(
# channel="ibm_quantum_platform",
# token="YOUR_TOKEN_HERE",
# overwrite=True,
# set_as_default=True,
# )
# service = QiskitRuntimeService(channel="ibm_quantum_platform")

# Or load saved credentials
service = QiskitRuntimeService()

# Use the least busy backend, or uncomment the loading of a specific backend like "ibm_brisbane".
backend = service.least_busy(operational=True, simulator=False, min_num_qubits=127)
# backend = service.backend("ibm_brisbane")
print(backend.name)
ibm_fez
# Transpile the circuit and optimize for running on the quantum computer selected
# Step 2: Transpile
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager

target = backend.target
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc)

qc_isa.draw("mpl")

Output of the previous code cell

Executar

Agora estamos prontos para executar! Vamos carregar o Sampler e enviar o trabalho para o backend.

# Load the Runtime primitive and session
from qiskit_ibm_runtime import SamplerV2 as Sampler

sampler = Sampler(mode=backend)

Ou, se estiver usando um simulador, você pode descomentar e executar esta célula em vez disso:

## Load the backend sampler
# from qiskit.primitives import BackendSamplerV2

## Load the Aer simulator and generate a noise model based on the currently-selected backend.
# from qiskit_aer import AerSimulator
# from qiskit_aer.noise import NoiseModel

# noise_model = NoiseModel.from_backend(backend)

## Define a simulator using Aer, and use it in Sampler.
# backend_sim = AerSimulator(noise_model=noise_model)
# sampler_sim = BackendSamplerV2(backend=backend_sim)

## Alternatively, load a fake backend with generic properties and define a simulator.
## backend_gen = GenericBackendV2(num_qubits=18)
## sampler_gen = BackendSamplerV2(backend=backend_gen)
job = sampler.run([qc_isa], shots=100)
# job = sampler_sim.run([qc_isa]) # uncomment if you want to run on a simulator
res = job.result()
counts = res[0].data.meas.get_counts()

Pós-processar

from qiskit.visualization import plot_histogram

print("counts = ", counts)
plot_histogram(counts)
counts =  {'10': 49, '01': 50, '11': 1}

Output of the previous code cell

Vemos que a maioria das contagens está em 01 ou 10, o que significa que quando um qubit foi medido como 0, o outro era 1, e vice-versa. Isso é consistente com o estado de Bell Ψ\vert \Psi^- \rangle que preparamos.

Experimento 2: Use Estimator para medir a energia

Agora que vimos como amostrar um estado quântico, vamos usar o Estimator para calcular a energia do nosso estado de Bell Ψ=12(0110)\vert \Psi^- \rangle = \frac{1}{\sqrt{2}}(\vert 01 \rangle - \vert 10 \rangle).

Mapear

Como lembrete, a energia do sistema é determinada pela interação entre os spins (JJ) e o campo magnético externo (hxh_x), conforme capturado pelo Hamiltoniano:

H=JZ1Z0+hx(X1+X0)H = J Z_1 Z_0 + h_x (X_1 + X_0)

Cada termo no Hamiltoniano nos diz como uma certa combinação de spins contribui para a energia. No Qiskit, podemos representar esses termos como operadores de Pauli, que são apenas rótulos para ações simples em qubits:

  • Z1Z0Z_1 Z_0 atua com um ZZ em ambos os qubits.
  • X0X_0 atua com XX no qubit 0.
  • X1X_1 atua com XX no qubit 1.

Um SparsePauliOp no Qiskit é uma forma de armazenar uma lista desses operadores de Pauli junto com seus coeficientes numéricos. Esses operadores de Pauli são os observáveis que queremos que o computador quântico meça — as quantidades que nos informam sobre o sistema. Usando Estimator, podemos calcular o valor médio de cada observável em nosso estado e combiná-los de acordo com os coeficientes no Hamiltoniano para obter a energia total.

# Import Qiskit primitives
from qiskit.quantum_info import SparsePauliOp

# Parameters
J = 1.0 # antiferromagnetic coupling (J<0)
hx = -0.5 # transverse field strength

# 1. Define the Hamiltonian H = J Z1 Z2 + hx (X1 + X2)
obs = SparsePauliOp.from_list([("ZZ", J), ("XI", hx), ("IX", hx)])

# Make state
qc = QuantumCircuit(2)
qc.h(0)
qc.cx(0, 1)
qc.x(1)
qc.z(0)
<qiskit.circuit.instructionset.InstructionSet at 0x1387ed630>

Note que omitimos a linha qc.measure_all() em nosso código. Isso é porque com Estimator, não precisamos especificar onde medir no circuito. Simplesmente informaremos quais observáveis queremos estimar, e o Qiskit cuida das medições nos bastidores.

Otimizar

A etapa de otimização prossegue como antes, com o acréscimo de garantir que nossos observáveis também estejam escritos de forma que o computador quântico possa entender.

# Transpile the circuit and optimize for running on the quantum computer selected
# Step 2: Transpile
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager

target = backend.target
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc)
obs_isa = obs.apply_layout(layout=qc_isa.layout)

qc_isa.draw("mpl")

Output of the previous code cell

Executar

Na etapa de execução, vamos carregar o Estimator e enviar o circuito mais a lista de observáveis que queremos que ele estime para o computador quântico.

# Load the Runtime primitive and session
from qiskit_ibm_runtime import EstimatorV2 as Estimator

estimator = Estimator(mode=backend)
# Load the backend sampler

# noise_model = NoiseModel.from_backend(backend)

# Use Aer simulator in Estimator
# estimator_sim = BackendEstimatorV2(backend=backend_sim)

# Alternatively, load a fake backend with generic properties and define a simulator.
# backend_gen = GenericBackendV2(num_qubits=18)
# estimator_gen = BackendEstimatorV2(backend=backend_gen)
pubs = [(qc_isa, obs_isa)]
job = estimator.run([[qc_isa, obs_isa]])
res = job.result()

# Uncomment lines below to run the job on the Aer simulator with noise model from real backend
# job = estimator_sim.run([[qc_isa,obs_isa]])
# res=job.result()

Pós-processar

Por fim, na etapa de pós-processamento, simplesmente imprimimos a energia calculada nos bastidores pelo Estimator.

print(res[0].data.evs)
-0.9934112021453058

Esta é a energia do nosso estado!

Conclusão

Nesta lição, aprendemos como preparar um estado quântico simples de dois qubits representando dois spins interagentes. Vimos como usar Sampler para observar a distribuição dos resultados de medição e como usar Estimator para calcular a energia do estado de acordo com o Hamiltoniano. Ao longo do caminho, vimos como o Hamiltoniano codifica as interações entre spins e os efeitos de um campo externo, e como diferentes estados podem ter energias diferentes.

Extensão para muitos spins

Até agora, olhamos apenas para dois spins, o que é simples o suficiente para analisar manualmente. Em sistemas físicos reais, como em um ímã ou outro material complexo, frequentemente há muitos spins interagentes. Quando o número de spins aumenta, o Hamiltoniano torna-se mais complexo e encontrar o estado de menor energia torna-se muito mais difícil. É aqui que os computadores quânticos podem ajudar: ao preparar diferentes estados e estimar suas energias, podemos explorar configurações de baixa energia de forma mais eficiente do que computadores clássicos para sistemas grandes.

Uma extensão natural deste experimento seria aumentar o número de qubits para representar mais spins e ajustar a forma como os spins são preparados para tentar encontrar o estado de menor energia. Essa abordagem é a essência dos métodos variacionais, sobre os quais você pode aprender no curso Variational Quantum Algorithms.

Também existem outras abordagens quânticas para estudar energias do estado fundamental que vão além das técnicas variacionais. Esses métodos não são abordados aqui, mas são introduzidos no curso Quantum Diagonalization Algorithms se você estiver interessado em aprender mais.

Objetivo de aprendizagem

Volte ao início do Experimento 2 e tente novamente com um estado de superposição diferente. Você consegue encontrar um estado com energia ainda menor do que o que usamos?

This translation based on the English version of 7 de mai. de 2026