Langkau ke kandungan utama

Pelaksanaan Qiskit

Dalam pelajaran ini, kita akan melaksanakan beberapa idea dari pelajaran tentang jalinan dalam tindakan, menggunakan Qiskit.

# Added by doQumentation — required packages for this notebook
!pip install -q qiskit qiskit-aer
from qiskit import __version__

print(__version__)
2.1.1
from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister
from qiskit_aer import AerSimulator
from qiskit.visualization import plot_histogram, array_to_latex
from qiskit.result import marginal_distribution
from qiskit.circuit.library import UGate
from math import pi
import random

Berikut ialah pelaksanaan litar kuantum untuk protokol teleportasi.

qubit = QuantumRegister(1, "Q")
ebit0 = QuantumRegister(1, "A")
ebit1 = QuantumRegister(1, "B")
a = ClassicalRegister(1, "a")
b = ClassicalRegister(1, "b")

protocol = QuantumCircuit(qubit, ebit0, ebit1, a, b)

# Prepare ebit used for teleportation
protocol.h(ebit0)
protocol.cx(ebit0, ebit1)
protocol.barrier()

# Alice's operations
protocol.cx(qubit, ebit0)
protocol.h(qubit)
protocol.barrier()

# Alice measures and sends classical bits to Bob
protocol.measure(ebit0, a)
protocol.measure(qubit, b)
protocol.barrier()

# Bob uses the classical bits to conditionally apply gates
with protocol.if_test((a, 1)):
protocol.x(ebit1)
with protocol.if_test((b, 1)):
protocol.z(ebit1)

display(protocol.draw(output="mpl"))

Output of the previous code cell

Litar ini menggunakan beberapa ciri Qiskit yang belum kita lihat dalam pelajaran sebelumnya, termasuk fungsi barrier dan if_test. Fungsi barrier mencipta pemisahan visual yang menjadikan gambar rajah litar lebih mudah dibaca, dan ia juga menghalang Qiskit daripada melakukan pelbagai penyederhanaan dan pengoptimuman merentasi penghalang semasa penyusunan apabila litar dijalankan pada perkakasan sebenar. Fungsi if_test menerapkan operasi secara bersyarat bergantung pada bit atau daftar klasik.

Litar ini mula-mula memulakan (A,B)(\mathsf{A},\mathsf{B}) untuk berada dalam keadaan ϕ+\vert \phi^+\rangle (yang bukan sebahagian daripada protokol itu sendiri), diikuti dengan operasi Alice, kemudian pengukurannya, dan akhirnya operasi Bob. Untuk menguji bahawa protokol berfungsi dengan betul, kita akan menerapkan get satu-qubit yang dijana secara rawak pada keadaan 0\vert 0\rangle yang dimulakan bagi Q\mathsf{Q} untuk mendapatkan vektor keadaan kuantum rawak untuk diteleportasikan. Dengan menerapkan songsangan (iaitu, anak matrik konjugat) get tersebut pada B\mathsf{B} selepas protokol dijalankan, kita boleh mengesahkan bahawa keadaan telah diteleportasikan dengan mengukur untuk melihat bahawa ia telah kembali ke keadaan 0\vert 0\rangle.

Pertama sekali kita akan memilih secara rawak get qubit unitari.

random_gate = UGate(
theta=random.random() * 2 * pi,
phi=random.random() * 2 * pi,
lam=random.random() * 2 * pi,
)

display(array_to_latex(random_gate.to_matrix()))
[0.98972121580.01950801030.141673401i0.0603319186+0.1296609988i0.8319925233+0.5360378028i] \begin{bmatrix} 0.9897212158 & -0.0195080103 - 0.141673401 i \\ 0.0603319186 + 0.1296609988 i & -0.8319925233 + 0.5360378028 i \\ \end{bmatrix}

Sekarang kita akan mencipta litar ujian baru yang mula-mula menerapkan get rawak kita pada Q\mathsf{Q}, kemudian menjalankan litar teleportasi, dan akhirnya menerapkan songsangan get rawak kita pada qubit B\mathsf{B} dan mengukur. Hasilnya sepatutnya 00 dengan kepastian.

# Create a new circuit including the same bits and qubits used in the
# teleportation protocol.

