Explorando a incerteza
Para este módulo do Qiskit in Classrooms, os alunos precisam ter um ambiente Python funcional com os seguintes pacotes instalados:
qiskitv2.1.0 ou mais recenteqiskit-ibm-runtimev0.40.1 ou mais recenteqiskit-aerv0.17.0 ou mais recenteqiskit.visualizationnumpypylatexenc
Para configurar e instalar os pacotes acima, consulte o guia Instalar o Qiskit. Para executar jobs em computadores quânticos reais, os alunos precisarão criar uma conta no IBM Quantum® seguindo os passos do guia Configurar sua conta IBM Cloud.
Este módulo foi testado e utilizou 8 minutos de tempo de QPU. Isso é apenas uma estimativa. O uso real pode variar. Dois cálculos demorados estão marcados como tal nos comentários de cabeçalho e podem ser realizados em simuladores caso os alunos estejam com pouco tempo de QPU. Sem eles, o módulo requer apenas ~30 segundos de tempo de QPU.
# Added by doQumentation — required packages for this notebook
!pip install -q matplotlib numpy qiskit qiskit-aer qiskit-ibm-runtime
# Uncomment and modify this line as needed to install dependencies
#!pip install 'qiskit>=2.1.0' 'qiskit-ibm-runtime>=0.40.1' 'qiskit-aer>=0.17.0' 'numpy' 'pylatexenc'
Assista ao guia do módulo apresentado pela Dra. Katie McCormick abaixo, ou clique aqui para assistir no YouTube.
Introdução
Você provavelmente já ouviu falar do princípio da incerteza, mesmo fora dos seus cursos de física. Uma reformulação coloquial comum da incerteza é "Ao observar algo, você o influencia." Isso é certamente verdade. Mas uma maneira mais física de descrever a incerteza é que existem certas grandezas físicas observáveis que possuem uma incompatibilidade que impede que ambas sejam conhecidas simultaneamente com precisão arbitrária. Muitos alunos encontram pela primeira vez o par de variáveis incompatíveis e , que representam a posição ao longo de um eixo chamado eixo e o momento linear ao longo dessa direção, respectivamente. Para essas variáveis, a restrição sobre a incerteza é escrita como Aqui, é chamado de "incerteza em ", que tem a mesma definição que o desvio padrão em estatística, e pode ser definido como é definido da mesma forma. Aqui, não vamos derivar essa relação de incerteza; vamos apontar que ela é consistente com nossa compreensão das ondas clássicas. Ou seja, uma onda com uma frequência e comprimento de onda verdadeiramente perfeitos se estenderia para sempre como um seno perfeito. Quanticamente, isso corresponderia a conhecer o momento perfeitamente de acordo com a hipótese de de Broglie: . Mas para saber uma partícula ondular está localizada, a onda que a descreve deve tornar-se mais concentrada no espaço, como uma Gaussiana muito estreita, por exemplo. Sabemos que podemos expressar qualquer função contínua, incluindo tais funções de onda concentradas, como uma série de Fourier de funções senoidais com diferentes comprimentos de onda. Mas à medida que a função de onda se torna mais concentrada (e a posição é melhor conhecida), precisaremos de mais termos na série de Fourier, significando uma mistura de mais comprimentos de onda (e, portanto, quanticamente, mais valores de momento).
Dito de forma mais simples: um estado com momento bem definido (um seno perfeito no espaço) tem posição muito incerta. Um estado com posição bem definida (como uma distribuição delta de Dirac) tem momento muito incerto.
Existem outras variáveis que exibem tal incompatibilidade. Por exemplo, a projeção do spin de uma partícula pode ser bem definida ao longo de um eixo, mas então não sabemos nada sobre a projeção em um eixo ortogonal. Por exemplo, o estado (para um qubit ou partícula de spin-1/2) tem uma projeção definida ao longo do eixo (de 1 no contexto de um qubit, e de no contexto de uma partícula de spin-1/2). Mas esse estado pode ser escrito como uma superposição de dois estados, cada um dos quais tem uma projeção bem definida no eixo : ou equivalentemente tem uma projeção bem definida em , assim como . Portanto, se especificarmos a projeção de um estado ao longo do eixo , não sabemos a projeção ao longo do eixo . E se especificarmos a projeção no eixo , não sabemos a projeção ao longo de . Existem pequenas diferenças ao discutir isso no contexto do spin e dos qubits. Mas, de modo geral, os autoestados das matrizes de Pauli têm uma relação interessante que podemos explorar. Ao longo desta aula, verificaremos experimentalmente nossa intuição sobre a incerteza nessas variáveis incompatíveis, e verificaremos que as relações de incerteza se mantêm nos computadores quânticos da IBM®.
Verificação simples da intuição
Neste primeiro experimento e ao longo do módulo, usaremos uma estrutura para computação quântica conhecida como "padrões Qiskit" (Qiskit patterns), que divide os fluxos de trabalho nas seguintes etapas:
- Etapa 1: Mapear entradas clássicas para um problema quântico
- Etapa 2: Otimizar o problema para execução quântica
- Etapa 3: Executar usando os Primitivos do Qiskit Runtime
- Etapa 4: Pós-processamento e análise clássica
Em geral, seguiremos essas etapas, embora nem sempre as rotulemos explicitamente.
Vamos começar carregando alguns pacotes necessários, incluindo os primitivos do Runtime. Também selecionaremos o computador quântico menos ocupado disponível para nós.
Há um código abaixo para salvar suas credenciais no primeiro uso. Certifique-se de excluir essas informações do notebook após salvá-las em seu ambiente, para que suas credenciais não sejam compartilhadas acidentalmente ao compartilhar o notebook. Consulte Configurar sua conta IBM Cloud e Inicializar o serviço em um ambiente não confiável para mais orientações.
from numpy import pi
# Load the Qiskit Runtime service
from qiskit_ibm_runtime import QiskitRuntimeService
# Syntax for first saving your token. Delete these lines after saving your credentials.
# QiskitRuntimeService.save_account(channel='ibm_quantum_platform', instance = '<YOUR_IBM_INSTANCE_CRN>', token='<YOUR-API_KEY>', overwrite=True, set_as_default=True)
# service = QiskitRuntimeService(channel='ibm_quantum_platform')
# Load saved credentials
service = QiskitRuntimeService()
# Load the Runtime primitive and session
from qiskit_ibm_runtime import (
Batch,
SamplerV2 as Sampler,
EstimatorV2 as Estimator,
)
# Use the least busy backend
backend = service.least_busy(min_num_qubits=127)
print(backend.name)
ibm_sherbrooke
Se um aluno esgotar seu tempo disponível de computação quântica durante a aula, as linhas abaixo podem ser descomentadas e usadas para configurar um simulador que imita parcialmente o comportamento de ruído do computador quântico selecionado acima.
# Import an estimator, this time from qiskit (we will import from Runtime for real hardware)
from qiskit_aer.primitives import SamplerV2, EstimatorV2
from qiskit_aer.noise import NoiseModel
# Generate the noise model from the backend properties
noise_model = NoiseModel.from_backend(backend)
noisy_sampler = SamplerV2(options={"backend_options": {"noise_model": noise_model}})
noisy_estimator = EstimatorV2(options={"backend_options": {"noise_model": noise_model}})
Você deve se lembrar de que um autoestado de um operador, Z, não é um autoestado de outro operador X. Vamos observar isso agora, experimentalmente, fazendo medições ao longo dos eixos e . Para a medição ao longo de , simplesmente usamos qc.measure(), pois os computadores quânticos da IBM são estruturados para medir ao longo de . Mas para medir ao longo de , precisamos rotacionar o sistema para efetivamente mover o eixo até a orientação ao longo da qual medimos. Isso é feito com uma porta Hadamard. Um passo semelhante é necessário para medições ao longo de . Os passos necessários são reunidos aqui para conveniência:
- Para medir ao longo de :
qc.measure() - Para medir ao longo de :
qc.h()e depoisqc.measure() - Para medir ao longo de :
qc.sdg(),qc.h(),qc.se depoisqc.measure()
Etapa 1: Mapear entradas clássicas para um problema quântico
Neste caso, a etapa de mapeamento consiste simplesmente em expressar as medições e rotações descritas acima em um circuito quântico:
# Step 1: Map
# Import some general packages
from qiskit import ClassicalRegister, QuantumCircuit, QuantumRegister
# Define registers
qr = QuantumRegister(1, "q")
cr = ClassicalRegister(2, "c")
qc = QuantumCircuit(qr, cr)
# Add a first measurement
qc.measure(qr, cr[0])
qc.barrier()
# Change basis so that measurements made on quantum computer which normally tell us about z, now tell us about x.
qc.h(qr)
# Add a second measurement
qc.measure(qr, cr[1])
qc.draw("mpl")
Etapa 2: Otimizar o problema para execução quântica
Esta etapa pega as operações que queremos realizar e as expressa em termos da funcionalidade de um computador quântico específico. Ela também mapeia nosso problema para o layout do computador quântico.
# 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)
Etapa 3: Executar usando os Primitivos do Qiskit Runtime
Podemos usar o Sampler para coletar estatísticas sobre as medições. Vamos construir o primitivo Sampler para executar em um computador quântico real usando mode = backend. Existem outros modos para outros fluxos de trabalho, e usaremos um deles abaixo. O Sampler será usado chamando seu método run() com uma lista de "pubs" (Primitive Unified Blocs). Cada pub contém até três valores que, juntos, definem uma unidade de trabalho computacional para o estimador completar: circuitos, observáveis, parâmetros. Você também pode fornecer uma lista de circuitos, uma lista de observáveis e uma lista de parâmetros. Para mais informações, leia a Visão geral dos PUBs.
Queremos executar em um computador quântico real, para que estejamos realizando um experimento real de física quântica. Se você esgotar o tempo alocado em computadores quânticos reais, pode comentar o código abaixo para o computador quântico e descomentar o código para execução em um simulador.
# Step 3: Run the job on a real quantum computer
sampler = Sampler(mode=backend)
pubs = [qc_isa]
job = sampler.run(pubs)
res = job.result()
counts = res[0].data.c.get_counts()
# Run the job on the Aer simulator with noise model from real backend
# job = noisy_sampler.run([qc_isa])
# res=job.result()
# counts=res[0].data.c.get_counts()
Etapa 4: Pós-processamento
Este é um caso especialmente simples de pós-processamento, no qual simplesmente visualizamos as contagens.
Observe que o Qiskit ordena qubits, medições e outras coisas listando o item de menor número por último / à direita, uma convenção chamada de "little-endian". Isso significa que a coluna abaixo rotulada como "10" refere-se às contagens em que a primeira medição resultou em "0" e a segunda medição resultou em "1".
# Step 4: Post-process
from qiskit.visualization import plot_histogram
plot_histogram(counts)
Se essa convenção não for conveniente para você, pode usar marginal_counts para visualizar os resultados de cada medição separadamente:
from qiskit.result import marginal_counts
plot_histogram(
marginal_counts(counts, indices=[0]), title="Counts after first measurement"
)
plot_histogram(
marginal_counts(counts, indices=[1]), title="Counts after second measurement"
)
Por padrão, os estados no Qiskit são inicializados no estado . Portanto, não é surpresa que quase todas as primeiras medições tenham resultado em . Observe, no entanto, que houve uma divisão quase igual na segunda medição (aquela que fornece informações sobre as projeções do estado em ). Parece que esse estado, que nos dá um resultado muito previsível de medições ao longo de , nos dá um conjunto muito imprevisível de resultados para medições ao longo de . Vamos explorar isso.
O que acontece se fizermos as medições na ordem inversa? Poderíamos começar usando a porta Hadamard para obter estatísticas sobre a probabilidade de ser medido em . Depois, para a segunda medição, voltaremos à base usando uma segunda porta Hadamard.
# Step 1:
# Define registers
qr = QuantumRegister(1, "q")
cr = ClassicalRegister(2, "c")
qc = QuantumCircuit(qr, cr)
# Change basis to measure along x.
qc.h(qr)
qc.measure(qr, cr[0])
qc.barrier()
# Change our basis back to z and make a second measurement
qc.h(qr)
qc.measure(qr, cr[1])
qc.draw("mpl")
# Step 2: Transpile the circuit for running on a quantum computer
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc)
# Step 3: Run the job on a real quantum computer
sampler = Sampler(mode=backend)
pubs = [qc_isa]
job = sampler.run(pubs)
res = job.result()
counts = res[0].data.c.get_counts()
# Run the job on the Aer simulator with noise model from real backend
# job = noisy_sampler.run([qc_isa])
# res=job.result()
# counts=res[0].data.c.get_counts()
# Step 4: Post-process
from qiskit.visualization import plot_histogram
plot_histogram(counts)
Aqui, parece que temos ainda menos previsibilidade! Anteriormente, pelo menos sabíamos qual seria o resultado da primeira medição; agora temos uma distribuição bastante uniforme por todos os estados possíveis. Não é difícil ver por que isso aconteceu. Começamos no estado , que é uma mistura 50-50 de e , de acordo com Portanto, claramente deve haver igual probabilidade de obter o estado + ou - (mapeados para 0 e 1 no gráfico) para a primeira medição. A medição ao longo de colapsa o estado para um autoestado ou para o autoestado . Cada um desses estados é uma mistura 50-50 de e , de acordo com Portanto, uma vez que o sistema esteja em um autoestado de , claramente as medições ao longo de produzirão tanto quanto , e o farão com probabilidade aproximadamente igual. Assim, nosso primeiro exemplo nos mostrou que alguns estados terão resultados muito previsíveis para algumas medições, mas resultados imprevisíveis para outras. O exemplo atual nos mostra que podemos ter um desempenho pior do que isso. Há estados que podem nos dar resultados imprevisíveis para ambas as medições, mesmo que tudo o que façamos seja trocar a ordem das medições. Vamos investigar o quão certa ou incerta é uma grandeza para um dado estado.
Calculando a incerteza
Podemos quantificar isso usando incerteza, ou variância. A "incerteza" é frequentemente definida como a raiz quadrada da "variância" de uma distribuição. Ou seja, a incerteza de um observável é denotada por e é dada por
Para o caso das matrizes de Pauli, para as quais , isso se torna
Vamos aplicar isso a um exemplo concreto. Vamos começar com o estado e determinar a incerteza do observável nesse estado.
Verifique seu entendimento
Calcule a incerteza de no estado , à mão.
Answer
No estado dado, isso resulta em:
Podemos criar um estado inicial arbitrário usando qc.initialize(). Note que a sintaxe para a unidade imaginária aqui é .
# Step 1: Map the problem into a quantum circuit
from qiskit.quantum_info import SparsePauliOp
import numpy as np
obs = SparsePauliOp("X")
# Define registers
qr = QuantumRegister(1, "q")
cr = ClassicalRegister(1, "c")
qc = QuantumCircuit(qr, cr)
# Initialize the state
qc.initialize([1, 1j] / np.sqrt(2))
# Step 2: Transpile the circuit
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc)
obs_isa = obs.apply_layout(layout=qc_isa.layout)
# Step 3: Run the circuit on a real quantum computer
estimator = Estimator(mode=backend)
pubs = [(qc_isa, obs_isa)]
job = estimator.run([[qc_isa, obs_isa]])
res = job.result()
# Run the job on the Aer simulator with noise model from real backend
# job = noisy_estimator.run([[qc_isa,obs_isa]])
# res=job.result()
# Step 4: Return the result in classical form, and analyze.
print(res[0].data.evs)
-0.02408454165642664
De acordo com nossa equação acima, Vamos manter o mesmo estado, mas agora encontrar o valor esperado de :
# Step 1: Map the problem into a quantum circuit
obs = SparsePauliOp("Z")
# Define registers
qr = QuantumRegister(1, "q")
cr = ClassicalRegister(1, "c")
qc = QuantumCircuit(qr, cr)
# Initialize the state to |+>_y
qc.initialize([1, 1j] / np.sqrt(2))
# Step 2: Transpile the circuit
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc)
obs_isa = obs.apply_layout(layout=qc_isa.layout)
# Step 3: Run the circuit on a real quantum computer
estimator = Estimator(mode=backend)
pubs = [(qc_isa, obs_isa)]
job = estimator.run(pubs)
res = job.result()
# Run the job on the Aer simulator with noise model from real backend
# job = noisy_estimator.run([[qc_isa,obs_isa]])
# res=job.result()
# Step 4: Return the result in classical form, and analyze.
print(res[0].data.evs)
0.04958271968581247
Poderíamos fazer a mesma matemática de antes, mas veríamos que a variância novamente ficaria muito próxima de 1,0. Poderíamos concluir que . De fato, isso é aproximadamente correto para o estado que escolhemos. Mas será que podemos fazer melhor? Ou pior?
Lembre-se de que existe uma relação de incerteza entre a posição ao longo de uma direção, e o momento ao longo da mesma direção, Para essas variáveis, a forma mais familiar é provavelmente Se é tudo o que lembramos, poderíamos ser tentados a pensar que e também poderiam ter tal limite fundamental sobre a incerteza. Talvez seja impossível que o produto chegue a zero? Vamos tentar outro estado e ver se isso se mantém. Desta vez, usaremos Vamos ver o que acontece. Note que no código abaixo, o estimator pode aceitar dois conjuntos de circuitos e observáveis na mesma submissão de job.
# Step 1: Map the problem into a quantum circuit
obs1 = SparsePauliOp("X")
obs2 = SparsePauliOp("Z")
# Define registers
qr = QuantumRegister(1, "q")
cr = ClassicalRegister(1, "c")
qc = QuantumCircuit(qr, cr)
# Initialize the state
qc.initialize([1, 1] / np.sqrt(2))
# Step 2: Transpile the circuit
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc)
obs1_isa = obs1.apply_layout(layout=qc_isa.layout)
obs2_isa = obs2.apply_layout(layout=qc_isa.layout)
# Step 3: Run the circuit on a real quantum computer
with Batch(backend=backend) as batch:
estimator = Estimator(mode=batch)
pubs = [(qc_isa, obs1_isa), (qc_isa, obs2_isa)]
job = estimator.run(pubs)
res = job.result()
batch.close()
# Run the job on the Aer simulator with noise model from real backend
# job = noisy_estimator.run([[qc,obs1],[qc,obs2]])
# res=job.result()
# Step 4: Return the result in classical form, and analyze.
print("The expectation value of the first observable is: ", res[0].data.evs)
print("The expectation value of the second observable is: ", res[1].data.evs)
The expectation value of the first observable is: 1.0011036174126302
The expectation value of the second observable is: 0.0029429797670141016
O valor esperado de deve ser próximo de 1,0, mas não deve exceder 1,0. Não se preocupe se ultrapassar 1,0 por uma quantidade muito pequena. Isso pode ser atribuído a fatores como ruído e/ou erro de leitura. Embora esse seja um tema muito importante, podemos ignorá-lo por ora.
Obtivemos um valor esperado de muito próximo de 1,0 (correspondendo a uma variância muito baixa para ). Isso faz com que o produto das duas variâncias seja bastante pequeno:
Embora esse valor não seja exatamente zero, ele está ficando pequeno em comparação com os autovalores dos operadores de Pauli (). Bem, você pode se lembrar de que a relação de incerteza entre posição linear e momento poderia ser escrita de forma diferente, usando explicitamente a relação de comutação entre os operadores e :
onde
é o comutador de e .
Esta é a forma que pode ser mais facilmente estendida aos operadores de Pauli. De forma geral, para dois operadores e ,
E no caso das matrizes de Pauli e , precisamos de para calcular
Mostramos isso aqui e deixamos cálculos semelhantes para o leitor como exercício:
Esta é uma resposta perfeitamente aceitável, mas com mais um passo, vemos
Nossa relação de incerteza se torna então
Verifique seu entendimento
Determine e . Use isso para escrever as relações de incerteza entre e , e entre e .
Answer
Combinando com a relação de incerteza geral, temos
Verificar consistência
Antes de prosseguir, vamos verificar se isso foi consistente com o que encontramos anteriormente. Usamos o estado E encontramos que Agora sabemos que esse produto deve ser maior ou igual a
Portanto, de fato,
Use as perguntas abaixo para desenvolver intuição sobre esses resultados:
Verifique seu entendimento
Responda aos itens a seguir em conjunto:
(a) Quais estados você esperaria ter incerteza zero em ?
(b) Quais estados você esperaria ter incerteza zero em ?
(c) Em quais estados você obteria um valor esperado zero ?
(d) As respostas às perguntas acima são consistentes com o caso ?
(e) Escreva código para verificar isso explicitamente usando o estimator.
Answer
(a) Poderíamos esperar que os autoestados do operador resultassem em incerteza zero em . De fato, usando temos
(b) Poderíamos esperar que os autoestados do operador resultassem em incerteza zero em . De fato, usando temos
(c) Esperamos encontrar para quaisquer estados que, ao serem medidos, produzam uma projeção positiva no eixo com a mesma frequência que uma projeção negativa. Isso inclui os autoestados de e .
(d) Sim. Esperaríamos um valor muito pequeno para o produto das incertezas para autoestados de ou : Isso pode se manter porque também esperaríamos para esses mesmos estados. Portanto, a relação de incerteza poderia ser satisfeita.
(e) Um código como o seguinte verificaria isso:
obs1 = SparsePauliOp.from_list(
[("X", 1.000)]
)
obs2 = SparsePauliOp.from_list(
[("Y", 1.000)]
)
obs3 = SparsePauliOp.from_list(
[("Z", 1.000)]
)
qc = QuantumCircuit(1,1)
qc.ry(pi/2,0)
job = estimator.run([(qc, [[obs1], [obs2], [obs3]])], precision=0.001)
res=job.result()
Onde o resultado retorna todos os valores esperados. Para recuperar todos os valores esperados e calcular as incertezas, poderíamos usar:
xs=res[0].data.evs[0]
ys=abs(res[0].data.evs[1])
zs=res[0].data.evs[2]
import math
prodxz=((1-xs[i]*xs[i])**0.5)*(1-zs[i]*zs[i])**0.5
Responda aos itens a seguir em conjunto:
(a) Você consegue pensar em um estado no qual teria um valor esperado grande ?
(b) Você esperaria que esse mesmo estado tivesse incerteza grande ou pequena em ?
(c) Você esperaria que esse mesmo estado tivesse incerteza grande ou pequena em ?
(d) As respostas às perguntas acima são consistentes com o caso ?
(e) Escreva código para verificar isso explicitamente usando o estimator.
Answer
(a) Esperamos encontrar para o autoestado de : .
(b) Poderíamos esperar que tivesse grande incerteza no estado já que medir nesse estado produziria um resultado positivo e negativo com igual frequência/probabilidade.
(c) Poderíamos esperar que tivesse grande incerteza no estado já que medir nesse estado produziria um resultado positivo e negativo com igual frequência/probabilidade.
(d) Sim. Esperaríamos um valor grande para o produto das incertezas para autoestados de , e para especificamente. Também esperaríamos para esse mesmo estado. Portanto, tanto quanto são bastante grandes nesse estado, e é plausível que a relação de incerteza possa ser satisfeita novamente.
(e) Um código como o seguinte verificaria isso:
obs1 = SparsePauliOp.from_list(
[("X", 1.000)]
)
obs2 = SparsePauliOp.from_list(
[("Y", 1.000)]
)
obs3 = SparsePauliOp.from_list(
[("Z", 1.000)]
)
qc = QuantumCircuit(1,1)
qc.rx(-pi/2,0)
job = estimator.run([(qc, [[obs1], [obs2], [obs3]])], precision=0.001)
res=job.result()
Onde o resultado retorna todos os valores esperados. Para recuperar todos os valores esperados e calcular as incertezas, poderíamos usar:
xs=res[0].data.evs[0]
ys=abs(res[0].data.evs[1])
zs=res[0].data.evs[2]
import math
prodxz=((1-xs[i]*xs[i])**0.5)*(1-zs[i]*zs[i])**0.5
Testando as relações de incerteza
O teste acima demonstrou apenas a validade da relação de incerteza para uma única escolha de vetor de estado . Para nos convencer de que isso é geralmente consistente com o experimento, devemos realizar cálculos similares usando o estimador para muitas escolhas de vetor de estado. Vamos começar rotacionando nosso vetor de estado para longe do eixo , usando uma porta RY para produzir diferentes estados iniciais com um parâmetro .
# The calculation below uses approximately 3-4 minutes of QPU time.
# Step 1: Map the problem into a quantum circuit
from qiskit.circuit import Parameter
import numpy as np
# Specify observables
obs1 = SparsePauliOp("X")
obs2 = SparsePauliOp("Y")
obs3 = SparsePauliOp("Z")
# Define registers
qr = QuantumRegister(1, "q")
cr = ClassicalRegister(1, "c")
qc = QuantumCircuit(qr, cr)
# Rotate away from |0>
theta = Parameter("θ")
qc.ry(theta, 0)
params = np.linspace(0, 2, num=21)
# Step 2: Transpile the circuit
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc)
obs1_isa = obs1.apply_layout(layout=qc_isa.layout)
obs2_isa = obs2.apply_layout(layout=qc_isa.layout)
obs3_isa = obs3.apply_layout(layout=qc_isa.layout)
# Step 3: Run the circuit on a real quantum computer
with Batch(backend=backend) as batch:
estimator = Estimator(mode=batch)
pubs = [(qc_isa, [[obs1_isa], [obs2_isa], [obs3_isa]], [params])]
job = estimator.run(pubs, precision=0.01)
res = job.result()
batch.close()
# Run the job on the Aer simulator with noise model from real backend
# job = noisy_estimator.run([(qc, [[obs1], [obs2], [obs3]], [params])])
# res=job.result()
# Step 4: Post-processing and classical analysis.
xs = res[0].data.evs[0]
ys = abs(res[0].data.evs[1])
zs = res[0].data.evs[2]
# Calculate uncertainties
delx = []
delz = []
prodxz = []
for i in range(len(xs)):
delx.append(abs((1 - xs[i] * xs[i])) ** 0.5)
delz.append(abs((1 - zs[i] * zs[i])) ** 0.5)
prodxz.append(delx[i] * delz[i])
# Here we can plot the results from this simulation.
import matplotlib.pyplot as plt
plt.plot(params, delx, label=r"$\Delta$ X")
plt.plot(params, ys, label=r"$\langle$ Y $\rangle$")
plt.plot(params, delz, label=r"$\Delta$ Z")
plt.plot(params, prodxz, label=r"$\Delta$X $\Delta$Z")
plt.xlabel(r"$\theta$")
plt.ylabel("Expectation/Uncertainty Values")
plt.legend()
plt.show()
Note que a curva vermelha é sempre maior que a curva laranja Em alguns momentos, o produto das incertezas cai e fica relativamente próximo do limite; em outros, sobe e fica mais distante do limite — mas sempre obedece à relação de incerteza.
É claro que esse pode não ser o melhor teste da relação de incerteza, já que nosso limite fica sempre muito próximo de zero. Vamos usar um estado quântico que tenha uma projeção maior nos autoestados de . Especificamente, ainda vamos rotacionar para longe do eixo por ângulos variados, mas agora também vamos rotacionar o estado resultante em torno de por algum ângulo, talvez , e ver o que acontece.
# The calculation below uses approximately 3-4 minutes of QPU time.
from qiskit.circuit import Parameter
import numpy as np
# Step 1: Map the problem to a quantum circuit
# Specify observables
obs1 = SparsePauliOp("X")
obs2 = SparsePauliOp("Y")
obs3 = SparsePauliOp("Z")
# Define registers
qr = QuantumRegister(1, "q")
cr = ClassicalRegister(1, "c")
qc = QuantumCircuit(qr, cr)
# Rotate away from |0> along one plane, and then along a transverse direction.
theta = Parameter("θ")
qc.ry(theta, 0)
qc.rz(pi / 4, 0)
params = np.linspace(0, 2, num=21)
# Step 2: Transpile the circuit
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc)
obs1_isa = obs1.apply_layout(layout=qc_isa.layout)
obs2_isa = obs2.apply_layout(layout=qc_isa.layout)
obs3_isa = obs3.apply_layout(layout=qc_isa.layout)
# Step 3: Run the circuit on a real quantum computer
with Batch(backend=backend) as batch:
estimator = Estimator(mode=batch)
pubs = [(qc_isa, [[obs1_isa], [obs2_isa], [obs3_isa]], [params])]
job = estimator.run(pubs, precision=0.01)
res = job.result()
batch.close()
# Run the job on the Aer simulator with noise model from real backend
# job = noisy_estimator.run([(qc, [[obs1], [obs2], [obs3]], [params])])
# res=job.result()
# Step 4: Post-processing and classical analysis.
xs = res[0].data.evs[0]
ys = abs(res[0].data.evs[1])
zs = res[0].data.evs[2]
# Calculate uncertainties
delx = []
delz = []
prodxz = []
for i in range(len(xs)):
delx.append(abs((1 - xs[i] * xs[i])) ** 0.5)
delz.append(abs((1 - zs[i] * zs[i])) ** 0.5)
prodxz.append(delx[i] * delz[i])
# Here we can plot the results from this simulation.
import matplotlib.pyplot as plt
plt.plot(params, delx, label=r"$\Delta$ X")
plt.plot(params, ys, label=r"$\langle$ Y $\rangle$")
plt.plot(params, delz, label=r"$\Delta$ Z")
plt.plot(params, prodxz, label=r"$\Delta$X $\Delta$Z")
plt.xlabel(r"$\theta$")
plt.ylabel("Expectation/Uncertainty Values")
plt.legend()
plt.show()
Agora vemos que o limite da incerteza está sendo posto à prova! A curva vermelha se aproxima muito mais da curva laranja do que antes. Na verdade, na ausência de ruído, a relação de incerteza seria exatamente saturada () em um ponto. Na presença de ruído e erro de leitura, não deve surpreender se uma execução ocasionalmente produzir levemente maior que Isso não é uma verdadeira violação da incerteza; é apenas um artefato do erro não nulo.
Verifique sua compreensão
Como você faria para levar isso ao limite absoluto, tornando o maior possível.
Answer
O código atualmente possui linhas que rotacionam o estado inicial padrão para longe do eixo por um ângulo parametrizado e, em seguida, também em torno do eixo por um ângulo o que rotaciona o vetor de estado parte do caminho em direção ao eixo .
qc.ry(theta,0)
qc.rz(pi/4,0)
Poderíamos mudar a rotação em torno de de para , rotacionando completamente até um autoestado de :
qc.ry(theta,0)
qc.rz(pi/2,0)
Nenhuma outra alteração seria necessária.
Altere o código ou copie-o e implemente essa verificação da relação de incerteza com o valor esperado de Y maximizado. A relação de incerteza é válida?
Answer
Usaríamos exatamente o código do exemplo acima, com
qc.rz(pi/2,0)
substituindo
qc.rz(pi/4,0).
O gráfico resultante deve se parecer com o mostrado abaixo e, sim, o princípio da incerteza ainda deve ser válido.

