Pular para o conteúdo principal
Este projeto está em fase beta. Encontrou um bug? Abra uma issue no GitHub. Tem uma pergunta ou ideia? Pergunte no Discussions — adoraríamos receber seu feedback!
Como está a qualidade da tradução nesta página?

Implementação com Qiskit

Na lição anterior, tivemos um primeiro contato com as classes Statevector e Operator do Qiskit, e as usamos para simular operações e medições em qubits individuais. Nesta seção, usaremos essas classes para explorar o comportamento de múltiplos qubits.

# Added by doQumentation — installs the packages this notebook needs if they are missing
import importlib.util

_needed = {"numpy": "numpy", "qiskit": "qiskit"}
_missing = [pip for module, pip in _needed.items()
if importlib.util.find_spec(module) is None]
# One at a time, so a package that fails to install does not block the others
for _pip in _missing:
%pip install -q {_pip}
if not _missing:
print("\u2713 All required packages are installed")
from qiskit import __version__

print(__version__)
2.1.1

Começaremos importando as classes Statevector e Operator, bem como a função de raiz quadrada do NumPy. A partir daqui, em geral, cuidaremos de todos os imports necessários logo no início de cada lição.

from qiskit.quantum_info import Statevector, Operator
from numpy import sqrt

Produtos tensoriais​

A classe Statevector possui um método tensor, que retorna o produto tensorial daquele Statevector com outro, fornecido como argumento. O argumento é interpretado como o fator tensorial à direita.

Por exemplo, abaixo criamos dois vetores de estado representando ∣0⟩\vert 0\rangle e ∣1⟩,\vert 1\rangle, e usamos o método tensor para criar um novo vetor, ∣ψ⟩=∣0⟩⊗∣1⟩.\vert \psi\rangle = \vert 0\rangle \otimes \vert 1\rangle. Observe que estamos usando o método from_label para definir os estados ∣0⟩\vert 0\rangle e ∣1⟩,\vert 1\rangle, em vez de defini-los manualmente.

zero = Statevector.from_label("0")
one = Statevector.from_label("1")
psi = zero.tensor(one)
display(psi.draw("latex"))

∣01⟩ |01\rangle

Outros rótulos permitidos incluem "+" e "-" para os estados mais e menos, bem como "r" e "l" (abreviações de "right" e "left") para os estados

∣+i⟩=12∣0⟩+i2∣1⟩e∣−i⟩=12∣0⟩−i2∣1⟩.\vert {+i} \rangle = \frac{1}{\sqrt{2}} \vert 0 \rangle + \frac{i}{\sqrt{2}} \vert 1 \rangle \qquad\text{e}\qquad \vert {-i} \rangle = \frac{1}{\sqrt{2}} \vert 0 \rangle - \frac{i}{\sqrt{2}} \vert 1 \rangle.

Aqui, "+" , "-" ou "right" e "left" vêm do contexto do spin na mecânica quântica, no qual uma componente do spin pode apontar para a esquerda ou para a direita em um experimento; não se refere ao qubit mais à direita ou mais à esquerda em sistemas de múltiplos qubits. Veja um exemplo do produto tensorial de ∣+⟩\vert {+} \rangle e ∣−i⟩\vert {-i} \rangle.

plus = Statevector.from_label("+")
minus_i = Statevector.from_label("l")
phi = plus.tensor(minus_i)
display(phi.draw("latex"))

12∣00⟩−i2∣01⟩+12∣10⟩−i2∣11⟩\frac{1}{2} |00\rangle- \frac{i}{2} |01\rangle+\frac{1}{2} |10\rangle- \frac{i}{2} |11\rangle

Uma alternativa é usar a operação ^ para produtos tensoriais, que naturalmente fornece os mesmos resultados.

display((plus ^ minus_i).draw("latex"))

12∣00⟩−i2∣01⟩+12∣10⟩−i2∣11⟩\frac{1}{2} |00\rangle- \frac{i}{2} |01\rangle+\frac{1}{2} |10\rangle- \frac{i}{2} |11\rangle

A classe Operator também possui um método tensor (assim como um método from_label), como vemos nos exemplos a seguir.

H = Operator.from_label("H")
Id = Operator.from_label("I")
X = Operator.from_label("X")
display(H.tensor(Id).draw("latex"))
display(H.tensor(Id).tensor(X).draw("latex"))
[220220022022220−2200220−22] \begin{bmatrix} \frac{\sqrt{2}}{2} & 0 & \frac{\sqrt{2}}{2} & 0 \\ 0 & \frac{\sqrt{2}}{2} & 0 & \frac{\sqrt{2}}{2} \\ \frac{\sqrt{2}}{2} & 0 & - \frac{\sqrt{2}}{2} & 0 \\ 0 & \frac{\sqrt{2}}{2} & 0 & - \frac{\sqrt{2}}{2} \\ \end{bmatrix} [0220002200220002200000022000220022000220022000−220022000−2200000022000−220022000−220] \begin{bmatrix} 0 & \frac{\sqrt{2}}{2} & 0 & 0 & 0 & \frac{\sqrt{2}}{2} & 0 & 0 \\ \frac{\sqrt{2}}{2} & 0 & 0 & 0 & \frac{\sqrt{2}}{2} & 0 & 0 & 0 \\ 0 & 0 & 0 & \frac{\sqrt{2}}{2} & 0 & 0 & 0 & \frac{\sqrt{2}}{2} \\ 0 & 0 & \frac{\sqrt{2}}{2} & 0 & 0 & 0 & \frac{\sqrt{2}}{2} & 0 \\ 0 & \frac{\sqrt{2}}{2} & 0 & 0 & 0 & - \frac{\sqrt{2}}{2} & 0 & 0 \\ \frac{\sqrt{2}}{2} & 0 & 0 & 0 & - \frac{\sqrt{2}}{2} & 0 & 0 & 0 \\ 0 & 0 & 0 & \frac{\sqrt{2}}{2} & 0 & 0 & 0 & - \frac{\sqrt{2}}{2} \\ 0 & 0 & \frac{\sqrt{2}}{2} & 0 & 0 & 0 & - \frac{\sqrt{2}}{2} & 0 \\ \end{bmatrix}