test = QuantumCircuit(qubit, ebit0, ebit1, a, b)

# Start with the randomly selected gate on Q

test.append(random_gate, qubit)
test.barrier()

# Append the entire teleportation protocol from above.

test = test.compose(protocol)
test.barrier()

# Finally, apply the inverse of the random unitary to B and measure.

test.append(random_gate.inverse(), ebit1)
result = ClassicalRegister(1, "Result")
test.add_register(result)
test.measure(ebit1, result)

display(test.draw(output="mpl"))

Output of the previous code cell

Akhir sekali, mari jalankan simulator Aer pada litar ini dan plot histogram output. Kita akan melihat statistik untuk ketiga-tiga bit klasik: bit bawah/paling kiri sepatutnya sentiasa 00, menunjukkan bahawa qubit Q\mathsf{Q} berjaya diteleportasikan ke dalam B\mathsf{B}, manakala dua bit yang lain sepatutnya lebih kurang seragam.

result = AerSimulator().run(test).result()
statistics = result.get_counts()
display(plot_histogram(statistics))

Output of the previous code cell

Kita juga boleh menapis statistik untuk memberi tumpuan semata-mata pada qubit keputusan ujian jika kita mahu, seperti ini:

filtered_statistics = marginal_distribution(statistics, [2])
display(plot_histogram(filtered_statistics))

Output of the previous code cell

Pengekodan superpadu

Pengekodan superpadu ialah protokol yang, dalam ertikata tertentu, mencapai matlamat yang saling melengkapi dengan teleportasi. Daripada membenarkan penghantaran satu qubit menggunakan dua bit komunikasi klasik (dengan kos satu e-bit jalinan), ia membenarkan penghantaran dua bit klasik menggunakan satu qubit komunikasi kuantum (sekali lagi, dengan kos satu e-bit jalinan).

Secara lebih terperinci, kita ada seorang penghantar (Alice) dan penerima (Bob) yang berkongsi satu e-bit jalinan. Mengikut konvensyen yang digunakan untuk pelajaran ini, ini bermakna Alice memegang qubit A\mathsf{A}, Bob memegang qubit B\mathsf{B}, dan bersama-sama pasangan (A,B)(\mathsf{A},\mathsf{B}) berada dalam keadaan ϕ+\vert\phi^+\rangle. Alice ingin menghantar dua bit klasik kepada Bob, yang kita tandakan sebagai cc dan dd, dan dia akan mencapai ini dengan menghantar satu qubit kepadanya.

Adalah munasabah untuk melihat pencapaian ini sebagai kurang menarik berbanding yang dicapai oleh teleportasi. Menghantar qubit kemungkinan besar akan jauh lebih sukar daripada menghantar bit klasik pada masa hadapan yang dapat dijangkau sehingga menukar satu qubit komunikasi kuantum dengan dua bit komunikasi klasik, dengan kos e-bit pula, nampaknya tidak berbaloi. Walau bagaimanapun, ini tidak bermakna pengekodan superpadu tidak menarik, kerana ia sememangnya menarik.

Sesuai dengan tema pelajaran, salah satu sebab mengapa pengekodan superpadu menarik ialah ia menunjukkan penggunaan jalinan yang konkrit dan (dalam konteks teori maklumat) agak mengejutkan. Teorem terkenal dalam teori maklumat kuantum, dikenali sebagai teorem Holevo, membawa maksud bahawa tanpa penggunaan keadaan jalinan yang dikongsi, adalah mustahil untuk menyampaikan lebih daripada satu bit maklumat klasik dengan menghantar satu qubit tunggal. (Teorem Holevo lebih umum daripada ini. Pernyataan tepatnya adalah teknikal dan memerlukan penjelasan, tetapi ini adalah salah satu akibatnya.) Jadi, melalui pengekodan superpadu, jalinan yang dikongsi secara berkesan membenarkan penggandaan kapasiti membawa maklumat klasik daripada penghantaran qubit.

Protokol

Gambar rajah litar kuantum berikut menerangkan protokol pengekodan superpadu:

Superdense coding circuit

Dalam kata-kata, inilah yang Alice lakukan:

  1. Jika d=1d=1, Alice melakukan get ZZ pada qubitnya A\mathsf{A} (dan jika d=0d=0 dia tidak melakukannya).

  2. Jika c=1c=1, Alice melakukan get XX pada qubitnya A\mathsf{A} (dan jika c=0c=0 dia tidak melakukannya).