Modifique o código acima para fazer um gráfico similar, demonstrando que, a partir de medições no computador quântico, o produto se comporta como deveria. Escolha qualquer conjunto de estados que preferir.
Answer
Usaríamos exatamente o código do exemplo acima e, de fato, poderíamos usar os mesmos resultados de antes, apenas usando os valores esperados para calcular incertezas diferentes. Por exemplo, poderíamos usar
xs=res[0].data.evs[0]
ys=res[0].data.evs[1]
zs=abs(res[0].data.evs[2])
import math
delx = []
dely = []
prodxy=[]
for i in range(len(xs)):
delx.append((1-xs[i]*xs[i])**0.5)
dely.append((1-ys[i]*ys[i])**0.5)
prodxy.append(((1-xs[i]*xs[i])**0.5)*(1-ys[i]*ys[i])**0.5)
e poderíamos plotar
import matplotlib.pyplot as plt
plt.plot(params, delx, label=r'$\Delta$ X')
plt.plot(params, dely, label=r'$\langle$ Y $\rangle$')
plt.plot(params, zs, label=r'$\Delta$ Z')
plt.plot(params, prodxy, label=r'$\Delta$X $\Delta$Z')
plt.xlabel(r'$\theta$')
plt.ylabel('Expectation/Uncertainty Values')
plt.legend()
plt.show()
Desafio: Escreva um código para varrer muitos valores de , assim como varremos muitos valores de , e faça um gráfico 3D mostrando que a relação de incerteza nunca é violada. Escolha quaisquer observáveis que preferir.
Questões
Instrutores podem solicitar versões desses notebooks com gabaritos e orientações sobre como inseri-los em currículos comuns preenchendo esta pesquisa rápida sobre como os notebooks estão sendo utilizados.
Conceitos fundamentais:
- Existem relações de incerteza entre muitos conjuntos de observáveis físicos, incluindo posição e momento linear, e componentes de spin.
- As matrizes de Pauli não comutam. Isso é um reflexo matemático do fato de que nem todos os componentes do spin podem ser simultaneamente conhecidos/determinados.
- A computação quântica faz uso intenso dos operadores/matrizes de Pauli, portanto é útil conhecer a relação de incerteza para os operadores de Pauli, bem como os operadores de spin intimamente relacionados.
- Uma fórmula geral para a incerteza de dois operadores e é
- Um autoestado de algum operador produz incerteza zero no observável físico associado a esse operador. Mesmo experimentalmente,
- Um autoestado de algum operador produzirá uma incerteza maior para um operador que não comuta com .
- Resultados experimentais usando um computador quântico real confirmam a intuição que obtemos das representações matriciais dos operadores físicos.
Questões V/F:
- V/F É possível medir e simultaneamente, mas não .
- V/F É possível medir e simultaneamente, mas não .
- V/F Os operadores de posição linear e momento linear não comutam.
- V/F Os computadores quânticos da IBM medem ao longo de por padrão, portanto uma rotação deve ser realizada para medir ao longo de qualquer outra direção.
- V/F O circuito abaixo efetivamente mede e depois .
Questões de múltipla escolha:
-
O diagrama abaixo demonstra qual das seguintes relações de incerteza?
- a.
- b.
- c.
- d. Nenhuma das anteriores