Novamente, como no caso dos vetores, a operação ^ é equivalente.

display((H ^ Id ^ X).draw("latex"))
[0220002200220002200000022000220022000220022000−220022000−2200000022000−220022000−220] \begin{bmatrix} 0 & \frac{\sqrt{2}}{2} & 0 & 0 & 0 & \frac{\sqrt{2}}{2} & 0 & 0 \\ \frac{\sqrt{2}}{2} & 0 & 0 & 0 & \frac{\sqrt{2}}{2} & 0 & 0 & 0 \\ 0 & 0 & 0 & \frac{\sqrt{2}}{2} & 0 & 0 & 0 & \frac{\sqrt{2}}{2} \\ 0 & 0 & \frac{\sqrt{2}}{2} & 0 & 0 & 0 & \frac{\sqrt{2}}{2} & 0 \\ 0 & \frac{\sqrt{2}}{2} & 0 & 0 & 0 & - \frac{\sqrt{2}}{2} & 0 & 0 \\ \frac{\sqrt{2}}{2} & 0 & 0 & 0 & - \frac{\sqrt{2}}{2} & 0 & 0 & 0 \\ 0 & 0 & 0 & \frac{\sqrt{2}}{2} & 0 & 0 & 0 & - \frac{\sqrt{2}}{2} \\ 0 & 0 & \frac{\sqrt{2}}{2} & 0 & 0 & 0 & - \frac{\sqrt{2}}{2} & 0 \\ \end{bmatrix}

Podemos fazer estados compostos evoluírem por meio de operações compostas, como era de se esperar — assim como vimos para sistemas individuais na lição anterior. Por exemplo, o código a seguir calcula o estado (H⊗I)∣ϕ⟩(H\otimes I)\vert\phi\rangle para ∣ϕ⟩=∣+⟩⊗∣−i⟩\vert\phi\rangle = \vert + \rangle \otimes \vert {-i}\rangle (que já foi definido acima).

display(phi.evolve(H ^ Id).draw("latex"))

22∣00⟩−2i2∣01⟩\frac{\sqrt{2}}{2} |00\rangle- \frac{\sqrt{2} i}{2} |01\rangle

Aqui está um código que define uma operação CXCX e calcula CX∣ψ⟩CX \vert\psi\rangle para ∣ψ⟩=∣+⟩⊗∣0⟩\vert\psi\rangle = \vert + \rangle \otimes \vert 0 \rangle. Para deixar claro, esta é uma operação CXCX em que o qubit à esquerda é o controle e o qubit à direita é o alvo. O resultado é o estado de Bell ∣ϕ+⟩\vert\phi^{+}\rangle.

CX = Operator([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]])
psi = plus.tensor(zero)
display(psi.evolve(CX).draw("latex"))

22∣00⟩+22∣11⟩\frac{\sqrt{2}}{2} |00\rangle+\frac{\sqrt{2}}{2} |11\rangle

Medições parciais​

Na lição anterior, usamos o método measure para simular uma medição de um vetor de estado quântico. Este método retorna dois itens: o resultado simulado da medição e o novo Statevector resultante dessa medição.

Por padrão, measure mede todos os qubits no vetor de estado. Como alternativa, podemos fornecer uma lista de inteiros como argumento, o que faz com que apenas os índices de qubit indicados sejam medidos. Para demonstrar isso, o código abaixo cria o estado

∣w⟩=∣001⟩+∣010⟩+∣100⟩3\vert w\rangle = \frac{\vert 001\rangle + \vert 010\rangle + \vert 100\rangle}{\sqrt{3}}

e mede o qubit de número 0, que é o qubit mais à direita. (O Qiskit numera os qubits a partir de 0, da direita para a esquerda. Voltaremos a essa convenção de numeração na próxima lição.)

w = Statevector([0, 1, 1, 0, 1, 0, 0, 0] / sqrt(3))
display(w.draw("latex"))

result, state = w.measure([0])
print(f"Measured: {result}\nState after measurement:")
display(state.draw("latex"))

result, state = w.measure([0, 1])
print(f"Measured: {result}\nState after measurement:")
display(state.draw("latex"))

33∣001⟩+33∣010⟩+33∣100⟩\frac{\sqrt{3}}{3} |001\rangle+\frac{\sqrt{3}}{3} |010\rangle+\frac{\sqrt{3}}{3} |100\rangle

Measured: 0
State after measurement:

22∣010⟩+22∣100⟩\frac{\sqrt{2}}{2} |010\rangle+\frac{\sqrt{2}}{2} |100\rangle

Measured: 00
State after measurement:

∣100⟩ |100\rangle