Alice kemudian menghantar qubitnya A\mathsf{A} kepada Bob.

Apa yang Bob lakukan apabila menerima qubit A\mathsf{A} ialah mula-mula melakukan get NOT terkawal, dengan A\mathsf{A} sebagai kawalan dan B\mathsf{B} sebagai sasaran, dan kemudian dia menerapkan get Hadamard pada A\mathsf{A}. Dia kemudian mengukur B\mathsf{B} untuk mendapatkan cc dan A\mathsf{A} untuk mendapatkan dd, dengan pengukuran asas standard dalam kedua-dua kes.

Analisis

Idea di sebalik protokol ini adalah mudah: Alice secara berkesan memilih keadaan Bell mana yang dia ingin kongsi dengan Bob, dia menghantar qubitnya kepada Bob, dan Bob mengukur untuk menentukan keadaan Bell mana yang dipilih oleh Alice.

Iaitu, mereka pada mulanya berkongsi ϕ+,\vert\phi^+\rangle, dan bergantung pada bit cc dan d,d, Alice sama ada membiarkan keadaan ini atau menganjak ke salah satu keadaan Bell yang lain dengan menerapkan I,\mathbb{I}, X,X, Z,Z, atau XZXZ pada qubitnya A.\mathsf{A}.

(II)ϕ+=ϕ+(IZ)ϕ+=ϕ(IX)ϕ+=ψ+(IXZ)ϕ+=ψ\begin{aligned} (\mathbb{I} \otimes \mathbb{I}) \vert \phi^+ \rangle & = \vert \phi^+\rangle \\ (\mathbb{I} \otimes Z) \vert \phi^+ \rangle & = \vert \phi^-\rangle \\ (\mathbb{I} \otimes X) \vert \phi^+ \rangle & = \vert \psi^+\rangle \\ (\mathbb{I} \otimes XZ) \vert \phi^+ \rangle & = \vert \psi^-\rangle \end{aligned}

Tindakan Bob memberi kesan berikut pada keempat-empat keadaan Bell:

ϕ+00ϕ01ψ+10ψ11\begin{aligned} \vert \phi^+\rangle & \mapsto \vert 00\rangle\\ \vert \phi^-\rangle & \mapsto \vert 01\rangle\\ \vert \psi^+\rangle & \mapsto \vert 10\rangle\\ \vert \psi^-\rangle & \mapsto -\vert 11\rangle\\ \end{aligned}

Ini boleh disemak secara langsung, dengan mengira hasil operasi Bob pada keadaan-keadaan ini satu persatu.

Jadi, apabila Bob melakukan pengukurannya, dia dapat menentukan keadaan Bell mana yang dipilih oleh Alice. Untuk mengesahkan bahawa protokol berfungsi dengan betul adalah dengan menyemak setiap kes:

  • Jika cd=00cd = 00, maka keadaan (B,A)(\mathsf{B},\mathsf{A}) apabila Bob menerima A\mathsf{A} ialah ϕ+\vert \phi^+\rangle. Dia mentransformasi keadaan ini menjadi 00\vert 00\rangle dan mendapat cd=00cd = 00.

  • Jika cd=01cd = 01, maka keadaan (B,A)(\mathsf{B},\mathsf{A}) apabila Bob menerima A\mathsf{A} ialah ϕ\vert \phi^-\rangle. Dia mentransformasi keadaan ini menjadi 01\vert 01\rangle dan mendapat cd=01cd = 01.

  • Jika cd=10cd = 10, maka keadaan (B,A)(\mathsf{B},\mathsf{A}) apabila Bob menerima A\mathsf{A} ialah ψ+\vert \psi^+\rangle. Dia mentransformasi keadaan ini menjadi 10\vert 10\rangle dan mendapat cd=10cd = 10.

  • Jika cd=11cd = 11, maka keadaan (B,A)(\mathsf{B},\mathsf{A}) apabila Bob menerima A\mathsf{A} ialah ψ\vert \psi^-\rangle. Dia mentransformasi keadaan ini menjadi 11-\vert 11\rangle dan mendapat cd=11cd = 11. (Faktor fasa negatif-satu tidak memberi kesan di sini.)