-
Qual das alternativas a seguir representa a sequência padrão para realizar uma medição ao longo de ?
- a. Apenas
qc.measure() - b.
qc.h()e depoisqc.measure() - c.
qc.h(),qc.h()e depoisqc.measure() - d.
qc.h(),qc.s,qc.h()e depoisqc.measure() - e.
qc.sdg(),qc.h(),qc.se depoisqc.measure() - f.
qc.sdg(),qc.h(),qc.s,qc.h()e depoisqc.measure()
- a. Apenas
-
Qual dos seguintes estados produz o maior valor esperado ?
- a.
- b.
- c. também chamado de
- d. também chamado de
- e. também chamado de
- f. também chamado de
-
Qual dos seguintes estados produz a maior incerteza ?
- a.
- b. também chamado de
- c. também chamado de
- d. a e b estão empatados
- e. b e c estão empatados
- f. a, b e c estão empatados
Questões para discussão:
-
Esse conceito de incerteza entra em conflito de alguma forma com a noção de spin como uma seta vetorial no espaço cartesiano? E na esfera de Bloch?
-
Suponha que você oriente um dispositivo de medição ao longo de uma direção a meio caminho entre os eixos e . O que acontece? Você consegue fazer uma medição nessa direção? Como isso se relaciona com a incerteza em e ?