A Figura 1 mostra o circuito quântico que realiza a operação de subtração. Esse circuito quântico é chamado de Full Subtractor Quântico em analogia ao circuito lógico Full Subtractor. Considerando as entradas, o qubit qr[0] equivale ao bit borrow in, o qubit qr[1] equivale ao bit que representa minuendo e o qubit qr[2] equivale ao bit que representa o subtraendo. Nas saída, o qubit qr[2] equivale à diferença e o qubit qr[3] equivale ao bit borrow out. Portas de Pauli X são utilizadas para alterar os estados iniciais dos qubits de $\left|0\right\rangle$ para $\left|1\right\rangle$. Na Figura 1, os qubits qr[0] e qr[1] têm os seus estados iniciais alterados para $\left|1\right\rangle$ o que equivale a realizar a operação de subtração em um Full Subtractor clássico com borrow in igual a 1, minuendo também igual a 1 e subtraendo igual a 0. O resultado esperado para essa operação é 0 para a diferença e 0 para o borrow out.
Figura 1. Full Subtractor Quântico.
No Qiskit, as bibliotecas necessárias implementar o circuito quântico da Figura 1 são:
from qiskit import QuantumCircuit,
from qiskit import QuantumRegister,
from qiskit import ClassicalRegister,
from qiskit import Aer
e
from qiskit import execute.
São necessários quatro qubits e dois bits clássicos. Os registradores quântico e clássico são instanciados
pelos comandos:
qr = QuantumRegister(4)
e
cr = ClassicalRegister(2).
Os registradores quântico e clássico são dados como argumento ao construtor QuantumCircuit() quando o circuito
quântico é instanciado através de:
qc = QuantumCircuit(qr,cr).
As portas de Pauli X utilizadas para definir os estados dos qubits de entrada são implementadas por:
qc.x(qr[0])
e
qc.x(qr[1]).
A primeira porta CNOT tem qr[0] como qubit de controle e qr[2] como qubit alvo. Essa porta quântica é implementada por:
qc.cx(qr[0],qr[2]).
Como o estado inicial de qr[0] foi alterado para $\left|1\right\rangle$ pela porta de Pauli X, o estado de qr[2] será alterado para
$\left|1\right\rangle$. O qubit qr[1] volta ao estado $\left|0\right\rangle$ pela ação da porta de Pauli X que segue a porta CNOT.
A primeira porta TOFFOLI é implementada por:
qc.ccx(qr[1],qr[2],qr[3]).
Essa porta não altera o estado de qr[3] porque qr[1] está no estado $\left|0\right\rangle$.
O qubit qr[2] volta ao estado $\left|0\right\rangle$ devido à ação da porta CNOT
qc.cx(qr[0],qr[2]).
A porta TOFFOLI,
qc.ccx(qr[0],qr[2],qr[3]),
não altera o estado de qr[3] porque qr[2] está no estado $\left|0\right\rangle$. A porta de Pauli X,
qc.x(qr[1]),
altera o estado de qr[1] para $\left|1\right\rangle$ que atua como qubit de controle da porta CNOT
qc.cx(qr[1],qr[2]).
Essa porta altera o estado de qr[2] para $\left|1\right\rangle$, mas a última porta CNOT,
qc.cx(qr[0],qr[2]),
faz com que o estado desse qubit volte para $\left|0\right\rangle$.
Ao final do algoritmo temos a implementação dos medidores quânticos por:
qc.measure(qr[2],cr[0])
e
qc.measure(qr[3],cr[1]).
As linhas de comando para a execução do algoritmo são as mesmas implementadas nos algoritmos anteriores com o uso do simulador
QASM Simulator. O algoritmo completo é apresentado a seguir:
from qiskit import QuantumCircuit
from qiskit import QuantumRegister
from qiskit import ClassicalRegister
from qiskit import Aer
from qiskit import execute
qr = QuantumRegister(4)
cr = ClassicalRegister(2)
qc = QuantumCircuit(qr,cr)
qc.x(qr[0])
qc.x(qr[1])
qc.cx(qr[0],qr[2])
qc.x(qr[1])
qc.ccx(qr[1],qr[2],qr[3])
qc.cx(qr[0],qr[2])
qc.ccx(qr[0],qr[2],qr[3])
qc.x(qr[1])
qc.cx(qr[1],qr[2])
qc.cx(qr[0],qr[2])
qc.measure(qr[2],cr[0])
qc.measure(qr[3],cr[1])
backend = Aer.get_backend('qasm_simulator')
job = execute(qc,backend,shots=100)
resultado = job.result()
contagem = resultado.get_counts()
print(contagem)
O resultado desse algoritmo será: {'00': 100}. As cem execuções realizadas obtiveram o mesmo resultado. Logo, a probabilidade para o resultado 00 é 1. Esse é o único resultado que pode ser obtido com a execução desse algoritmo. O resultado 00, que indica que qr[3] = 0 e qr[2] = 0, equivale ao número binário 00 que é o número decimal 0 como esperado.
No Forest, as bibliotecas necessárias para a execução do algoritmo que implementa o circuito para o Full Subtractor
são importadas por:
from pyquil import get_qc, Program,
from pyquil.gates import *
e
from pyquil.quilbase import Declare.
O circuito quântico é instanciado por:
p = Program().
Os qubits qr[0] e qr[1] têm os seus estados alterados pela ação das portas de Pauli X que são implementadas por:
p += X(0)
e
p += X(1).
A porta CNOT
p += CNOT(0,2)
altera o estado de qr[2] para $\left|1\right\rangle$.
O qubit qr[1] volta ao estado $\left|0\right\rangle$ devido a
p += X(1),
portanto a porta TOFFOLI
p += CCNOT(1,2,3)
não altera o estado de qr[3]. A porta CNOT
p += CNOT(0,2)
altera o estado de qr[2] para $\left|0\right\rangle$. Logo, a porta TOFFOLI
p += CCNOT(0,2,3)
também não altera o estado de qr[3]. O qubit qr[1] volta ao estado $\left|1\right\rangle$ pela ação da porta
quântica
p += X(1)
de modo que
p += CNOT(1,2)
altera o estado de qr[2] para $\left|1\right\rangle$ e
p += CNOT(0,2)
altera o estado de qr[2] para $\left|0\right\rangle$. Um registrador clássico contendo dois bits para armazenar o resultado das
medições dos dois qubits é instanciado pelo método declare(). Uma máquina quântica virtual de quatro
qubits é instanciada e os comandos para compilar e executar são implementado no algoritmo. O algoritmo completo é mostrado abaixo.
from pyquil import get_qc, Program
from pyquil.gates import *
from pyquil.quilbase import Declare
p = Program()
p += X(0)
p += X(1)
p += CNOT(0,2)
p += X(1)
p += CCNOT(1,2,3)
p += CNOT(0,2)
p += CCNOT(0,2,3)
p += X(1)
p += CNOT(1,2)
p += CNOT(0,2)
ro = p.declare('ro', 'BIT', 2)
p += MEASURE(2, ro[0])
p += MEASURE(3, ro[1])
qc = get_qc("4q-qvm")
executable = qc.compile(p)
result = qc.run(executable)
print(result.readout_data.get('ro'))
O resultado da execução do algoritmo acima é [ [0 0] ] que é uma matriz com um único elemento. O par de valores 0 e 0 é o elemento dessa matriz. O primeiro 0 é o resultado da medição do qubit qr[2] e o segundo 0, o resultado da medição do qubit qr[3]. Esses resultados indicam que o resultado da operação de subtração é o número binário 00 que é o número decimal 0.
No Cirq, o algoritmo inicia-se com a importação da biblioteca cirq. Então, o circuito quântico e os qubits são
instanciados por:
qc = cirq.Circuit(),
qr0 = cirq.NamedQubit('qr[0]'),
qr1 = cirq.NamedQubit('qr[1]'),
qr2 = cirq.NamedQubit('qr[2]'),
e
qr3 = cirq.NamedQubit('qr[3]').
As portas de Pauli X, que são utilizadas para estabelecer os estados iniciais dos qubits, são implementadas por:
qc.append(cirq.X(qr0))
e
qc.append(cirq.X(qr1)).
A primeira porta CNOT é implementada por:
qc.append(cirq.CNOT(qr0,qr2)).
O qubit qr[1] volta ao estado $\left|0\right\rangle$ pela ação da porta de Pauli X implementada por:
qc.append(cirq.X(qr1)).
Logo, a porta TOFFOLI
qc.append(cirq.TOFFOLI(qr1,qr2,qr3))
não altera o estado de qr[3]. A porta CNOT
qc.append(cirq.CNOT(qr0,qr2))
altera o estado de qr[2] para $\left|0\right\rangle$. Assim, a porta TOFFOLI
qc.append(cirq.TOFFOLI(qr0,qr2,qr3))
não altere o estado de qr[3]. O qubit qr[1] tem o seu estado alterado para $\left|1\right\rangle$ por:
qc.append(cirq.X(qr1)).
Assim, a porta CNOT
qc.append(cirq.CNOT(qr1,qr2))
altera o estado de qr[2] para $\left|1\right\rangle$ e a última porta CNOT
qc.append(cirq.CNOT(qr0,qr2))
altera o estado de qr[2] para $\left|0\right\rangle$.
Os qubits qr[2] e qr[3] são medidos por:
qc.append(cirq.measure(qr2,key = 'qr[2]'))
e
qc.append(cirq.measure(qr3,key = 'qr[3]')).
O simulador é instanciado por:
simulador = cirq.Simulator().
O método run(), que é utilizado na execução do algoritmo, é implementado por:
resultado = simulador.run(qc,repetitions=10).
O algoritmo completo é mostrado a seguir:
import cirq
qc = cirq.Circuit()
qr0 = cirq.NamedQubit('qr[0]')
qr1 = cirq.NamedQubit('qr[1]')
qr2 = cirq.NamedQubit('qr[2]')
qr3 = cirq.NamedQubit('qr[3]')
qc.append(cirq.X(qr0))
qc.append(cirq.X(qr1))
qc.append(cirq.CNOT(qr0,qr2))
qc.append(cirq.X(qr1))
qc.append(cirq.TOFFOLI(qr1,qr2,qr3))
qc.append(cirq.CNOT(qr0,qr2))
qc.append(cirq.TOFFOLI(qr0,qr2,qr3))
qc.append(cirq.X(qr1))
qc.append(cirq.CNOT(qr1,qr2))
qc.append(cirq.CNOT(qr0,qr2))
qc.append(cirq.measure(qr2,key = 'qr[2]'))
qc.append(cirq.measure(qr3,key = 'qr[3]'))
simulador = cirq.Simulator()
resultado = simulador.run(qc,repetitions=10)
print(resultado)
O resultado da execução do algoritmo acima é
qr[2]=0000000000
qr[3]=0000000000
Em todas as execuções, o valor 0 foi o resultado das medições dos qubits qr[2] e qr[3]. Foram realizadas dez execuções que se deve ao valor 10 atribuído à variável repetitions. O resultado 0 para qr[2] e 0 para qr[3] equivale ao número binário 00 que é o número decimal 0.