Pelaksanaan pengekodan superpadu

Berikut ialah pelaksanaan mudah pengekodan superpadu di mana kita menentukan litar itu sendiri bergantung pada bit yang hendak dihantar. Pertama kita akan memilih dua bit untuk dihantar. (Kemudian kita akan memilihnya secara rawak, tetapi buat masa ini kita hanya membuat pilihan sewenang-wenangnya.)

c = "1"
d = "0"

Sekarang kita akan membina litar mengikutnya. Di sini kita akan membenarkan Qiskit menggunakan nama lalai untuk qubit: q0\mathsf{q}_0 untuk qubit atas dan q1\mathsf{q}_1 untuk qubit bawah.

protocol = QuantumCircuit(2)

# Prepare ebit used for superdense coding
protocol.h(0)
protocol.cx(0, 1)
protocol.barrier()

# Alice's operations
if d == "1":
protocol.z(0)
if c == "1":
protocol.x(0)
protocol.barrier()

# Bob's actions
protocol.cx(0, 1)
protocol.h(0)
protocol.measure_all()

display(protocol.draw(output="mpl"))

Output of the previous code cell

Tidak banyak yang baharu di sini, kecuali fungsi measure_all, yang mengukur semua qubit dan meletakkan hasilnya ke dalam satu daftar klasik (dan oleh itu mempunyai dua bit dalam kes ini).

Menjalankan simulator Aer menghasilkan output yang dijangkakan.

result = AerSimulator().run(protocol).result()
statistics = result.get_counts()

for outcome, frequency in statistics.items():
print(f"Measured {outcome} with frequency {frequency}")

display(plot_histogram(statistics))
Measured 10 with frequency 1024

Output of the previous code cell

Sekarang mari gunakan qubit tambahan sebagai penjana bit rawak — pada dasarnya untuk membalik syiling yang adil. Kita akan gunakannya untuk memilih cc dan dd secara rawak, dan kemudian jalankan protokol pengekodan superpadu.

rbg = QuantumRegister(1, "coin")
ebit0 = QuantumRegister(1, "A")
ebit1 = QuantumRegister(1, "B")

Alice_c = ClassicalRegister(1, "Alice c")
Alice_d = ClassicalRegister(1, "Alice d")

test = QuantumCircuit(rbg, ebit0, ebit1, Alice_d, Alice_c)

# Initialize the ebit
test.h(ebit0)
test.cx(ebit0, ebit1)
test.barrier()

# Use the 'coin' qubit twice to generate Alice's bits c and d.
test.h(rbg)
test.measure(rbg, Alice_c)
test.h(rbg)
test.measure(rbg, Alice_d)
test.barrier()

# Now the protocol runs, starting with Alice's actions, which depend
# on her bits.
with test.if_test((Alice_d, 1), label="Z"):
test.z(ebit0)
with test.if_test((Alice_c, 1), label="X"):
test.x(ebit0)
test.barrier()

# Bob's actions
test.cx(ebit0, ebit1)
test.h(ebit0)
test.barrier()

Bob_c = ClassicalRegister(1, "Bob c")
Bob_d = ClassicalRegister(1, "Bob d")
test.add_register(Bob_d)
test.add_register(Bob_c)
test.measure(ebit0, Bob_d)
test.measure(ebit1, Bob_c)

display(test.draw(output="mpl"))

Output of the previous code cell

Menjalankan simulator Aer menunjukkan hasilnya: bit klasik Alice dan Bob sentiasa bersetuju.

result = AerSimulator().run(test).result()
statistics = result.get_counts()
display(plot_histogram(statistics))

Output of the previous code cell

Pelaksanaan Qiskit

Kita boleh melaksanakan permainan CHSH, bersama-sama dengan strategi kuantum yang ditakrifkan di atas, dalam Qiskit seperti berikut.

Pertama, berikut ialah definisi permainan itu sendiri, yang membenarkan strategi sewenang-wenang dimasukkan sebagai argumen.

def chsh_game(strategy):
# This function runs the CHSH game, using the strategy (a function
# from two bits to two bits), returning 1 for a win and 0 for a loss.

