らんだむな記憶

blogというものを体験してみようか!的なー

逆演算 (2)

逆演算 (1) - らんだむな記憶 の続きとして、textbook で扱われているサンプルについて眺める。textbook そのままであるが、一部気になったので補足を追加する。

from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister
from qiskit import execute, Aer
from qiskit.visualization import plot_histogram

input_bit = QuantumRegister(1, 'input')
output_bit = QuantumRegister(1, 'output')
garbage_bit = QuantumRegister(1, 'garbage')

Uf = QuantumCircuit(input_bit, output_bit, garbage_bit)
Uf.cx(input_bit[0], output_bit[0])

Vf = QuantumCircuit(input_bit, output_bit, garbage_bit)
Vf.cx(input_bit[0], garbage_bit[0])
Vf.cx(input_bit[0], output_bit[0])

final_output_bit = QuantumRegister(1, 'final-output')

copy = QuantumCircuit(output_bit, final_output_bit)
copy.cx(output_bit, final_output_bit)

qbits = (input_bit, output_bit, garbage_bit, final_output_bit)
clbits = ClassicalRegister(len(qbits), 'c')
qc = QuantumCircuit(*qbits, clbits)
qc.h(0)
qc.barrier()
qc = qc.compose(Vf.inverse())
qc = qc.compose(copy, qubits=[1, 3])
qc = qc.compose(Vf)
qc.barrier()
for i in range(qc.num_qubits):
    qc.measure(i, i)
qc.draw('mpl')

で回路を作って可視化すると:

f:id:derwind:20220212032028p:plain

このような感じに。これを測定すると、入力を $\frac{1}{\sqrt{2}}(\ket{0} + \ket{1})$ で初期化したので、$\ket{q_0} = \ket{0}$ の時は $\ket{f(x)} = \ket{0}$ が、$\ket{q_0} = \ket{1}$ の時は $\ket{f(x)} = \ket{1}$ が 50% ずつ観測されるはずである。つまり、$\ket{0000}$ と $\ket{1001}$ が 50% ずつ観測されるはずである。

backend = Aer.get_backend('qasm_simulator')
shots = 1042
results = execute(qc, backend=backend, shots=shots).result()
answer = results.get_counts()

plot_histogram(answer)

を実行すると:

f:id:derwind:20220212032217p:plain

ということで期待通りの結果となる。

・・・ただ、textbook の内容だと回路の構成順序がコード的には違うのではないだろうか・・・。(実質回路も等価ではあるのだが・・・) 操作として $V_f^\dagger U_{2,4}^{cp} V_f$ を適用する場合、見た目の式の順序とコードの適用順は逆になると思われる。

qc = qc.compose(Vf)
qc = qc.compose(copy, qubits=[1, 3])
qc = qc.compose(Vf.inverse())

だと思うのだが、この場合は回路図は以下のようになるだけで、測定と観測結果は特に変化はしない:

f:id:derwind:20220212032929p:plain