# Choose x and y randomly
x, y = random.randint(0, 1), random.randint(0, 1)

# Use the strategy to determine a and b
a, b = strategy(x, y)

# Decide if the strategy wins or loses
if (a != b) == (x & y):
return 1 # Win
return 0 # Lose

Sekarang kita akan mencipta fungsi yang menghasilkan litar bergantung pada soalan untuk Alice dan Bob. Kita akan membiarkan qubit mempunyai nama lalai mereka untuk kesederhanaan, dan kita akan menggunakan get Ry(θ)R_y(\theta) terbina dalam untuk tindakan Alice dan Bob.

def chsh_circuit(x, y):
# This function creates a `QuantumCircuit` implementing the quantum
# strategy described above (including the e-bit preparation).

qc = QuantumCircuit(2, 2)

# Prepare an e-bit
qc.h(0)
qc.cx(0, 1)
qc.barrier()

# Alice's actions
if x == 0:
qc.ry(0, 0)
else:
qc.ry(-pi / 2, 0)
qc.measure(0, 0)

# Bob's actions
if y == 0:
qc.ry(-pi / 4, 1)
else:
qc.ry(pi / 4, 1)
qc.measure(1, 1)

return qc

Berikut ialah keempat-empat litar yang mungkin, bergantung pada soalan mana yang ditanya.

# Draw the four possible circuits

print("(x,y) = (0,0)")
display(chsh_circuit(0, 0).draw(output="mpl"))

print("(x,y) = (0,1)")
display(chsh_circuit(0, 1).draw(output="mpl"))

print("(x,y) = (1,0)")
display(chsh_circuit(1, 0).draw(output="mpl"))

print("(x,y) = (1,1)")
display(chsh_circuit(1, 1).draw(output="mpl"))
(x,y) = (0,0)

Output of the previous code cell

(x,y) = (0,1)

Output of the previous code cell

(x,y) = (1,0)

Output of the previous code cell

(x,y) = (1,1)

Output of the previous code cell

Sekarang kita akan mencipta tugas menggunakan simulator Aer yang menjalankan litar sekali untuk pasangan input (x,y)(x,y) yang diberikan.

def quantum_strategy(x, y):
# This function runs the appropriate quantum circuit defined above
# one time and returns the measurement results

# Setting `shots=1` to run the circuit once
result = AerSimulator().run(chsh_circuit(x, y), shots=1).result()
statistics = result.get_counts()

# Determine the output bits and return them
bits = list(statistics.keys())[0]
a, b = bits[0], bits[1]
return a, b

Akhir sekali, kita akan memainkan permainan 1000 kali dan mengira pecahan yang dimenangi oleh strategi tersebut.

NUM_GAMES = 1000
TOTAL_SCORE = 0

for _ in range(NUM_GAMES):
TOTAL_SCORE += chsh_game(quantum_strategy)

print("Fraction of games won:", TOTAL_SCORE / NUM_GAMES)
Fraction of games won: 0.867

Kita juga boleh mentakrifkan strategi klasik dan melihat seberapa baik ia berfungsi. Ini hanyalah satu strategi — yang lain boleh diuji dengan menukar kod — tetapi ia adalah antara strategi klasik yang optimum.

def classical_strategy(x, y):
# This function implements just one example of an optimal classical
# strategy for the CHSH game. Other classical strategies can be
# implemented by changing the bit values assigned to a and b.

# Alice's answer
if x == 0:
a = 0
elif x == 1:
a = 1

# Bob's answer
if y == 0:
b = 1
elif y == 1:
b = 0

return a, b

Sekali lagi mari kita mainkan permainan 1000 kali untuk melihat seberapa baik ia berfungsi.

NUM_GAMES = 1000
TOTAL_SCORE = 0

for _ in range(NUM_GAMES):
TOTAL_SCORE += chsh_game(classical_strategy)

print("Fraction of games won:", TOTAL_SCORE / NUM_GAMES)
Fraction of games won: 0.747

Walaupun terdapat kerawakan yang terlibat, statistik sangat tidak mungkin menyimpang terlalu jauh selepas 1000 pusingan. Strategi kuantum menang kira-kira 85% daripada masa manakala strategi klasik tidak boleh menang lebih daripada kira-kira 75% daripada masa.