Komputasi Kuantum Teori dan Praktik
Daftar Isi
- Pendahuluan
- Bab 1: Keadaan Kuantum
- Bab 2: Operator
- Bab 3: Entanglement
-
Bab 4: Pemrograman Kuantum
- Pengantar
- 4.1 Visualisasi Qubit
- 4.2 Sirkuit Kuantum
- 4.3 Statevector
- 4.4 Probabilitas & Histogram
- 4.5 Pengukuran
- 4.6 Akses Komputer Kuantum
-
Bab 6: Informasi Kuantum
- Pengantar
- 6.1 Teleportasi
- 6.2 Superdense Coding
- 6.3 Teorema No-Cloning
- 6.4 Operasi Kuantum
6.5 Kanal Kuantum
- Pengantar
- 6.5.1 Kanal Bit Flip
- 6.5.2 Kanal Fase Flip
- 6.5.3 Kanal Depolarisasi
- 6.5.4 Peredaman Amplitudo
- 6.5.5 Peredaman Fase
6.6 Tool Informasi Kuantum
- Pengantar
- 6.6.1 Operator Densitas
- 6.6.2 Trace
- 6.6.3 Trace Parsial
- 6.6.4 Trace Distance
- 6.6.5 Fidelity
- 6.7 Entropi
- 6.8 Koreksi Eror Kuantum
-
Bab 7: Algoritma Kuantum Variasional
- Pengantar
- 7.1 Hamiltonian dan Prinsip Variasional
- 7.2 Variational Quantum Eigensolver
- 7.3 Quantum Approximate Optimisation Algorithm
-
Bab 8: Pembelajaran Mesin Kuantum
- Pengantar
- 8.1 Parameterised Quantum Circuit
- 8.2 Peta Fitur Kuantum
- 8.3 Kernel Kuantum
8.4 Quantum Support Vector Machine
- Pengantar
- 8.4.1 Quantum Support Vector Classifier
- 8.4.2 Quantum Support Vector Regressor
8.5 Variational Quantum Circuit
- Pengantar
- 8.5.1 Variational Quantum Classifier
- 8.5.2 Variational Quantum Regressor
- 8.6 Quantum Neural Network
- 8.7 Quantum Convolutional Neural Network
- Referensi
Pendahuluan
Komputasi Kuantum Teori dan Praktik menyajikan dasar-dasar komputasi kuantum secara mudah dan sederhana, baik dari sisi teori maupun praktik. Dokumen terdiri atas delapan bab yakni Keadaan Kuantum, Operator, Entanglement, Pemrograman Kuantum, Algoritma Kuantum, Informasi Kuantum, Algoritma Kuantum Variasional, serta Pembelajaran Mesin Kuantum.
Bab pertama, Keadaan Kuantum, mengenalkan bahasan tentang qubit, keadaan kuantum, superposisi, probabilitas, kondisi ternormalisasi, vektor Bloch, bra-ket, inner product, ortogonal dan ortonormal, outer product, matriks densitas, trace, keadaan murni, keadaan campuran, serta sistem kuantum 1-qubit.
Bab kedua, Operator, berisi bahasan tentang operator, operator Pauli, Hermitian, normal, unitary, gerbang kuantum, serta gerbang Hadamard.
Selanjutnya, bab ketiga adalah Entanglement. Bab ini membahas sistem kuantum 2-qubit, produk tensor, product state, sifat separable, sifat entangled, e-bit, serta gerbang kuantum terkontrol.
Bab keempat, Pemrograman Kuantum, berisi sajian tentang bahasa pemrograman dan SDK Qiskit, Dinfio module quantum, simulator, visualisasi qubit, sirkuit kuantum, statevector, probabilitas, histogram, pengukuran, serta akses komputer kuantum dengan Qiskit Runtime.
Bab kelima, Algoritma Kuantum, membahas fondasi dan implementasi algoritma kuantum, diantaranya yakni transformasi Walsh-Hadamard, transformasi unitary, orakel kuantum, register kuantum, paralelisme kuantum, orakel fase, algoritma Deutsch, transformasi Fourier kuantum, estimasi fase kuantum, vektor eigen, nilai eigen, serta algoritma Grover.
Bab keenam, Informasi Kuantum. Bab keenam menyajikan bahasan tentang teleportasi, superdense coding, teorema no-cloning, operasi kuantum, representasi operator-sum, operator Kraus, completely positive, trace-preserving, kanal kuantum, kanal bit flip, kanal fase flip, kanal depolarisasi, operator densitas, peredaman amplitudo, peredaman fase, trace parsial, trace distance, fidelity, entropi, entropi von Neumann, koreksi eror kuantum, serta kode bit flip 3-qubit.
Bab ketujuh, Algoritma Kuantum Variasional. Beberapa topik yang disajikan di bab ketujuh atau bab variational quantum algorithm yaitu Hamiltonian, prinsip variasional, noisy intermediate-scale quantum, nilai ekspektasi, energi dasar, variational quantum eigensolver, ansatz, parameterised quantum circuit, optimasi, iterasi, quantum approximate optimisation algorithm, cost Hamiltonian, mixing Hamiltonian, Max-Cut problem, serta graf.
Bab kedelapan, Pembelajaran Mesin Kuantum. Bab terakhir ini membahas dasar-dasar pembelajaran mesin kuantum atau quantum machine learning diantaranya yakni model kuantum, trainable, optimisable, expressivity, trainability, peta fitur kuantum, vektor fitur, ruang fitur kuantum, enkode basis, enkode amplitudo, enkode sudut, enkode fase, enkode sudut padat, kernel kuantum, quantum support vector machine, quantum support vector classifier, quantum support vector regressor, regresi ridge, variational quantum circuit, variational quantum classifier, RealAmplitudes, variational quantum regressor, quantum neural network, perceptron kuantum, serta quantum convolutional neural network.
Penulisan urutan qubit dalam dokumen ini menggunakan konvensi little-endian, yakni \(\ket{q_{n-1}...q_1q_0}\), kecuali di beberapa persamaan yang bertanda \(^*\) berarti memakai konvensi big-endian \(\ket{q_0q_1...q_{n-1}}\).
Bab 1: Keadaan Kuantum
— Qubit, keadaan kuantum, superposisi, probabilitas, kondisi ternormalisasi, vektor Bloch, bra-ket, inner product, ortogonal dan ortonormal, outer product, matriks densitas, trace, keadaan murni, keadaan campuran, sistem kuantum 1-qubit.
Jika dalam komputasi klasikal dikenal istilah bit atau binary digit, yaitu 0 dan 1, maka komputasi kuantum dibangun dengan qubit — quantum bit. Qubit adalah representasi dari keadaan kuantum — quantum state. Keadaan kuantum juga dikenal sebagai vektor atau ket. Ia merupakan superposisi dari vektor \(\ket{0}\) dan vektor \(\ket{1}\)
\[ \ket{\psi} = \alpha\ket{0} + \beta\ket{1} \tag{1.1} \]
Vektor-vektor tersebut dapat ditulis dalam bentuk vektor kolom yaitu
\[ \ket{0} = \begin{pmatrix} 1\\ 0 \end{pmatrix} \tag{1.2} \]
\[ \ket{1} = \begin{pmatrix} 0\\ 1 \end{pmatrix} \tag{1.3} \]
dan
\[ \ket{\psi} = \alpha \begin{pmatrix} 1\\ 0 \end{pmatrix} + \beta \begin{pmatrix} 0\\ 1 \end{pmatrix} = \begin{pmatrix} \alpha\\ \beta \end{pmatrix} \tag{1.4} \]
dengan \(|\alpha|^2\) merupakan probabilitas menemukan \(\ket{\psi}\) di vektor \(\ket{0}\) dan \(|\beta|^2\) adalah probabilitas menemukan \(\ket{\psi}\) di vektor \(\ket{1}\). Hubungan dari keduanya yaitu
\[ |\alpha|^2 + |\beta|^2 = 1 \tag{1.5} \]
Kondisi \((1.5)\) disebut sebagai ternormalisasi (normalised).
Vektor \((1.1)\) juga dapat ditulis sebagai
\[ \ket{\psi} = \cos{\frac{\theta}{2}}\ket{0} + e^{i \phi} \sin{\frac{\theta}{2}}\ket{1} \tag{1.6} \]
dan dikenal sebagai vektor Bloch.
Berikutnya, bra \(\bra{0}\) merupakan transpos konjugat kompleks dari ket \(\ket{0}\) sehingga bra \(\bra{0} = \big(1 \ \ 0 \big) \) dan dengan cara yang sama diperoleh bra \(\bra{1} = \big(0 \ \ 1 \big)\).
Perhatikan perhitungan inner product bra-ket berikut.
\[ \left \langle 0 \middle | 1 \right \rangle = \big(1 \ \ 0 \big) \begin{pmatrix} 0\\ 1 \end{pmatrix} = 0 \tag{1.7} \]
\[ \left \langle 1 \middle | 0 \right \rangle = \big(0 \ \ 1 \big) \begin{pmatrix} 1\\ 0 \end{pmatrix} = 0 \tag{1.8} \]
\[ \left \langle 0 \middle | 0 \right \rangle = \big(1 \ \ 0 \big) \begin{pmatrix} 1\\ 0 \end{pmatrix} = 1 \tag{1.9} \]
\[ \left \langle 1 \middle | 1 \right \rangle = \big(0 \ \ 1 \big) \begin{pmatrix} 0\\ 1 \end{pmatrix} = 1 \tag{1.10} \]
Dari perhitungan di atas terlihat bahwa \( \left \langle 0 \middle | 1 \right \rangle = 0 \) dan \( \left \langle 1 \middle | 0 \right \rangle = 0 \), sehingga ket \(\ket{0}\) dan ket \(\ket{1}\) dikenal memiliki sifat ortogonal. Kedua ket juga memenuhi kaidah ortonormal, yaitu (a) bersifat ortogonal, (b) \( \left \langle 0 \middle | 0 \right \rangle = 1 \), dan (c) \( \left \langle 1 \middle | 1 \right \rangle = 1 \).
Lalu, bagaimanakah jika ket \(\ket{0}\) dikalikan dengan bra \(\bra{0}\). Outer product ini menghasilkan sebuah matriks dan dikenal sebagai matriks densitas \(\rho\).
\[ \ket{0} \bra{0} = \begin{pmatrix} 1\\ 0 \end{pmatrix} \big(1 \ \ 0 \big) = \begin{pmatrix} 1 & 0\\ 0 & 0 \end{pmatrix} \tag{1.11} \]
dan \(\ket{1}\bra{1}\) adalah
\[ \ket{1} \bra{1} = \begin{pmatrix} 0\\ 1 \end{pmatrix} \big(0 \ \ 1 \big) = \begin{pmatrix} 0 & 0\\ 0 & 1 \end{pmatrix} \tag{1.12} \]
Penjumlahan komponen diagonal pada matriks densitas dikenal sebagai trace \(Tr\), sehingga trace untuk \(\ket{0}\bra{0}\) sebesar
\[ Tr(\rho) = 1 + 0 = 1 \tag{1.13} \]
dan trace untuk \(\ket{1}\bra{1}\) senilai
\[ Tr(\rho) = 0 + 1 = 1 \tag{1.14} \]
Nilai trace yang bernilai 1 mencerminkan normalisasi probabilitas. Trace juga menggambarkan keadaan kuantum, apakah ia keadaan murni (pure state) atau keadaan campuran (mixed state). Keadaan murni jika
\[ \rho^2 = \rho, \ Tr(\rho^2) = 1 \tag{1.15} \]
dan keadaan campuran apabila
\[ Tr(\rho^2) < 1 \tag{1.16} \]
Diberikan contoh sebuah sistem kuantum 1-qubit
\[ \ket{\psi_q} = \frac{\sqrt{3}}{2}\ket{0} + \frac{1}{2}\ket{1} \tag{1.17} \]
Bagaimanakah analisis dari vektor di atas? Secara analitis matematis, vektor \((1.17)\) mempunyai nilai \(\alpha = \frac{\sqrt{3}}{2}\) dan \(\beta = \frac{1}{2}\), sehingga \(|\alpha|^2 + |\beta|^2 = \frac{3}{4} + \frac{1}{4} = 1\). Hal ini berarti bahwa probabilitas menemukan \(\ket{\psi_q}\) di keadaan \(\ket{0}\) sebesar \(\frac{3}{4}\) dan probabilitas bernilai \(\frac{1}{4}\) di keadaan \(\ket{1}\).
Guna mendapatkan keadaan kuantum \((1.17)\), maka keadaan \(\ket{0}\) dilakukan rotasi sebesar \(\frac{\pi}{3}\). Dari \((1.1)\) dan \((1.6)\) dapat dijelaskan bahwa nilai \(\alpha\) pada \((1.17)\) yang merupakan \(\cos{\frac{\theta}{2}} = \frac{\sqrt{3}}{2}\) sehingga \(\theta = \frac{\pi}{3}\) dan \(\beta\) representasi dari \(\mathrm{e}^{i \phi} \sin{\frac{\theta}{2}} = \frac{1}{2}\) maka \(\theta = \frac{\pi}{3}\) dengan \(\phi = 0\).
Secara umum, nilai bra \(\bra{\psi}\) dari sebuah keadaan kuantum \(\ket{\psi} = \alpha\ket{0} + \beta\ket{1}\) memiliki persamaan
\[ \bra{\psi} = \alpha^*\bra{0} + \beta^*\bra{1} \tag{1.18} \]
dan untuk matriks densitasnya
\[ \ket{\psi} \bra{\psi} = \begin{pmatrix} \alpha\\ \beta \end{pmatrix} \begin{pmatrix} \alpha^* & \beta^* \end{pmatrix} \tag{1.19} \]
dengan \(\alpha^*\) dan \(\beta^*\) berturut-turut ialah konjugat kompleks dari \(\alpha\) dan \(\beta\). Misal \(\alpha = \frac{1}{\sqrt{2}}\), \(\beta = \frac{i}{\sqrt{2}}\) maka \(\alpha^* = \frac{1}{\sqrt{2}}\), \(\beta^* = \frac{-i}{\sqrt{2}}\).
Selanjutnya, dari contoh \((1.17)\) diperoleh
\[ \bra{\psi_q} = \frac{\sqrt{3}}{2}\bra{0} + \frac{1}{2}\bra{1} \tag{1.20} \]
serta
\[ \ket{\psi_q} \bra{\psi_q} = \begin{pmatrix} \frac{\sqrt{3}}{2}\\ \frac{1}{2} \end{pmatrix} \begin{pmatrix} \frac{\sqrt{3}}{2} & \frac{1}{2} \end{pmatrix} = \begin{pmatrix} \frac{3}{4} & \frac{\sqrt{3}}{4} \\ \frac{\sqrt{3}}{4} & \frac{1}{4} \end{pmatrix} \tag{1.21} \]
Dengan mengecek nilai \(Tr(\rho)\), \(\rho^2\), dan \(Tr(\rho^2)\) pada matriks densitas \((1.21)\) maka dapat diketahui sifat keadaan kuantum \(\ket{\psi_q}\) dari contoh \((1.17)\) yakni apakah ia keadaan murni atau keadaan campuran.
Bab 2: Operator
— Operator, operator Pauli, Hermitian, normal, unitary, gerbang kuantum, gerbang Hadamard.
Operator merupakan sebuah mathematical rule dan pada saat diaplikasikan ke sebuah keadaan \(\ket{\psi}\) maka akan mentransformasikannya menjadi keadaan lain \(\ket{\psi'}\). Operator dalam mekanika kuantum dapat dituliskan sebagai \(A\) sehingga
\[ A \ket{\psi} = \ket{\psi'} \tag{2.1} \]
Dalam komputasi kuantum terdapat sebuah set operator fundamental dan dikenal sebagai operator Pauli. Operator Pauli terdiri atas \(\sigma_0\), \(\sigma_1\), \(\sigma_2\), \(\sigma_3\) atau \(\sigma_0\), \(\sigma_x\), \(\sigma_y\), \(\sigma_z\) atau \(I\), \(X\), \(Y\), \(Z\).
Adapun representasi matriks dari operator Pauli yaitu
\[ I = \begin{pmatrix} 1 & 0\\ 0 & 1 \end{pmatrix} \tag{2.2} \]
\[ X = \begin{pmatrix} 0 & 1\\ 1 & 0 \end{pmatrix} \tag{2.3} \]
\[ Y = \begin{pmatrix} 0 & -i\\ i & 0 \end{pmatrix} \tag{2.4} \]
\[ Z = \begin{pmatrix} 1 & 0\\ 0 & -1 \end{pmatrix} \tag{2.5} \]
Operator juga harus memenuhi kaidah mekanika kuantum, yaitu bersifat Hermitian, normal, dan unitary. Operator dikatakan memiliki sifat Hermitian jika
\[ A = A^\dagger \tag{2.6} \]
dengan \(A^{\dagger}\) adalah transpos konjugat kompleks \(A\). Sebagai contoh adalah operator Pauli \(Y\). Transpos konjugat kompleks \(Y\) adalah
\[ Y^{\dagger} = \begin{pmatrix} 0 & -(i)\\ -(-i) & 0 \end{pmatrix} = \begin{pmatrix} 0 & -i\\ i & 0 \end{pmatrix} \tag{2.7} \]
Dari \((2.4)\) dan \((2.7)\) terlihat bahwa \(Y = Y^{\dagger}\).
Kaidah berikutnya adalah normal dan unitary. Operator disebut normal jika
\[ A A^\dagger = A^\dagger A \tag{2.8} \]
dan bersifat unitary apabila
\[ U U^\dagger = U^\dagger U = I \tag{2.9} \]
Sebagai contoh adalah pada operator Pauli \(Y\) kembali.
\[ Y Y^{\dagger} = \begin{pmatrix} 0 & -i\\ i & 0 \end{pmatrix} \begin{pmatrix} 0 & -i\\ i & 0 \end{pmatrix} = \begin{pmatrix} -i^2 & 0\\ 0 & -i^2 \end{pmatrix} \tag{2.10} \]
\[ Y^{\dagger} Y = \begin{pmatrix} 0 & -i\\ i & 0 \end{pmatrix} \begin{pmatrix} 0 & -i\\ i & 0 \end{pmatrix} = \begin{pmatrix} -i^2 & 0\\ 0 & -i^2 \end{pmatrix} \tag{2.11} \]
\[ Y Y^{\dagger} = Y^{\dagger} Y = \begin{pmatrix} 1 & 0\\ 0 & 1 \end{pmatrix} \tag{2.12} \]
Dari \((2.10)\), \((2.11)\), dan \((2.12)\) terlihat bahwa \(Y Y^\dagger = Y^\dagger Y\) dan \(Y Y^\dagger = Y^\dagger Y = I\).
Telah disebutkan di awal bab bahwa sebuah operator saat diaplikasikan pada sebuah keadaan \(\ket{\psi}\) akan mentransformasikannya menjadi keadaan lain \(\ket{\psi'}\). Sebagai contoh yaitu
\[ X \ket{0} = \ket{1} \tag{2.13} \]
Contoh \((2.13)\) dapat diuraikan dengan perhitungan matriks \((2.3)\) dan \((1.2)\) sehingga
\[ \begin{pmatrix} 0 & 1\\ 1 & 0 \end{pmatrix} \begin{pmatrix} 1\\ 0 \end{pmatrix} = \begin{pmatrix} 0\\ 1 \end{pmatrix} \tag{2.14} \]
Matriks \((2.14)\) tidak bukan merupakan representasi keadaan \(\ket{1}\) seperti pada \((1.3)\). Dari contoh ini, operator Pauli \(X\) dapat disebut sebagai gerbang kuantum (quantum gate) — gerbang \(X\). Pun demikian dengan gerbang \(Y\) dan gerbang \(Z\).
Gerbang kuantum fundamental berikutnya adalah gerbang Hadamard. Gerbang Hadamard memiliki representasi matriks
\[ H = \frac{1}{\sqrt{2}} \begin{pmatrix} 1 & 1\\ 1 & -1 \end{pmatrix} \tag{2.15} \]
Saat gerbang Hadamard dioperasikan pada keadaan kuantum \(\ket{0}\) maka akan mentransformasikannya menjadi keadaan kuantum \(\ket{+}\).
\[ H\ket{0} = \frac{1}{\sqrt{2}} \begin{pmatrix} 1 & 1\\ 1 & -1 \end{pmatrix} \begin{pmatrix} 1\\ 0 \end{pmatrix} = \frac{1}{\sqrt{2}} \begin{pmatrix} 1\\ 1 \end{pmatrix} \tag{2.16} \]
sehingga
\[ H\ket{0} = \frac{1}{\sqrt{2}} \begin{pmatrix} 1\\ 0 \end{pmatrix} + \frac{1}{\sqrt{2}} \begin{pmatrix} 0\\ 1 \end{pmatrix} = \frac{1}{\sqrt{2}} \ket{0} + \frac{1}{\sqrt{2}} \ket{1} = \ket{+} \tag{2.17} \]
Dengan cara perhitungan yang sama, operasi \(H\) pada \(\ket{1}\) akan menghasilkan vektor \(\ket{-}\).
\[ H \ket{0} = \ket{+}, \ H \ket{1} = \ket{-} \tag{2.18} \]
Dua contoh gerbang kuantum yang terakhir yakni gerbang \(S\) dan gerbang \(T\). Gerbang \(S\) dikenal dengan gerbang fase dan gerbang \(T\) sebagai gerbang \(\frac{\pi}{8}\). Adapun bentuk matriksnya yakni
\[ S = \begin{pmatrix} 1 & 0\\ 0 & i \end{pmatrix} \tag{2.19} \]
dan
\[ T = \begin{pmatrix} 1 & 0\\ 0 & e^{i\pi/4} \end{pmatrix} \tag{2.20} \]
Bab 3: Entanglement
— Sistem kuantum 2-qubit, produk tensor, product state, separable, entangled, e-bit, gerbang kuantum terkontrol.
Jika pada dua bab sebelumnya pembahasan dasar-dasar komputasi kuantum pada sistem kuantum 1-qubit, maka pada bab ketiga ini akan disajikan pembahasan pada sistem kuantum 2-qubit. Sistem kuantum 2-qubit melibatkan dua buah qubit, yakni qubit 0 dan qubit 1, yang secara umum qubit 0 ditulis sebagai \(q_0\) dan qubit 1 sebagai \(q_1\).
Sistem kuantum 1-qubit memiliki persamaan \(\ket{\psi} = \alpha \ket{0} + \beta \ket{1}\) seperti pada \((1.1)\), maka sistem kuantum 2-qubit mempunyai persamaan
\[ \ket{\psi} = \alpha \ket{00} + \beta \ket{01} + \gamma \ket{10} + \delta \ket{11} \tag{3.1} \]
dengan \(|\alpha|^2\), \(|\beta|^2\), \(|\gamma|^2\), dan \(|\delta|^2\) berturut-turut adalah probabilitas menemukan keadaan \(\ket{00}\), \(\ket{01}\), \(\ket{10}\), dan \(\ket{11}\), serta memenuhi kaidah \(|\alpha|^2 + |\beta|^2 + |\gamma|^2 + |\delta|^2 = 1\).
Contoh sistem kuantum 2-qubit yaitu keadaan
\[ \ket{\psi_1} = \ket{01} \tag{3.2} \]
Keadaan \(\ket{\psi_1}\) memiliki representasi vektor kolom
\[ \ket{\psi_1} = \begin{pmatrix} 0 \\ 1 \\ 0 \\ 0 \\ \end{pmatrix} \tag{3.3} \]
Keadaan \(\ket{\psi_1}\) juga merupakan hasil produk tensor dari keadaan \(\ket{0}\) dan \(\ket{1}\) atau dapat ditulis sebagai
\[ \ket{\psi_1} = \ket{0} \otimes \ket{1} = \begin{pmatrix} 1\\ 0 \end{pmatrix} \otimes \begin{pmatrix} 0\\ 1 \end{pmatrix} = \begin{pmatrix} 0\\ 1\\ 0\\ 0 \end{pmatrix} \tag{3.4} \]
sehingga
\[ \ket{\psi_1} = 0\ket{00} + 1\ket{01} + 0\ket{10} + 0\ket{11} = \ket{01} \tag{3.5} \]
Contoh sistem kuantum 2-qubit yang kedua adalah
\[ \ket{\psi_2} = \frac{1}{\sqrt{2}} \ket{01} + \frac{1}{\sqrt{2}} \ket{11} \tag{3.6} \]
Keadaan \(\ket{\psi_2}\) ini merupakan produk tensor dari \(\ket{+}\) dan \(\ket{1}\)
\[ \ket{\psi_2} = \ket{+} \otimes \ket{1} = \frac{1}{\sqrt{2}} \begin{pmatrix} 1\\ 1 \end{pmatrix} \otimes \begin{pmatrix} 0\\ 1 \end{pmatrix} \tag{3.7} \]
sehingga
\[ \ket{\psi_2} = \frac{1}{\sqrt{2}} \begin{pmatrix} 0\\ 1\\ 0\\ 1 \end{pmatrix} = \frac{1}{\sqrt{2}} \ket{01} + \frac{1}{\sqrt{2}} \ket{11} \tag{3.8} \]
Kedua contoh keadaan di atas \(\ket{\psi_1}\) dan \(\ket{\psi_2}\) merupakan product state atau bersifat separable. Keadaan kuantum memiliki sifat separable jika memenuhi kaidah
\[ \alpha \delta = \beta \gamma \tag{3.9} \]
Keadaan \(\ket{\psi_1} = \ket{01}\) memiliki nilai \(\alpha = 0\), \(\beta = 1\), \(\gamma = 0\), dan \(\delta = 0\), sehingga \(\alpha \delta = \beta \gamma = 0\). Selanjutnya, \(\ket{\psi_2} = \frac{1}{\sqrt{2}} \ket{01} + \frac{1}{\sqrt{2}} \ket{11}\) memiliki nilai \(\alpha = 0\), \(\beta = \frac{1}{\sqrt{2}}\), \(\gamma = 0\), dan \(\delta = \frac{1}{\sqrt{2}}\), sehingga \(\alpha \delta = \beta \gamma = 0\).
Contoh sistem kuantum 2-qubit ketiga adalah
\[ \ket{\Phi^+} = \frac{1}{\sqrt{2}}\ket{00} + \frac{1}{\sqrt{2}}\ket{11} \tag{3.10} \]
Berbeda dengan dua keadaan kuantum sebelumnya, keadaan kuantum \(\ket{\Phi^+}\) bukan merupakan product state atau tidak bersifat separable. Keadaan kuantum \(\ket{\Phi^+}\) memiliki \(\alpha \delta = \frac{1}{2}\) dan \(\beta \gamma = 0\) sehingga \(\alpha \delta \neq \beta \gamma\). Keadaan kuantum \(\ket{\Phi^+}\) dikenal sebagai entangled state atau e-bit.
Sebelum melangkah ke pembahasan tentang entangled state lebih lanjut, akan dikenalkan terlebih dahulu gerbang kuantum yang baru, yakni gerbang kuantum terkontrol atau controlled-\(U\). Gerbang ini dapat ditulis sebagai gerbang \(CU\) dan memiliki persamaan
\[ CU = \ket{0}\bra{0} \otimes I + \ket{1}\bra{1} \otimes U \tag{3.11} \]
dengan \(U\) adalah operasi unitary. Oleh karenanya, jika akan dibuat gerbang terkontrol lain semisal \(CX\), maka
\[ CX = \ket{0}\bra{0} \otimes I + \ket{1}\bra{1} \otimes X \tag{3.12} \]
yang mana \(X\) ialah gerbang \(X\).
Keadaan kuantum \(\ket{\Phi^+}\) dapat dibentuk dengan memanfaatkan gerbang \(CX\) atau juga dikenal sebagai gerbang \(CNOT\). Gerbang \(CX\) memiliki matriks
\[ CX = \begin{pmatrix} 1 & 0 & 0 & 0\\ 0 & 1 & 0 & 0\\ 0 & 0 & 0 & 1\\ 0 & 0 & 1 & 0 \end{pmatrix} \tag{3.13} \]
Keadaan \(\ket{\Phi^+}\) dapat ditulis sebagai
\[ \ket{\Phi^+} = CX(H\ket{0} \otimes \ket{0}) \tag{3.14*} \]
atau
\[ \ket{\Phi^+} = CX(\ket{+} \otimes \ket{0}) \tag{3.15*} \]
maka representasi matriks dari \(\ket{\Phi^+}\) adalah
\[ \ket{\Phi^+} = \begin{pmatrix} 1 & 0 & 0 & 0\\ 0 & 1 & 0 & 0\\ 0 & 0 & 0 & 1\\ 0 & 0 & 1 & 0 \end{pmatrix} \left( \frac{1}{\sqrt{2}} \begin{pmatrix} 1\\ 1 \\ \end{pmatrix} \otimes \begin{pmatrix} 1\\ 0 \end{pmatrix} \right) = \frac{1}{\sqrt{2}} \begin{pmatrix} 1\\ 0 \\ 0 \\ 1 \end{pmatrix} \tag{3.16*} \]
atau
\[ \ket{\Phi^+} = \frac{1}{\sqrt{2}}\ket{00} + \frac{1}{\sqrt{2}}\ket{11} \tag{3.17} \]
Perhitungan dari persamaan \((3.14^*)\) dapat juga dilakukan dengan cara
\[ \ket{\Phi^+} = CX \big(\frac{1}{\sqrt{2}} (\ket{0} + \ket{1}) \otimes \ket{0} \big) \tag{3.18*} \]
atau
\[ \ket{\Phi^+} = \frac{1}{\sqrt{2}} CX (\ket{00} + \ket{10}) = \frac{1}{\sqrt{2}} (CX \ket{00} + CX \ket{10}) \tag{3.19*} \]
sehingga
\[ \ket{\Phi^+} = \frac{1}{\sqrt{2}} (\ket{00} + \ket{11}) \tag{3.20*} \]
Contoh lain dari entangled state yaitu keadaan \(\ket{\Phi^-}\), keadaan \(\ket{\Psi^+}\), dan keadaan \(\ket{\Psi^-}\).
\[ \ket{\Phi^-} = \frac{1}{\sqrt{2}} (\ket{00} - \ket{11}) \tag{3.21} \]
\[ \ket{\Psi^+} = \frac{1}{\sqrt{2}} (\ket{01} + \ket{10}) \tag{3.22} \]
\[ \ket{\Psi^-} = \frac{1}{\sqrt{2}} (\ket{01} - \ket{10}) \tag{3.23} \]
Keempat keadaan kuantum terakhir di atas dikenal sebagai Bell state atau EPR state.
Bab 4: Pemrograman Kuantum
— Bahasa pemrograman dan SDK Qiskit, Dinfio module quantum, simulator, visualisasi qubit, sirkuit kuantum, statevector, probabilitas, histogram, pengukuran, akses komputer kuantum dengan Qiskit Runtime.
Salah satu pilihan bahasa pemrograman dan SDK kuantum ialah Qiskit. Qiskit merupakan sebuah framework open-source untuk pengembangan aplikasi kuantum. Diciptakan oleh IBM, Qiskit menyediakan tools dan libraries yang diperlukan untuk membuat, menguji, dan menjalankan algoritma kuantum, baik pada simulator maupun pada komputer kuantum riil IBM.
Selain Qiskit, pilihan pemrograman kedua yang dipilih yakni dengan menggunakan Dinfio module quantum.
4.1 Visualisasi Qubit

Qubit dalam komputasi kuantum dapat divisualisasikan dengan menggunakan bola Bloch. Contoh: visualisasi keadaan kuantum \(\ket{10}\). Qubit 0, \(q_0 = \ket{0}\) dan qubit 1, \(q_1 = \ket{1}\).
Code: Qubit Visualisation
# Qubit Visualisation
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector
from qiskit.visualization import plot_bloch_multivector
qc = QuantumCircuit(2)
qc.x(1)
state = Statevector(qc)
plot_bloch_multivector(state)
4.2 Sirkuit Kuantum

Gambar di atas merupakan sirkuit kuantum dari sistem kuantum 2-qubit. Terdapat gerbang Hadamard pada \(q_0\) serta gerbang CX dengan \(q_0\) sebagai kontrol dan \(q_1\) sebagai target. Sirkuit ini tidak bukan merupakan representasi dari entangled state seperti pada \((3.10)\).
Code: Quantum Circuit
# Quantum Circuit
from qiskit import QuantumCircuit
qc = QuantumCircuit(2)
qc.h(0)
qc.cx(0, 1)
qc.draw("mpl", scale = 1.0, style = {"backgroundcolor": "#fff"})
Code: Quantum Circuit (Dinfio)
' Quantum Circuit
import quantum
qc = quantum_circuit(2)
qc.h(0)
qc.cx(0, 1)
qc.draw()
4.3 Statevector
\[ \frac{\sqrt{2}}{2}\ket{00} + \frac{\sqrt{2}}{2}\ket{11} \]
Statevector output "LaTeX" hasil pemrograman keadaan kuantum entangled state \((3.10)\).
Code: Statevector
# Statevector
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector
qc = QuantumCircuit(2)
qc.h(0)
qc.cx(0, 1)
state = Statevector(qc)
state.draw("latex")
Code: Statevector (Dinfio)
' Statevector
import quantum
qc = quantum_circuit(2)
qc.h(0)
qc.cx(0, 1)
qc.print_statevector("latex")
4.4 Probabilitas & Histogram

Probabilitas dan histogram hasil pemrograman untuk entangled state pada \((3.10)\). Hasil simulator menunjukkan probabilitas ket \(\ket{00}\) sebesar 45% dan ket \(\ket{11}\) sebesar 55%.
Code: Probability & Histogram
# Probability & Histogram
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector
from qiskit.visualization import plot_histogram
qc = QuantumCircuit(2)
qc.h(0)
qc.cx(0, 1)
state = Statevector(qc)
counts = state.sample_counts(100)
print(counts)
plot_histogram(counts)
Code: Probability (Dinfio)
' Probability
import quantum
qc = quantum_circuit(2)
qc.h(0)
qc.cx(0, 1)
qc.print_probability()
4.5 Pengukuran

Pengukuran pada qubit \(q_0\) dari keadaan kuantum \(\frac{1}{\sqrt{2}} \big( \ket{00} + \ket{01} \big)\). Hasilnya yakni {'1': 55, '0': 45}.
Code: Measurement
# Measurement
from qiskit import QuantumCircuit
from qiskit.primitives import StatevectorSampler
qc = QuantumCircuit(2, 1)
qc.h(0)
qc.measure(0, 0)
sampler = StatevectorSampler()
job = sampler.run([(qc, None, 100)])
result = job.result()
counts = result[0].data.c.get_counts()
print(counts)
qc.draw("mpl", style = {"backgroundcolor": "#f5f5f5"})
Code: Measurement (Dinfio)
' Measurement
import quantum
qc = quantum_circuit(2, 1)
qc.h(0)
qc.measure(0, 0)
qc.draw()
qc.print_classical_bits()
4.6 Akses Komputer Kuantum
Saat ini, komputer kuantum masih tergolong sangat langka dan umumnya hanya dimiliki serta dikembangkan oleh Big Tech, universitas, dan startup global. Meskipun demikian, terdapat cara untuk mengakses komputer kuantum, yaitu melalui layanan cloud. Salah satu opsi yang tersedia adalah akses ke komputer kuantum IBM melalui Qiskit Runtime.
Berikut adalah contoh kode program untuk menyelesaikan masalah komputasi kuantum dengan memanfaatkan perangkat komputer kuantum melalui fasilitas Qiskit Runtime. Dalam contoh ini, Qiskit Runtime digunakan untuk mengakses dan menjalankan algoritma kuantum secara langsung pada perangkat keras kuantum, memberikan pengalaman praktis dalam pemrograman dan eksekusi komputasi kuantum.
Code: Qiskit IBM Runtime
# Qiskit IBM Runtime
from qiskit import QuantumCircuit
from qiskit_ibm_runtime import QiskitRuntimeService, SamplerV2 as Sampler
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
service = QiskitRuntimeService(channel = "ibm_quantum", token = "your_IBM_account")
qc = QuantumCircuit(2)
qc.h(0)
qc.cx(0, 1)
qc.measure_all()
backend = service.least_busy(operational = True, simulator = False)
pm = generate_preset_pass_manager(backend = backend, optimization_level = 1)
isa_circuit = pm.run(qc)
sampler = Sampler(mode = backend)
sampler.options.default_shots = 100000
job = sampler.run([isa_circuit])
pub_result = job.result()[0]
print(f"Counts for the meas output register: {pub_result.data.meas.get_counts()}")
Bab 5: Algoritma Kuantum
— Transformasi Walsh-Hadamard, transformasi unitary, orakel kuantum, register kuantum, paralelisme kuantum, orakel fase, algoritma Deutsch, transformasi Fourier kuantum, estimasi fase kuantum, vektor eigen, nilai eigen, algoritma Grover.
Bab ini membahas fondasi dan implementasi dari algoritma kuantum, yaitu algoritma yang dijalankan pada simulator ataupun komputer kuantum dengan memanfaatkan sifat-sifat khas sistem kuantum.
5.1 Transformasi Walsh-Hadamard
Transformasi Walsh, atau juga dikenal sebagai transformasi Walsh-Hadamard, merupakan pengembangan atau generalisasi transformasi Hadamard. Sebuah qubit dengan keadaan kuantum \(\ket{0}\) jika diberikan trasformasi Hadamard \(H\) maka keadaan kuantum tersebut akan berubah menjadi keadaan superposisi \(\frac{1}{\sqrt{2}}(\ket{0} + \ket{1})\), sebagaimana telah dibahas seperti pada \((2.15)\), \((2.16)\), dan \((2.17)\). Transformasi Walsh-Hadamard mentransformasi \(n\) qubit, yang semuanya pada keadaan \(\ket{0}\), seluruhnya berubah menjadi keadaan superposisi.
Secara matematis, transformasi Walsh-Hadamard dapat ditulis sebagai
\[ W\ket{0} = \frac{1}{\sqrt{2^n}} \sum_{x=0}^{2^n-1} \ket{x} \tag{5.1.1} \]
Contoh: Implementasi transformasi Walsh-Hadamard untuk \(n=2\), maka
\[ W\ket{0} = \frac{1}{\sqrt{2^2}} \sum_{x=0}^{2^2-1} \ket{x} = \frac{1}{2} \sum_{x=0}^{3} \ket{x} \tag{5.1.2} \]
\[ W\ket{0} = \frac{1}{2} (\ket{0} + \ket{1} + \ket{2} + \ket{3}) \tag{5.1.3} \]
atau
\[ W\ket{0} = \frac{1}{2} (\ket{00} + \ket{01} + \ket{10} + \ket{11}) \tag{5.1.4} \]
Hasil \((5.1.4)\) menunjukkan bahwa semua vektor telah berada pada keadaan superposisi. Adapun contoh kegunaan transformasi Walsh-Hadamard yaitu sebagai tahap inisialisasi dalam implementasi algoritma-algoritma kuantum, semisal algoritma Deutsch dan algoritma Grover.

Code: Walsh-Hadamard Transformation
# Walsh-Hadamard Transformation
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector
n = 2
qc = QuantumCircuit(n)
for i in range(n):
qc.h(i)
state = Statevector(qc)
state.draw("latex")
qc.draw("mpl")
Code: Walsh-Hadamard Transformation (Dinfio)
' Walsh-Hadamard Transformation
import quantum
n = 2
qc = quantum_circuit(n)
for i, 0, n - 1
qc.h(i)
endfor
qc.print_statevector("latex")
qc.draw()
5.2 Transformasi Unitary
Transformasi unitary ialah sebuah operasi kuantum yang mana ia memetakan atau mengkodekan sebuah fungsi \(f\) dalam komputasi kuantum. Operasi kuantum ini lazim dikenal sebagai orakel kuantum atau quantum oracle. Salah satu contoh transformasi unitary disajikan dalam bentuk matematis sebagai berikut
\[ U_f:\ket{x,y} \to \ket{x, y \oplus f(x)} \tag{5.2.1*} \]
Ada dua register kuantum dalam transformasi di atas, yakni \(\ket{x}\) dan \(\ket{y}\). Register \(\ket{x}\) berperan sebagai qubit input, yakni representasi variabel masukan \(x\), dan register \(\ket{y}\) sebagai qubit tambahan atau qubit ancilla, berfungsi untuk menyimpan informasi tentang fungsi \(f\). Adapun notasi \(\oplus\) sendiri ialah operasi XOR.
Kasus ke-1: Register \(\ket{x, y} = \ket{0, 0}\) dan \(f(0) = 0\) maka
\[ U_f \ket{0, 0} = \ket{0, 0 \oplus 0} = \ket{0, 0} \tag{5.2.2*} \]
Kasus ke-2: Register \(\ket{x, y} = \ket{1, 0}\) dan \(f(1) = 1\) maka
\[ U_f \ket{1, 0} = \ket{1, 0 \oplus 1} = \ket{1, 1} \tag{5.2.3*} \]
5.3 Paralelisme Kuantum
Paralelisme kuantum yaitu sebuah konsep dalam komputasi kuantum yang memanfaatkan sifat superposisi untuk melakukan banyak perhitungan sekaligus. Fokusnya adalah pada transformasi kuantum \(U_f\) dan bagaimana ia bekerja dengan superposisi. Berikut ialah contoh perhitungan konsep paralelisme kuantum dengan memperhatikan kembali transformasi unitary seperti pada \((5.2.1^*)\).
Contoh: Nilai keadaan \(\ket{x} = H \ket{0} = \frac{1}{\sqrt{2}} (\ket{0} + \ket{1}) \) dan \(\ket{y} = \ket{0}\) maka
\[ U_f \bigg(\frac{1}{\sqrt{2}} (\ket{0} + \ket{1})\bigg) \ket{0} = \frac{1}{\sqrt{2}} (U_f \ket{00} + U_f \ket{10}) \tag{5.3.1*} \]
atau
\[ \frac{\ket{0, 0 \oplus f(0)} + \ket{1, 0 \oplus f(1)}}{\sqrt{2}} \tag{5.3.2*} \]
Hasil \((5.3.2^*)\) menunjukkan bahwa \(U_f\) dapat menghitung \(f(x)\) untuk semua \(x\) hanya dalam satu langkah.
5.4 Orakel Fase
Orakel fase dalam komputasi kuantum ialah jenis orakel yang digunakan untuk memodifikasi fase dari suatu keadaan kuantum. Secara matematis, orakel fase dapat direpresentasikan sebagai
\[ U_f \ket{x} = (-1)^{f(x)} \ket{x} \tag{5.4.1} \]
Dengan \(f(x)\) adalah fungsi yang mengevaluasi apakah \(x\) sebagai solusinya. Misalnya yaitu \(f(x)=1\) untuk solusi dan \(f(x)=0\) bukan untuk solusi. Jika \(f(x)=1\) maka keadaan \(\ket{x}\) berubah menjadi \(-\ket{x}\) atau ada perubahan fase pada \(\ket{x}\), sedang jika \(f(x)=0\) maka keadaan \(\ket{x}\) tetap.
Contoh: Penerapan orakel fase pada sistem kuantum 2 qubit. Adapun fungsi yang diharapkan yaitu \(U_f\) mengubah fase keadaan \(\ket{01}\), sementara keadaan yang lain yakni \(\ket{00}\), \(\ket{10}\), dan \(\ket{11}\) tetap. Orakel fase ini dapat ditulis sebagai
\[ U_f \ket{01} = -\ket{01} \tag{5.4.2} \]
dan
\[ U_f \ket{00} = \ket{00}, \ U_f \ket{10} = \ket{10}, \ U_f \ket{11} = \ket{11} \tag{5.4.3} \]
Adapun gerbang-gerbang kuantum yang dibutuhkan untuk membuat orakel fase \(U_f\) ini ditunjukkan dalam sirkuit kuantum yakni pada bagian yang diapit oleh dua barrier.

Hasil akhir sistem kuantum 2 qubit yang diharapkan yaitu
\[ \frac{1}{2} \ket{00} - \frac{1}{2} \ket{01} + \frac{1}{2} \ket{10} + \frac{1}{2} \ket{11} \tag{5.4.4} \]
Code: Phase Oracle
# Phase Oracle Uf∣01⟩ = -∣01⟩
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector
qc = QuantumCircuit(2)
qc.h([0, 1])
qc.barrier(0, 1)
qc.x(1)
qc.cz(0, 1)
qc.x(1)
qc.barrier(0, 1)
state = Statevector(qc)
state.draw("latex")
qc.draw("mpl")
Code: Phase Oracle (Dinfio)
' Phase Oracle Uf∣01⟩ = -∣01⟩
import quantum
qc = quantum_circuit(2)
qc.h(0)
qc.h(1)
qc.barrier()
qc.x(1)
qc.cz(0, 1)
qc.x(1)
qc.barrier()
qc.print_statevector("latex")
qc.draw()
5.5 Algoritma Deutsch
Algoritma Deutsch menentukan apakah suatu fungsi biner \(f: \{0, 1\} \to \{0, 1\}\) adalah konstan atau seimbang. Disebut konstan jika \(f(0) = f(1) = 0\) atau \(f(0) = f(1) = 1\). Adapun dinamai seimbang jika \(f(0) = 0, f(1) = 1\) atau \(f(0) = 1, f(1) = 0\). Dalam komputasi klasik, penentuan fungsi biner ini membutuhkan dua langkah eksekusi.
Langkah ke-1: Input = 0 ⇒ \(f(0)\) ⇒ Output = 0.
Langkah ke-2: Input = 1 ⇒ \(f(1)\) ⇒ Output = 0 atau 1.
Jika output pada langkah ke-2 adalah 0, maka fungsi biner bersifat konstan, sebaliknya apabila output pada langkah ke-2 memberi hasil 1, fungsi binernya adalah fungsi seimbang. Jadi untuk mengetahui sifat fungsi biner pada komputasi klasik dibutuhkan dua langkah implementasi. Hal ini akan berbeda jika fungsi biner tersebut dijalankan dengan komputasi kuantum, yaitu dengan hanya membutuhkan satu langkah eksekusi.
Persamaan implementasi algoritma Deutsch yakni
\[ \ket{\psi_{\text{out}}} = (H \otimes I) U_f (H \otimes H) \ket{0} \ket{1} \tag{5.5*} \]

Orakel kuantum \(U_f\) dapat diisi dengan gerbang-gerbang kuantum seperti pada tabel sesuai dengan jenis orakel \(U_f\) yang diinginkan, yakni apakah konstan atau seimbang.
| Sifat | \(f\) | \(U_f\) |
|---|---|---|
| Konstan | \(f(0) = f(1) = 0\) | - |
| Konstan | \(f(0) = f(1) = 1\) | \(X(q_1)\) |
| Seimbang | \(f(0) = 0\), \(f(1) = 1\) | \(CX\) |
| Seimbang | \(f(0) = 1\), \(f(1) = 0\) | \(X(q_0)\), \(CX\) |
Code: Deutsch’s Algorithm
# Deutsch’s Algorithm
from qiskit import QuantumCircuit
from qiskit.primitives import StatevectorSampler
qc = QuantumCircuit(2, 1)
qc.h(0)
qc.x(1)
qc.h(1)
# Uf goes here
qc.h(0)
qc.measure(0, 0)
sampler = StatevectorSampler()
job = sampler.run([(qc, None, 1024)])
result = job.result()
counts = result[0].data.c.get_counts()
print(counts)
qc.draw("mpl")
Code: Deutsch’s Algorithm (Dinfio)
' Deutsch’s Algorithm
import quantum
qc = quantum_circuit(2, 1)
qc.h(0)
qc.x(1)
qc.h(1)
' Uf goes here
qc.h(0)
qc.measure(0, 0)
qc.draw()
qc.print_classical_bits()
5.6 Transformasi Fourier Kuantum
Transformasi Fourier kuantum atau Quantum Fourier Transform (QFT) merupakan operasi linear pada register kuantum \(n\) qubit yang mengubah state dalam basis komputasi \(|0\rangle, |1\rangle, \dots, |2^n-1\rangle\) menjadi basis Fourier. Adapun register kuantum sendiri ialah sekumpulan qubit yang digunakan untuk menyimpan dan memproses informasi dalam komputasi kuantum. Setiap qubit dalam register dapat berada dalam state \(|0\rangle\), \(|1\rangle\), atau kombinasi liniernya \((\alpha|0\rangle + \beta|1\rangle)\). Untuk \(n\) qubit, register kuantum dapat mewakili superposisi dari \(2^n\) state sekaligus.
\[ \ket{\psi_n} = \sum_{i=0}^{2^n-1} a_i \ket{i} \tag{5.6.1} \]
Selanjutnya, secara matematis QFT dapat ditulis sebagai
\[ QFT\ket{\psi} \mapsto \frac{1}{\sqrt{2^n}} \sum_{x=0}^{2^n-1} e^{2\pi i kx / 2^n} \ket{x} \tag{5.6.2} \]
Contoh ke-1: Implementasi QFT pada state \(\ket{0}\). Pada contoh ini, QFT diterapkan pada sistem 1-qubit \(\ket{0}\), maka \(n=1\) dan \(k=0\).
\[ QFT\ket{0} \mapsto \frac{1}{\sqrt{2^1}} \sum_{x=0}^{2^1-1} e^{2\pi i ⋅ 0 ⋅ x / 2^1} \ket{x} \tag{5.6.3} \]
atau
\[ QFT\ket{0} \mapsto \frac{1}{\sqrt{2}} \sum_{x=0}^{1} \ket{x} \tag{5.6.4} \]
Didapat
\[ QFT\ket{0} = \frac{1}{\sqrt{2}} (\ket{0} + \ket{1}) \tag{5.6.5} \]
Hasil \((5.6.5)\) menunjukkan bahwa \(QFT\ket{0}\) adalah sama dengan \(H\ket{0}\) seperti pada \((2.17)\).
Contoh ke-2: Implementasi QFT pada state \(\ket{01}\). Pada contoh kedua ini, state merupakan sistem 2-qubit, sehingga \(n=2\) dan \(k=1\), maka
\[ QFT\ket{01} \mapsto \frac{1}{\sqrt{2^2}} \sum_{x=0}^{2^2-1} e^{2\pi i ⋅ 1 ⋅ x / 2^2} \ket{x} \tag{5.6.6} \]
atau
\[ QFT\ket{01} \mapsto \frac{1}{2} \sum_{x=0}^{3} e^{\pi i ⋅ x / 2} \ket{x} \tag{5.6.7} \]
Diperoleh
\[ QFT\ket{01} = \frac{1}{2} \Big( e^{\pi i ⋅ 0 / 2} \ket{0} + e^{\pi i ⋅ 1 / 2} \ket{1} + e^{\pi i ⋅ 2 / 2} \ket{2} + e^{\pi i ⋅ 3 / 2} \ket{3} \Big) \tag{5.6.8} \]
Ingat bahwa dalam persamaan Euler \(e^{i\theta} = \cos \theta + i \sin \theta\); dan \(\ket{0} = \ket{00}, \ket{1} = \ket{01}, \ket{2} = \ket{10}, \ket{3} = \ket{11}\); maka didapatkan hasil
\[ QFT\ket{01} = \frac{1}{2} \Big( \ket{00} + i\ket{01} - \ket{10} - i\ket{11} \Big) \tag{5.6.9} \]

Code: QFT∣01⟩
# QFT∣01⟩
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector
from math import pi
qc = QuantumCircuit(2)
qc.x(0)
qc.barrier(0, 1)
qc.h(1)
qc.cp(pi/2, 0, 1)
qc.h(0)
qc.swap(0, 1)
state = Statevector(qc)
state.draw("latex")
qc.draw("mpl")
Code: QFT∣01⟩ Using QFTGate
# QFT∣01⟩ Using QFTGate
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector
from qiskit.circuit.library import QFTGate
n = 2
qc = QuantumCircuit(n)
qc.x(0)
qft = QFTGate(n)
qc.append(qft, list(range(n)))
state = Statevector(qc)
state.draw("latex")
qc.draw('mpl')
Code: QFT∣01⟩ Matrix Analysis
# QFT∣01⟩ Matrix Analysis
import numpy as np
i = complex(0, 1)
# Qubit |0>
Psi = np.array([[1],
[0]])
# I Gate
I = np.array([[1, 0],
[0, 1]])
# X Gate
X = np.array([[0, 1],
[1, 0]])
# Hadamard Gate
H = (1 / np.sqrt(2)) * np.array([[1, 1],
[1, -1]])
# Control Phase PI/2
CP = np.array([[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, i]],
dtype=complex)
# SWAP Gate
SWAP = np.array([[1, 0, 0, 0],
[0, 0, 1, 0],
[0, 1, 0, 0],
[0, 0, 0, 1]])
Psi_1 = np.kron((np.dot(H, Psi)), (np.dot(X, Psi)))
Psi_2 = np.dot(CP, Psi_1)
Psi_3 = np.dot((np.kron(I, H)), Psi_2)
Psi_4 = np.dot(SWAP, Psi_3)
print(Psi_4)
Code: QFT∣01⟩ (Dinfio)
' QFT∣01⟩
import quantum
qc = quantum_circuit(2)
qc.x(0)
qc.barrier(0, 1)
qc.h(1)
qc.cp(pi / 2, 0, 1)
qc.h(0)
qc.swap(0, 1)
' qc.qft([0, 1])
qc.print_statevector("latex")
qc.draw()
5.7 Estimasi Fase Kuantum
Selain QFT, estimasi fase kuantum atau Quantum Phase Estimation (QPE) juga merupakan salah satu algoritma fundamental dalam komputasi kuantum yang menjadi dasar bagi algoritma kuantum lainnya. QPE bertujuan untuk menemukan fase \(\theta\) dari ekspresi matematika
\[ U \ket{\psi} = e^{2 \pi i \theta} \ket{\psi} \tag{5.7.1} \]
dengan \(U\), \(\ket{\psi}\), dan \(e^{2 \pi i \theta}\) berturut-turut adalah operasi unitary, vektor eigen, dan nilai eigen. Implementasi QPE terdiri atas empat tahapan, yakni inisialisasi, operasi \(U\) terkontrol, inverse QFT, serta pengukuran.
5.7.1 Estimasi Fase 1-Qubit

Sebagai dasar dan gambaran awal mengenai estimasi fase, berikut disajikan bahasan tentang estimasi fase 1-qubit. Adapun perhitungan dalam notasi bra-ketnya diuraikan tahap demi tahap sebagai berikut.
Kolom ke-1: Inisialisasi. Terdapat gerbang \(H\) pada qubit \(q_0\) (counting qubit) dan gerbang \(X\) pada qubit \(q_1\) (vektor eigen) sehingga
\[ \ket{\psi_1} = (X \ket{0}) \otimes (H \ket{0}) \tag{5.7.2} \]
atau
\[ \ket{\psi_1} = \ket{1} \big(\frac{1}{\sqrt{2}} (\ket{0} + \ket{1})\big) = \frac{1}{\sqrt{2}} \ket{1}\ket{0} + \frac{1}{\sqrt{2}} \ket{1}\ket{1} \tag{5.7.3} \]
Kolom ke-2: Operasi \(U\) terkontrol. Gerbang kuantum \(CU\) diterapkan pada kedua qubit, dengan \(q_0\) berperan sebagai qubit kontrol dan \(q_1\) sebagai qubit target. Perlu diingat kembali bahwa pada komputasi kuantum, gerbang kontrol hanya akan aktif jika qubit kontrol bernilai \(\ket{1}\), sehingga
\[ \ket{\psi_2} = \frac{1}{\sqrt{2}} \ket{1}\ket{0} + \frac{1}{\sqrt{2}} (U\ket{1})\ket{1} \tag{5.7.4} \]
Dari \((5.7.1)\) maka \((5.7.4)\) menjadi
\[ \ket{\psi_2} = \frac{1}{\sqrt{2}} \ket{1}\ket{0} + \frac{1}{\sqrt{2}} (\lambda\ket{1})\ket{1} \tag{5.7.5} \]
dengan \(\lambda = e^{2 \pi i \theta}\). Persamaan \((5.7.5)\) dapat juga ditulis sebagai
\[ \ket{\psi_2} = \ket{1} \otimes \bigg( \frac{1}{\sqrt{2}} \ket{0} + \frac{1}{\sqrt{2}} \lambda\ket{1}\bigg) \tag{5.7.6} \]
Kolom ke-3: Inverse QFT. Pada tahap ini, inverse QFT diaplikasikan pada qubit \(q_0\). Inverse QFT untuk 1 qubit sama dengan gerbang Hadamard, sehingga
\[ \ket{\psi_3} = \ket{1} \otimes \bigg( \frac{1}{\sqrt{2}} H\ket{0} + \frac{1}{\sqrt{2}} \lambda H\ket{1}\bigg) \tag{5.7.7} \]
atau
\[ \ket{\psi_3} = \ket{1} \otimes \bigg( \frac{1}{\sqrt{2}} \big(\frac{1}{\sqrt{2}} (\ket{0} + \ket{1}) \big) + \frac{1}{\sqrt{2}} \lambda \big(\frac{1}{\sqrt{2}} (\ket{0} - \ket{1}) \big) \bigg) \tag{5.7.8} \]
sehingga
\[ \ket{\psi_3} = \ket{1} \otimes \bigg( \frac{1 + \lambda}{2} \ket{0} + \frac{1 - \lambda}{2} \ket{1} \bigg) \tag{5.7.9} \]
Kolom ke-4: Pengukuran. Pengukuran pada \(q_0\) menghasilkan dua buah probabilitas yakni
\[ p_\ket{0} = \bigg|\frac{1 + \lambda}{2} \bigg|^2, \ p_\ket{1} = \bigg|\frac{1 - \lambda}{2} \bigg|^2 \tag{5.7.10} \]
5.7.2 QPE Gerbang \(T\) - Estimasi Fase 1-Qubit
Salah satu contoh sederhana implementasi QPE yakni penggunaan gerbang \(T\) sebagai operator unitary dalam QPE dan ingin diestimasi nilai fase \(\theta\)-nya. Representasi matematis implementasi QPE ini yaitu
\[ T \ket{1} = e^{2 \pi i \theta} \ket{1} \tag{5.7.11} \]
atau
\[ T \ket{1} = \begin{pmatrix} 1 & 0\\ 0 & e^{\frac{i\pi}{4}} \end{pmatrix} \begin{pmatrix} 0\\ 1 \end{pmatrix} = \begin{pmatrix} 0\\ e^{\frac{i\pi}{4}} \end{pmatrix} = e^{\frac{i\pi}{4}} \ket{1} \tag{5.7.12} \]
Dari \((5.7.12)\) maka nilai eigen \(\lambda = e^{\frac{i\pi}{4}}\) dan fase \(\theta\) yang diinginkan sebesar \(\frac{1}{8}\). Selanjutnya, nilai \(\lambda\) dimasukkan ke dalam \((5.7.10)\) hingga didapat probabilitas \(\ket{0} \approx 0.8536\) dan probabilitas \(\ket{1} \approx 0.1464\).

Probabilitas hasil pengukuran sebagai output sirkuit kuantum QPE gerbang \(T\) dengan estimasi fase 1-qubit yakni {'0': 857, '1': 143}. Hasil pengukuran ini mendekati hasil perhitungan di atas. Perlu dicermati bahwa pada estimasi fase 1-qubit atau dikenal juga presisi 1-qubit, hasil '0' memiliki arti \(\frac{0}{2^1} = 0\) dan '1' berarti \(\frac{1}{2^1} = 0.5\). Nilai 0 dan 0.5 ini tidak lain ialah nilai fase \(\theta\) hasil pengukuran. Fase \(\theta = 0\) sebesar 85.7% dan \(\theta = 0.5\) senilai 14.3%. Estimasi fase 1-qubit masih memberi selisih yang besar karena nilai fase \(\theta\) yang diinginkan adalah \(\frac{1}{8}\) atau 0.125.
5.7.3 QPE Gerbang \(T\) - Estimasi Fase 2-Qubit

Berikutnya, implementasi QPE gerbang \(T\) dengan estimasi fase 2-qubit atau presisi 2-qubit. Probabilitas hasil pengukuran pada sirkuit kuantum yakni {'00': 406, '01': 418, '10': 96, '11': 80}. Maksud dari nilai-nilai ini secara berturut-turut ialah \('00' \to \frac{0}{2^2} = 0 \to 40.6\%\); \('01' \to \frac{1}{2^2} = 0.25 \to 41.8\%\); \('10' \to \frac{2}{2^2} = 0.5 \to 9.6\%\); dan \('11' \to \frac{3}{2^2} = 0.75 \to 8.0\%\). Jika diambil dua probabilitas terbesar, maka nilai fase \(\theta = 0\) senilai 40.6% dan fase \(\theta = 0.25\) sebesar 41.8%.
5.7.4 QPE Gerbang \(T\) - Estimasi Fase 3-Qubit

Terakhir, implementasi QPE gerbang \(T\) dengan estimasi fase 3-qubit atau presisi 3-qubit. Adapun probabilitas hasil pengukuran dari sirkuit kuantum yakni {'001': 1000}. Nilai ini berarti \('001' \to \frac{1}{2^3} = \frac{1}{8} = 0.125 \to 100\%\). Probabilitas nilai fase \(\theta = 0.125\) sebesar 100%. Hasil implementasi ini sama dengan nilai fase yang diinginkan yakni \(\theta = 0.125\).
Code: QPE n-Qubit Phase Estimation
# QPE n-Qubit Phase Estimation
from qiskit import QuantumCircuit
from qiskit.primitives import StatevectorSampler
from qiskit.circuit.library import QFT
from math import pi
# n-Qubit
n = 3
qc = QuantumCircuit(n + 1, n)
# Eigenvector
qc.x(n)
# Initialisation
for i in range(n):
qc.h(i)
# Controlled-U
theta = pi / 4
r = 1
for q in range(n):
for i in range(r):
qc.cp(theta, q, n)
r *= 2
# Inverse QFT
qc.append(QFT(n, inverse = True), list(range(n)))
# Measurement
for i in range(n):
qc.measure(i, i)
sampler = StatevectorSampler()
job = sampler.run([(qc, None, 1000)])
result = job.result()
counts = result[0].data.c.get_counts()
print(counts)
qc.draw("mpl")
Code: QPE n-Qubit Phase Estimation (Dinfio)
' QPE n-Qubit Phase Estimation
import quantum
' n-Qubit
n = 3
qc = quantum_circuit(n + 1, n)
' Eigenvector
qc.x(n)
' Initialisation
for i, 0, n - 1
qc.h(i)
endfor
' Controlled-U
theta = pi / 4
r = 1
for q, 0, n - 1
for i, 0, r - 1
qc.cp(theta, q, n)
endfor
r *= 2
endfor
' Inverse QFT
qc.iqft([0, 1, 2])
' Measurement
for i, 0, n - 1
qc.measure(i, i)
endfor
qc.draw()
qc.print_classical_bits()
5.8 Algoritma Grover
Bahasan dan implementasi algoritma kuantum yang terakhir yakni algoritma Grover. Adapun contoh kasus yang dipilih yaitu implementasi algoritma Grover dalam menyelesaikan ekspresi logika sederhana (A XOR B) AND B. Secara praktis, algoritma Grover memiliki empat tahapan, yaitu inisialisasi, orakel kuantum, transformasi difusi, serta pengukuran.
5.8.1 Ekspresi Logika
Ekspresi logika (A XOR B) AND B. Ekspresi ini mempunyai dua variabel A dan B serta dua buah klausa dengan operator XOR dan AND. Tabel kebenaran ekspresi logika (A XOR B) AND B disajikan dalam tabel di bawah. Dari tabel terlihat bahwa ekspresi logika akan bernilai true jika A bernilai 0 dan B bernilai 1.
| A | B | A XOR B | (A XOR B) AND B |
|---|---|---|---|
| 0 | 0 | 0 | 0 |
| 1 | 0 | 1 | 0 |
| 0 | 1 | 1 | 1 |
| 1 | 1 | 0 | 0 |
5.8.2 Inisialisasi

Langkah pertama implementasi algoritma Grover dalam komputasi kuantum adalah inisialisasi. Ekspresi logika (A XOR B) AND B mempunyai dua variabel A dan B sehingga dibutuhkan dua buah qubit sebagai representasi dari variabel-variabel ini. Qubit \(q_0\) untuk variabel A dan qubit \(q_1\) untuk variabel B. Selain itu, dibutuhkan juga qubit \(q_2\). Qubit \(q_0\) dan \(q_1\) ada di keadaan kuantum \(\ket{0}\) dan qubit \(q_2\) berada di keadaan kuantum \(\ket{1}\). Terakhir, gerbang Hadamard diaplikasikan pada setiap qubit.
5.8.3 Orakel Kuantum
Dalam komputasi kuantum, operator XOR dan AND dapat direpresentasikan oleh gerbang CNOT dan gerbang Toffoli. Dengan mengkombinasikan kedua gerbang kuantum ini maka dapat dibuatlah sirkuit kuantum untuk ekspresi logika (A XOR B) AND B. Pada sirkuit kuantum ini dibutuhkan qubit \(q_3\) sebagai qubit ancilla.

Pertama, diasumsikan bahwa \(q_0\) dan \(q_1\), ada pada keadaan kuantum \(\ket{0}\). Pada kolom ke-1 dari sirkuit terdapat gerbang CNOT yang mana \(q_1\) berlaku sebagai kontrol dan \(q_0\) berperan sebagai target. Karena \(q_1 = \ket{0}\) maka \(q_0\) tetap pada keadaan \(\ket{0}\). Pada kolom ke-2 terdapat gerbang Toffoli dengan \(q_0\) dan \(q_1\) sebagai kontrol dan \(q_3\) sebagai target. Pada kolom ke-2 ini, \(q_0 = q_1 = \ket{0}\) sehingga \(q_3\) tetap pada keadaan kuantum \(\ket{0}\).
Kedua, diasumsikan bahwa \(q_0 = \ket{1}\) dan \(q_1 = \ket{0}\). Setelah diaplikasikan pada gerbang CNOT, \(q_1 = \ket{0}\) dan \(q_0 = \ket{1}\). Jika kedua keadaan kuantum ini diaplikasikan pada gerbang Toffoli, maka \(q_3 = \ket{0}\).
Ketiga, diberikan \(q_0 = \ket{0}\) dan \(q_1 = \ket{1}\). Qubit \(q_0\) akan berubah menjadi \(\ket{1}\) setelah diaplikasikan pada gerbang CNOT dengan \(q_1 = \ket{1}\). Kedua keadaan kuantum ini yaitu \(q_0 = q_1 = \ket{1}\) akan memberikan hasil keluaran gerbang Toffoli \(q_3 = \ket{1}\).
Terakhir, qubit \(q_0\) dan \(q_1\) ada pada keadaan kuantum \(\ket{1}\). Setelah melalui gerbang CNOT, \(q_0\) berubah menjadi \(\ket{0}\) dan \(q_1\) tetap pada keadaan \(\ket{1}\). Kedua keadaan kuantum ini menghasilkan qubit \(q_3\) bernilai \(\ket{0}\) pada gerbang Toffoli.

Langkah berikutnya yaitu memodifikasi sirkuit kuantum sehingga didapatkan orakel kuantum untuk ekspresi logika (A XOR B) AND B yaitu dengan menambahkan gerbang Z pada qubit ancilla \(q_3\) dan melakukan pencerminan gerbang CNOT dan Toffoli.
5.8.4 Transformasi Difusi

Jika ingin dilakukan analisis dengan perhitungan matriks pada transformasi difusi, maka digunakan operasi matriks
\[ 2 \ket{0} \bra{0} - I \tag{5.8.1} \]
Karena merupakan sistem kuantum 2-qubit maka ket \(\ket{0}\) menjadi \(\ket{00}\) dan bra \(\bra{0}\) menjadi \(\bra{00}\) sehingga operasi matriks \((5.8.1)\) berubah menjadi
\[ 2 \ket{00} \bra{00} - I_2 \tag{5.8.2} \]
Representasi matriks dari gerbang kuantum \(CZ(Z \otimes Z)\) dari gambar juga dapat dihitung. Kedua perhitungan menghasilkan matriks yang sama yaitu
\[ 2 \ket{00} \bra{00} - I_2 = CZ(Z \otimes Z) = \begin{pmatrix} 1 & 0 & 0 & 0\\ 0 & -1 & 0 & 0\\ 0 & 0 & -1 & 0\\ 0 & 0 & 0 & -1 \end{pmatrix} \tag{5.8.3} \]
5.8.5 Pengukuran

Pengukuran adalah tahapan keempat implementasi algoritma Grover dalam komputasi kuantum. Dalam pengukuran ini, dibutuhkan dua buah register klasik.
5.8.6 Sirkuit Kuantum dan Kode Program Algoritma Grover

Penggabungan sirkuit inisialisasi, orakel kuantum, transformasi difusi, dan pengukuran akan menghasilkan sirkuit kuantum algoritma Grover sebagai solusi dari implementasi ekspresi logika (A XOR B) AND B. Selanjutnya, sirkuit kuantum ini dapat dijalankan di simulator atau di komputer kuantum riil.
Code: Grover's Algorithm
# Grover's Algorithm
# Solving "(A XOR B) AND B" logical expression
from qiskit import QuantumCircuit
from qiskit.primitives import StatevectorSampler
qc = QuantumCircuit(4, 2)
qc.h(0)
qc.h(1)
qc.x(2)
qc.h(2)
qc.barrier()
qc.cx(1, 0)
qc.ccx(0, 1, 3)
qc.z(3)
qc.ccx(0, 1, 3)
qc.cx(1, 0)
qc.barrier()
qc.h(0)
qc.h(1)
qc.z(0)
qc.z(1)
qc.cz(0, 1)
qc.h(0)
qc.h(1)
qc.barrier()
qc.measure(0, 0)
qc.measure(1, 1)
sampler = StatevectorSampler()
job = sampler.run([(qc, None, 1024)])
result = job.result()
counts = result[0].data.c.get_counts()
print(counts)
qc.draw("mpl")
Code: Grover's Algorithm (Dinfio)
' Grover's Algorithm
' Solving "(A XOR B) AND B" logical expression
import quantum
qc = quantum_circuit(4, 2)
qc.h(0)
qc.h(1)
qc.x(2)
qc.h(2)
qc.barrier()
qc.cx(1, 0)
qc.ccx(0, 1, 3)
qc.z(3)
qc.ccx(0, 1, 3)
qc.cx(1, 0)
qc.barrier()
qc.h(0)
qc.h(1)
qc.z(0)
qc.z(1)
qc.cz(0, 1)
qc.h(0)
qc.h(1)
qc.barrier()
qc.measure(0, 0)
qc.measure(1, 1)
qc.draw()
qc.print_classical_bits()
Output kode program, yakni selain gambar sirkuit kuantum, juga didapatkan hasil berupa nilai {'10': 1024}. Maksud dari nilai ini yaitu keadaan kuantum '00', '01', dan '11' bernilai 0, sedangkan '10' bernilai 1 (1024 adalah jumlah shots). Keadaan '10' berarti \(q_1 = 1\) dan \(q_0 = 0\) atau variabel B bernilai 1 serta variabel A bernilai 0. Ini adalah solusi ekspresi logika (A XOR B) AND B dengan menggunakan algoritma Grover.
Bab 6: Informasi Kuantum
— Teleportasi, superdense coding, teorema no-cloning, operasi kuantum, representasi operator-sum, operator Kraus, completely positive, trace-preserving, kanal kuantum, kanal bit flip, kanal fase flip, kanal depolarisasi, operator densitas, peredaman amplitudo, peredaman fase, trace parsial, trace distance, fidelity, entropi, entropi von Neumann, koreksi eror kuantum, kode bit flip 3-qubit.
Tidak seperti sistem klasik, sistem kuantum memungkinkan manipulasi informasi secara unik melalui fenomena seperti superposisi dan entanglement. Hal ini membuka berbagai kemungkinan baru dalam pengolahan dan transmisi informasi yang tidak dapat dicapai oleh sistem klasik.
6.1 Teleportasi

Teleportasi merupakan salah satu fenomena unik dan sering dibahas dalam komputasi kuantum. Teleportasi memungkinkan pemindahan informasi kuantum dari satu tempat ke tempat lain, tanpa memindahkan partikel fisiknya itu sendiri. Proses ini memanfaatkan prinsip mekanika kuantum, seperti entanglement dan superposisi, yang tidak ada dalam mekanika klasik.
Alice memiliki keadaan kuantum \(\alpha \ket{0} + \beta \ket{1}\) pada qubit \(q_0\) dan akan dikirim ke Bob di qubit \(q_2\). Alice dan Bob juga berbagi entangled state. Adapun protokol teleportasi dan analisis perhitungan bra-ketnya dapat disajikan sebagai berikut.
Keadaan \(\alpha \ket{0} + \beta \ket{1}\) pada qubit \(q_0\) dan entangled state qubit \(q_1\), \(q_2\).
\[ \ket{\psi_i} = (\alpha \ket{0} + \beta \ket{1}) \otimes \frac{1}{\sqrt{2}} (\ket{00} + \ket{11}) \tag{6.1.1*} \]
atau
\[ \ket{\psi_i} = \frac{1}{\sqrt{2}} \bigg( \alpha \ket{0} \ket{00} + \alpha \ket{0} \ket{11} + \beta \ket{1} \ket{00} + \beta \ket{1} \ket{11} \bigg) \tag{6.1.2*} \]
Alice menerapkan gerbang \(CX\) pada \(q_0\) dan \(q_1\), dengan qubit \(q_0\) sebagai kontrol dan qubit \(q_1\) sebagai target.
\[ \ket{\psi_{ii}} = \frac{1}{\sqrt{2}} \bigg( \alpha \ket{0} \ket{00} + \alpha \ket{0} \ket{11} + \beta \ket{1} \ket{10} + \beta \ket{1} \ket{01} \bigg) \tag{6.1.3*} \]
Ia juga menggunakan gerbang \(H\) pada qubit \(q_0\).
\[ \begin{multline} \ket{\psi_{iii}} = \frac{1}{\sqrt{2}} \bigg( \alpha (\frac{\ket{0} + \ket{1}}{\sqrt{2}}) \ket{00} + \alpha (\frac{\ket{0} + \ket{1}}{\sqrt{2}}) \ket{11} \\ + \beta (\frac{\ket{0} - \ket{1}}{\sqrt{2}}) \ket{10} + \beta (\frac{\ket{0} - \ket{1}}{\sqrt{2}}) \ket{01} \bigg) \end{multline} \tag{6.1.4*} \]
atau
\[ \begin{multline} \ket{\psi_{iii}} = \frac{1}{2} \bigg( \alpha \Big( \ket{0} \ket{00} + \ket{1} \ket{00} + \ket{0} \ket{11} + \ket{1} \ket{11} \Big) \\ + \beta \Big( \ket{0} \ket{10} - \ket{1} \ket{10} + \ket{0} \ket{01} - \ket{1} \ket{01} \Big) \bigg) \end{multline} \tag{6.1.5*} \]
Bentuk \((6.1.5^*)\) dapat juga ditulis sebagai
\[ \begin{multline} \ket{\psi_{iii}} = \frac{1}{2} \bigg( \ket{00} (\alpha \ket{0} + \beta \ket{1}) + \ket{01} (\alpha \ket{1} + \beta \ket{0}) + \ket{10} (\alpha \ket{0} - \beta \ket{1}) + \ket{11} (\alpha \ket{1} - \beta \ket{0}) \bigg) \end{multline} \tag{6.1.6*} \]
Alice melakukan pengukuran dan mengirim hasil pengukurannya ke Bob. Adapun hasil pengukurannya yaitu apakah bernilai '00', '01', '10', atau '11'.
Bob melakukan operasi koreksi atas 2-bit informasi yang dikirim Alice. Jika '00', Bob tidak melakukan apa-apa. Jika nilainya '01', '10', atau '11', maka Bob menerapkan masing-masing gerbang \(X\), \(Z\), atau \(ZX\).
Pengukuran '00' \(\to (\alpha \ket{0} + \beta \ket{1}) \), tidak perlu operasi koreksi apa-apa.
Pengukuran '01' \(\to (\alpha \ket{1} + \beta \ket{0}) \), perlu operasi koreksi gerbang \(X\).
\[ X (\alpha \ket{1} + \beta \ket{0}) = \alpha X\ket{1} + \beta X\ket{0} = \alpha \ket{0} + \beta \ket{1} \tag{6.1.7*} \]
Pengukuran '10' \(\to (\alpha \ket{0} - \beta \ket{1}) \), perlu operasi koreksi gerbang \(Z\).
\[ Z (\alpha \ket{0} - \beta \ket{1}) = \alpha Z\ket{0} - \beta Z\ket{1} = \alpha \ket{0} + \beta \ket{1} \tag{6.1.8*} \]
Pengukuran '11' \(\to (\alpha \ket{1} - \beta \ket{0}) \), perlu operasi koreksi gerbang \(ZX\).
\[ ZX (\alpha \ket{1} - \beta \ket{0}) = Z (\alpha X\ket{1} - \beta X\ket{0}) = Z (\alpha \ket{0} - \beta \ket{1}) = \alpha Z \ket{0} - \beta Z \ket{1} = \alpha \ket{0} + \beta \ket{1} \tag{6.1.9*} \]
Akhirnya, Bob mendapatkan \(\alpha \ket{0} + \beta \ket{1}\).
Code: Teleportation
# Teleportation
from qiskit import QuantumCircuit
from qiskit_aer import StatevectorSimulator
from qiskit.visualization import plot_bloch_multivector
import numpy as np
theta = np.pi / 3
varphi = 0
qc = QuantumCircuit(3, 2)
qc.u(theta, varphi, 0.0, 0)
qc.barrier()
qc.h(1)
qc.cx(1, 2)
qc.barrier()
qc.cx(0, 1)
qc.h(0)
qc.barrier()
qc.measure(0, 0)
qc.measure(1, 1)
with qc.if_test((0, 1)):
qc.z(2)
with qc.if_test((1, 1)):
qc.x(2)
backend = StatevectorSimulator()
psi = backend.run(qc, shots = 1).result().get_statevector()
plot_bloch_multivector(psi)
qc.draw("mpl")
# Ref.: https://quantum.cloud.ibm.com/learning/en/courses/utility-scale-quantum-computing/teleportation
Code: Teleportation with Bob's Measurement
# Teleportation with Bob's Measurement
from qiskit import QuantumCircuit
from qiskit_aer import AerSimulator
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit_ibm_runtime import Sampler
from qiskit.visualization import plot_histogram
import numpy as np
theta = np.pi / 3
varphi = 0
qc = QuantumCircuit(3, 3)
qc.u(theta, varphi, 0.0, 0)
qc.barrier()
qc.h(1)
qc.cx(1, 2)
qc.barrier()
qc.cx(0, 1)
qc.h(0)
qc.barrier()
qc.measure(0, 0)
qc.measure(1, 1)
with qc.if_test((0, 1)):
qc.z(2)
with qc.if_test((1, 1)):
qc.x(2)
qc.barrier()
qc.u(theta, varphi, 0.0, 2).inverse()
qc.measure(2, 2)
backend = AerSimulator()
pm = generate_preset_pass_manager(backend = backend, optimization_level = 1)
isa_qc = pm.run(qc)
sampler = Sampler(mode = backend)
job = sampler.run([isa_qc], shots = 1024)
result = job.result()
counts = result[0].data.c.get_counts()
print(counts)
plot_histogram(counts)
qc.draw("mpl")
# Ref.: https://quantum.cloud.ibm.com/learning/en/courses/utility-scale-quantum-computing/teleportation
6.2 Superdense Coding
Superdense coding adalah protokol dalam komputasi kuantum yang memungkinkan pengiriman dua bit informasi klasik hanya dengan menggunakan satu qubit, yakni melalui bantuan fenomena entanglement.
Ilustrasi superdense coding dapat diuraikan sebagai berikut. Dua pihak (misalnya, Alice dan Bob) berbagi sepasang qubit yang berada dalam keadaan entangled. Alice mengkodekan dua bit informasi klasik (00, 01, 10, atau 11) dengan melakukan operasi kuantum tertentu pada qubitnya sendiri. Setelah itu, Alice mengirim qubitnya ke Bob, dan Bob merekonstruksi dua bit informasi tersebut lalu mengukur kedua qubit yang ada (miliknya dan yang diterima dari Alice).

Analisis perhitungan bra-ket superdense coding adalah sebagai berikut.
Alice dan Bob berbagi sepasang qubit dalam keadaan entangled:
\[ \ket{\psi_i} = \frac{1}{\sqrt{2}} (\ket{00} + \ket{11}) \tag{6.2.1} \]
Alice mengkodekan dua bit klasik '01'. Ia berarti akan menggunakan gerbang \(X\) untuk proses kode ini.
\[ \ket{\psi_{ii}} = (X \otimes I) \ket{\psi_i} = \frac{1}{\sqrt{2}} (X\ket{00} + X\ket{11}) = \frac{1}{\sqrt{2}} (\ket{10} + \ket{01}) \tag{6.2.2*} \]
Alice mengirimkan qubitnya ke Bob, lalu Bob melakukan proses dekode. Untuk proses ini, Bob menerapkan gerbang \(CX\) lalu \(H\).
\[ \ket{\psi_{iii}} = CX\ket{\psi_{ii}} = CX \bigg( \frac{1}{\sqrt{2}} (\ket{10} + \ket{01}) \bigg) = \frac{1}{\sqrt{2}} (CX\ket{10} + CX\ket{01}) = \frac{1}{\sqrt{2}} (\ket{11} + \ket{01}) \tag{6.2.3*} \]
Lalu
\[ \ket{\psi_{iv}} = (H \otimes I) \ket{\psi_{iii}} = H \bigg( \frac{1}{\sqrt{2}} (\ket{11} + \ket{01}) \bigg) = \frac{1}{\sqrt{2}} (H\ket{11} + H\ket{01}) \tag{6.2.4*} \]
atau
\[ \ket{\psi_{iv}} = \frac{1}{\sqrt{2}} \bigg( \frac{1}{\sqrt{2}}(\ket{0} - \ket{1}) \ket{1} \bigg) + \frac{1}{\sqrt{2}} \bigg( \frac{1}{\sqrt{2}}(\ket{0} + \ket{1}) \ket{1} \bigg) \tag{6.2.5*} \]
diperoleh
\[ \ket{\psi_{iv}} = \frac{1}{2} (\ket{01} - \ket{11}) + \frac{1}{2} (\ket{01} + \ket{11}) = \ket{01} \tag{6.2.6*} \]
Perlu diingat bahwa perhitungan bra-ket di atas dan hasil yang diperoleh adalah dengan menggunakan konvensi big-endian. Hal ini berarti hasil \(\ket{01} \to \ket{q_0q_1}\).
Adapun hasil eksekusi sirkuit kuantum berupa {'10': 1024}. Sirkuit kuantum menggunakan konvensi little-endian, sehingga '10' \(\to \ket{q_1q_0}\).
Selanjutnya, gerbang kuantum \(X\) pada bagian yang diapit oleh barrier sebelah kiri di sirkuit dapat diganti dengan gerbang \(I\), \(Z\), atau \(XZ\) untuk mengirimkan variasi dua bit informasi klasik lainnya.
Code: Superdense Coding
# Superdense Coding
from qiskit import QuantumCircuit
from qiskit_aer.primitives import SamplerV2
qc = QuantumCircuit(2)
qc.h(0)
qc.cx(0, 1)
qc.barrier(0, 1)
qc.x(0)
qc.barrier(0, 1)
qc.cx(0, 1)
qc.h(0)
qc.measure_all()
sampler = SamplerV2()
job = sampler.run([qc])
result = job.result()
counts = result[0].data.meas.get_counts()
print(counts)
qc.draw("mpl")
Code: Superdense Coding (Dinfio)
' Superdense Coding
import quantum
qc = quantum_circuit(2, 2)
qc.h(0)
qc.cx(0, 1)
qc.barrier(0, 1)
qc.x(0)
qc.barrier(0, 1)
qc.cx(0, 1)
qc.h(0)
qc.measure(0, 0)
qc.measure(1, 1)
qc.draw()
qc.print_classical_bits()
6.3 Teorema No-Cloning
Teorema no-cloning menyatakan bahwa tidak mungkin ada operasi kuantum \(U\) yang dapat menduplikasi keadaan kuantum \(\ket{\psi}\) menjadi \(\ket{\psi}\)\(\ket{\psi}\) atau
\[ U\ket{\psi}\ket{0} = \ket{\psi}\ket{\psi} \tag{6.3.1} \]
Anggap \(U\) pada \((6.3.1)\) ada, maka
\[ U\ket{0}\ket{0} = \ket{0}\ket{0} = \ket{00} \tag{6.3.2} \]
dan
\[ U\ket{1}\ket{0} = \ket{1}\ket{1} = \ket{11} \tag{6.3.3} \]
Uji kasus pada keadaan kuantum \(\ket{\phi}\):
\[ \ket{\phi} = \frac{1}{\sqrt{2}}\ket{0} + \frac{1}{\sqrt{2}}\ket{1} \tag{6.3.4} \]
maka
\[ \ket{\phi}\ket{\phi} = (\frac{1}{\sqrt{2}}\ket{0} + \frac{1}{\sqrt{2}}\ket{1}) \otimes (\frac{1}{\sqrt{2}}\ket{0} + \frac{1}{\sqrt{2}}\ket{1}) \tag{6.3.5} \]
atau
\[ \ket{\phi}\ket{\phi} = \frac{1}{2}\ket{00} + \frac{1}{2}\ket{01} + \frac{1}{2}\ket{10} + \frac{1}{2}\ket{11} \tag{6.3.6} \]
Anggap sekali lagi \(U\) pada \((6.3.1)\) ada dan terapkan \(U\) pada \(\ket{\phi}\), maka
\[ U\ket{\phi}\ket{0} = U\big(\frac{1}{\sqrt{2}}\ket{0} + \frac{1}{\sqrt{2}}\ket{1}\big) \ket{0} = \frac{1}{\sqrt{2}}U(\ket{0}\ket{0}) + \frac{1}{\sqrt{2}}U(\ket{1}\ket{0}) \tag{6.3.7} \]
Gunakan \((6.3.2)\) dan \((6.3.3)\), maka \((6.3.7)\) menjadi
\[ U\ket{\phi}\ket{0} = \frac{1}{\sqrt{2}}\ket{00} + \frac{1}{\sqrt{2}}\ket{11} \tag{6.3.8} \]
Hasil \((6.3.8)\) berbeda dengan nilai sebenarnya yang diharapkan, yakni keadaan kuantum \((6.3.6)\).
6.4 Operasi Kuantum
Operasi kuantum dalam teori informasi kuantum merupakan konsep matematis yang menggambarkan bagaimana informasi kuantum berubah karena proses transformasi atau akibat interaksi dengan lingkungan. Operasi kuantum memetakan keadaan kuantum awal yang biasanya direpresentasikan sebagai matriks densitas \(\rho\) ke keadaan kuantum akhir \(\rho'\) atau
\[ \rho' = \Phi (\rho) \tag{6.4.1} \]
dengan \(\Phi\) adalah operasi kuantum.
Salah satu representasi penting dari operasi kuantum adalah melalui representasi operator-sum, yang menyatakan bahwa operasi kuantum \(\Phi\) dapat ditulis sebagai
\[ \Phi (\rho) = \sum_i A_i \rho A_i^\dagger \tag{6.4.2} \]
dimana \(A_i\) adalah operator Kraus dan \(A_i^\dagger\) ialah adjoinnya.
\[ \sum_i A_i A_i^\dagger = I \tag{6.4.3} \]
Representasi ini memiliki sifat completely positive dan trace-preserving. Completely positive yakni ia memetakan matriks densitas ke matriks densitas lain yang tetap positif. Adapun trace-preserving yaitu total probabilitas keadaan kuantum tetap bernilai 1.
6.5 Kanal Kuantum
Kanal kuantum digunakan untuk memodelkan kebisingan (noise) atau efek lain akibat interaksi dengan lingkungan dalam sistem kuantum. Ia digambarkan dalam kerangka representasi operator-sum. Contoh kanal kuantum yaitu kanal bit flip, kanal fase flip, kanal depolarisasi, peredaman amplitudo, dan peredaman fase.
6.5.1 Kanal Bit Flip
Kanal bit flip menggambarkan kemungkinan qubit berpindah dari \(|0\rangle\) ke \(|1\rangle\) atau sebaliknya dengan probabilitas tertentu. Kanal bit flip memiliki dua operator Kraus, yakni
\[ A_0 = \sqrt{p}I, \ A_1 = \sqrt{1-p}X \tag{6.5.1} \]
sehingga
\[ \Phi (\rho) = A_0 \rho A_0 + A_1 \rho A_1 \tag{6.5.2} \]
atau
\[ \Phi (\rho) = p\rho + (1-p)X\rho X \tag{6.5.3} \]
dengan \((1-p)\) adalah probabilitas flip dan \(X\) representasi matriks dari operator Pauli \((2.3)\).
Contoh: Sebuah qubit dengan keadaan kuantum awal \(\ket{0}\). Bagaimanakah keadaan kuantum qubit tersebut setelah melewati kanal bit flip? Misal nilai \((1-p) = 0.1\).
Dari \((1.11)\) dan \((2.3)\) maka
\[ \Phi(\rho) = 0.9 \begin{pmatrix} 1 & 0\\ 0 & 0 \end{pmatrix} + 0.1 \begin{pmatrix} 0 & 1\\ 1 & 0 \end{pmatrix} \begin{pmatrix} 1 & 0\\ 0 & 0 \end{pmatrix} \begin{pmatrix} 0 & 1\\ 1 & 0 \end{pmatrix} \tag{6.5.4} \]
didapat
\[ \Phi(\rho) = \begin{pmatrix} 0.9 & 0\\ 0 & 0.1 \end{pmatrix} \tag{6.5.5} \]
Hasil \((6.5.5)\) menunjukkan bahwa keadaan kuantum qubit setelah melewati kanal kuantum yakni probabilitas tetap di keadaan \(\ket{0}\) sebesar 0.9 dan probabilitas berubah menjadi keadaan \(\ket{1}\) senilai 0.1. Perlu dipastikan juga bahwa kanal kuantum dianggap valid jika trace-preserving matriks densitas akhir bernilai 1, dalam hal ini \(Tr(\rho') = 0.9 + 0.1 = 1\).
Code: Bit Flip Channel
# Bit Flip Channel
from qiskit import QuantumCircuit
from qiskit.quantum_info import Kraus, DensityMatrix
import numpy as np
# Bit flip probability
# (1 - p) = 0.1
p = 0.9
# Pauli operators I & X
I = np.array([[1, 0], [0, 1]])
X = np.array([[0, 1], [1, 0]])
# Kraus operators for bit flip channel
A0 = np.sqrt(p) * I
A1 = np.sqrt(1 - p) * X
# Bit flip channel using Kraus operator
bit_flip_channel = Kraus([A0, A1])
# 1-Qubit quantum state
qc = QuantumCircuit(1)
# Density matrix
state = DensityMatrix.from_instruction(qc)
# Apply bit flip channel to state
output_state = state.evolve(bit_flip_channel)
# Print initial and final density matrices
print("rho:")
print(state.data)
print("\nrho':")
print(output_state.data)
Code: Bit Flip Channel (Dinfio)
' Bit Flip Channel
import quantum
qc = quantum_circuit(1)
' Bit flip probability (1 - p) = 0.1
p = 0.9
' Density matrix of ∣0⟩
rho = qc.density_operator()
' X gate matrix
X = gate_x
' Bit flip channel formula
Phi = p * rho + (1 - p) * X * rho * X
Phi.print()
6.5.2 Kanal Fase Flip
Kanal fase flip ialah jenis kanal kuantum yang memodelkan perubahan fase qubit. Kanal fase flip memiliki dua operator Kraus, yaitu
\[ A_0 = \sqrt{p}I, \ A_1 = \sqrt{1-p}Z \tag{6.5.6} \]
sehingga
\[ \Phi (\rho) = A_0 \rho A_0 + A_1 \rho A_1 \tag{6.5.7} \]
atau
\[ \Phi (\rho) = p\rho + (1-p)Z\rho Z \tag{6.5.8} \]
dengan \((1-p)\) ialah probabilitas fase flip dan \(Z\) representasi matriks operator Pauli \((2.5)\).
Contoh: Sebuah qubit dengan keadaan kuantum awal \(\frac{1}{\sqrt{2}}\ket{0} + \frac{1}{\sqrt{2}}\ket{1}\). Tentukan keadaan kuantum qubit setelah melalui kanal fase flip dengan nilai probabilitas \((1-p) = 0.6\).
Matriks densitas keadaan kuantum awal yakni
\[ \rho = \begin{pmatrix} \frac{1}{\sqrt{2}}\\ \frac{1}{\sqrt{2}} \end{pmatrix} \begin{pmatrix} \frac{1}{\sqrt{2}} & \frac{1}{\sqrt{2}} \end{pmatrix} = \begin{pmatrix} \frac{1}{2} & \frac{1}{2}\\ \frac{1}{2} & \frac{1}{2} \end{pmatrix} \tag{6.5.9} \]
\[ \Phi(\rho) = 0.4 \begin{pmatrix} \frac{1}{2} & \frac{1}{2}\\ \frac{1}{2} & \frac{1}{2} \end{pmatrix} + 0.6 \begin{pmatrix} 1 & 0\\ 0 & -1 \end{pmatrix} \begin{pmatrix} \frac{1}{2} & \frac{1}{2}\\ \frac{1}{2} & \frac{1}{2} \end{pmatrix} \begin{pmatrix} 1 & 0\\ 0 & -1 \end{pmatrix} \tag{6.5.10} \]
diperoleh
\[ \Phi(\rho) = \begin{pmatrix} 0.5 & -0.1\\ -0.1 & 0.5 \end{pmatrix} \tag{6.5.11} \]
Hasil \((6.5.11)\) menunjukkan bahwa elemen diagonal pada matriks densitas keadaan kuantum setelah melalui kanal fase flip adalah tetap yakni (0.5, 0.5), namun elemen off-diagonal berubah ke (-0.1, -0.1).
Code: Phase Flip Channel
# Phase Flip Channel
from qiskit import QuantumCircuit
from qiskit.quantum_info import Kraus, DensityMatrix
import numpy as np
# Phase flip probability
# 1 - p = 0.6
p = 0.4
# Pauli operators I & Z
I = np.array([[1, 0], [0, 1]])
Z = np.array([[1, 0], [0, -1]])
# Kraus operators for phase flip channel
A0 = np.sqrt(p) * I
A1 = np.sqrt(1 - p) * Z
# Phase flip channel using Kraus operators
phase_flip_channel = Kraus([A0, A1])
# 1-Qubit quantum state
qc = QuantumCircuit(1)
qc.h(0)
# Density matrix
state = DensityMatrix.from_instruction(qc)
# Apply phase flip channel to state
output_state = state.evolve(phase_flip_channel)
# Print initial and final density matrices
print("rho:")
print(state.data)
print("\nrho':")
print(output_state.data)
Code: Phase Flip Channel (Dinfio)
' Phase Flip Channel
import quantum
qc = quantum_circuit(1)
' Initial state
qc.h(0)
' Phase flip probability (1 - p) = 0.6
p = 0.4
' Density matrix of H∣0⟩
rho = qc.density_operator()
' Z gate matrix
Z = gate_z
' Phase flip channel formula
Phi = p * rho + (1 - p) * Z * rho * Z
Phi.print()
6.5.3 Kanal Depolarisasi
Kanal depolarisasi adalah kanal kuantum yang, dengan probabilitas tertentu, mengubah suatu keadaan kuantum menjadi keadaan campuran maksimal (completely mixed state).
Kanal depolarisasi mempunyai empat operator Kraus, yakni
\[ A_0 = \sqrt{1-\frac{3p}{4}}I, \ A_1 = \sqrt{\frac{p}{4}}X, \ A_2 = \sqrt{\frac{p}{4}}Y, \ A_3 = \sqrt{\frac{p}{4}}Z \tag{6.5.12} \]
sehingga
\[ \Phi (\rho) = A_0 \rho A_0 + A_1 \rho A_1 + A_2 \rho A_2 + A_3 \rho A_3 \tag{6.5.13} \]
Operator densitas sebuah qubit dapat ditulis sebagai
\[ \rho = \frac{1}{2}(I + r_xX + r_yY + r_zZ) \tag{6.5.14} \]
dengan \(r_x^2 + r_y^2 + r_z^2 = 1\) dan \(r = (r_x, r_y, r_z)\) merupakan vektor Bloch.
Maka
\[ X \rho X = \frac{1}{2}(X^2 + r_xX^2X + r_yXYX + r_zXZX) \tag{6.5.15} \]
atau
\[ X \rho X = \frac{1}{2}(I + r_xX - r_yY - r_zZ) \tag{6.5.16} \]
Dengan cara yang sama, diperoleh
\[ Y \rho Y = \frac{1}{2}(I - r_xX + r_yY - r_zZ) \tag{6.5.17} \]
dan
\[ Z \rho Z = \frac{1}{2}(I - r_xX - r_yY + r_zZ) \tag{6.5.18} \]
\[ \rho + X \rho X + Y \rho Y + Z \rho Z = 2I \tag{6.5.19} \]
atau
\[ X \rho X + Y \rho Y + Z \rho Z = 2I - \rho \tag{6.5.20} \]
Berikutnya, masukkan \((6.5.12)\) ke \((6.5.13)\)
\[ \Phi (\rho) = (1-\frac{3p}{4})\rho + \frac{p}{4} X \rho X + \frac{p}{4} Y \rho Y + \frac{p}{4} Z \rho Z \tag{6.5.21} \]
atau
\[ \Phi (\rho) = (1-\frac{3p}{4})\rho + \frac{p}{4} \bigg( X \rho X + Y \rho Y + Z \rho Z \bigg) \tag{6.5.22} \]
Substitusikan \((6.5.20)\) ke \((6.5.22)\) sehingga
\[ \Phi (\rho) = (1-\frac{3p}{4})\rho + \frac{p}{4} (2I - \rho) \tag{6.5.23} \]
dan akhirnya diperoleh
\[ \Phi(\rho) = (1-p)\rho + p\frac{I}{2} \tag{6.5.24} \]
dengan \(p\) merupakan probabilitas sistem berubah menjadi completely mixed state dan \(I\) adalah matriks identitas seperti pada \((2.2)\).
Contoh: Sebuah qubit dengan keadaan kuantum awal
\[ \ket{\varphi} = \frac{\sqrt{3}}{2}\ket{0} + \frac{1}{2}\ket{1} \tag{6.5.25} \]
Bagaimanakah keadaan kuantum qubit tersebut setelah melewati kanal depolarisasi? Misal nilai \(p = 0.4\).
Dari \((6.5.25)\) maka
\[ \rho = \ket{\varphi} \bra{\varphi} = \begin{pmatrix} \frac{\sqrt{3}}{2}\\ \frac{1}{2} \end{pmatrix} \begin{pmatrix} \frac{\sqrt{3}}{2} & \frac{1}{2} \end{pmatrix} \tag{6.5.26} \]
atau
\[ \rho = \begin{pmatrix} \frac{3}{4} & \frac{\sqrt{3}}{4} \\ \frac{\sqrt{3}}{4} & \frac{1}{4} \end{pmatrix} \tag{6.5.27} \]
nilai \(\sqrt{3} / 4 \approx 0.433\), sehingga
\[ \Phi (\rho) = (1-0.4) \begin{pmatrix} 0.75 & 0.433\\ 0.433 & 0.25 \end{pmatrix} + 0.4 \bigg( \frac{1}{2} \begin{pmatrix} 1 & 0\\ 0 & 1 \end{pmatrix} \bigg) \tag{6.5.28} \]
atau
\[ \Phi (\rho) = \begin{pmatrix} 0.65 & 0.26\\ 0.26 & 0.35 \end{pmatrix} \tag{6.5.29} \]
Elemen diagonal dari \((6.5.29)\) yaitu (0.65, 0.35) menunjukkan bahwa probabilitas telah bergeser mendekati keadaan campuran maksimal (0.5, 0.5), dibandingkan dengan keadaan awal pada \((6.5.27)\) yakni (0.75, 0.25).
Code: Depolarising Channel
# Depolarising Channel
from qiskit import QuantumCircuit
from qiskit.quantum_info import Kraus, DensityMatrix
import numpy as np
# Probability
p = 0.4
# Pauli operators
I = np.array([[1, 0], [0, 1]])
X = np.array([[0, 1], [1, 0]])
Y = np.array([[0, -1j], [1j, 0]])
Z = np.array([[1, 0], [0, -1]])
# Kraus operators for depolarising channel
A0 = np.sqrt(1 - 3 * p / 4) * I
A1 = np.sqrt(p / 4) * X
A2 = np.sqrt(p / 4) * Y
A3 = np.sqrt(p / 4) * Z
# Depolarising channel using Kraus operators
depolarising_channel = Kraus([A0, A1, A2, A3])
# 1-Qubit quantum state
qc = QuantumCircuit(1)
qc.ry(np.pi/3, 0)
# Density matrix
state = DensityMatrix.from_instruction(qc)
# Apply depolarising channel to state
output_state = state.evolve(depolarising_channel)
# Print initial and final density matrices
print("rho:")
print(state.data)
print("\nrho':")
print(output_state.data)
Code: Depolarising Channel (Dinfio)
' Depolarising Channel
import quantum
qc = quantum_circuit(1)
' Initial state
qc.ry(pi / 3, 0)
' Probability p = 0.4
p = 0.4
' Density matrix of Ry∣0⟩
rho = qc.density_operator()
' I gate matrix
I = gate_i
' Depolarising channel formula
Phi = (1 - p) * rho + p * I / 2
Phi.print()
6.5.4 Peredaman Amplitudo
Peredaman amplitudo (amplitude damping) merupakan operasi kuantum yang mendeskripsikan sistem kuantum mengalamai disipasi energi akibat efek berinteraksi dengan lingkungan. Ia menggambarkan proses keadaan kuantum kehilangan energi, misalnya dari keadaan eksitasi \(\ket{1}\) ke keadaan dasar \(\ket{0}\).
Operator Kraus pada peredaman amplitudo yaitu
\[ A_0 = \begin{pmatrix} 1 & 0\\ 0 & \sqrt{1-p} \end{pmatrix}, \ A_1 = \begin{pmatrix} 0 & \sqrt{p}\\ 0 & 0 \end{pmatrix} \tag{6.5.30} \]
dengan \(p\) adalah probabilitas keadaan kuantum kehilangan energi. Kedua operator di atas juga dapat ditulis dalam bentuk basis komputasi, yakni
\[ A_0 = \ket{0} \bra{0} + \sqrt{1-p} \ket{1} \bra{1} , \ A_1 = \sqrt{p} \ket{0} \bra{1} \tag{6.5.31} \]
Contoh: Sebuah qubit dengan keadaan awal \(\ket{\phi} = \ket{1}\). Tentukan keadaan akhir qubit setelah mengalami peredaman amplitudo jika \(p=0.2\).
Nilai operator densitas \(\rho\) yakni
\[ \rho = \ket{\phi} \bra{\phi} = \ket{1} \bra{1} = \begin{pmatrix} 0 & 0\\ 0 & 1 \end{pmatrix} \tag{6.5.32} \]
Dengan \(p=0.2\) maka
\[ A_0 = \begin{pmatrix} 1 & 0\\ 0 & \sqrt{0.8} \end{pmatrix}, \ A_0' = A_0 \tag{6.5.33} \]
dan
\[ A_1 = \begin{pmatrix} 0 & \sqrt{0.2}\\ 0 & 0 \end{pmatrix}, \ A_1' = \begin{pmatrix} 0 & 0\\ \sqrt{0.2} & 0 \end{pmatrix} \tag{6.5.34} \]
sehingga nilai keadaan akhir qubit \(\Phi (\rho) = A_0 \rho A_0' + A_1 \rho A_1' \) yaitu
\[ \Phi \rho = \begin{pmatrix} 1 & 0\\ 0 & \sqrt{0.8} \end{pmatrix} \begin{pmatrix} 0 & 0\\ 0 & 1 \end{pmatrix} \begin{pmatrix} 1 & 0\\ 0 & \sqrt{0.8} \end{pmatrix} + \begin{pmatrix} 0 & \sqrt{0.2}\\ 0 & 0 \end{pmatrix} \begin{pmatrix} 0 & 0\\ 0 & 1 \end{pmatrix} \begin{pmatrix} 0 & 0\\ \sqrt{0.2} & 0 \end{pmatrix} \tag{6.5.35} \]
atau
\[ \Phi \rho = \begin{pmatrix} 0.2 & 0\\ 0 & 0.8 \end{pmatrix} \tag{6.5.36} \]
Hasil \((6.5.36)\) menunjukkan bahwa setelah mengalami peredaman amplitudo, probabilitas keadaan qubit di keadaan \(\ket{1}\) menjadi senilai 0.8.
Code: Amplitude Damping
# Amplitude Damping
from qiskit import QuantumCircuit
from qiskit.quantum_info import Kraus, DensityMatrix
import numpy as np
# Probability
p = 0.2
# Kraus operators for amplitude damping
A0 = np.array([[1, 0], [0, np.sqrt(1 - p)]])
A1 = np.array([[0, np.sqrt(p)], [0, 0]])
# Amplitude damping using Kraus operators
amplitude_damping = Kraus([A0, A1])
# 1-Qubit quantum state
qc = QuantumCircuit(1)
qc.x(0)
# Density matrix
state = DensityMatrix.from_instruction(qc)
# Apply amplitude damping to state
output_state = state.evolve(amplitude_damping)
# Print initial and final density matrices
print("rho:")
print(state.data)
print("\nrho':")
print(output_state.data)
Code: Amplitude Damping (Dinfio)
' Amplitude Damping
import quantum
qc = quantum_circuit(1)
' Initial state
qc.x(0)
' Probability p = 0.2
p = 0.2
' Kraus operators
A0 = matrix([[1, 0], [0, sqrt(1 - p)]])
A0_T = transpose(A0)
A1 = matrix([[0, sqrt(p)], [0, 0]])
A1_T = transpose(A1)
' Density matrix of X∣0⟩
rho = qc.density_operator()
' Amplitude damping formula
Phi = A0 * rho * A0_T + A1 * rho * A1_T
Phi.print()
6.5.5 Peredaman Fase
Peredaman fase (phase damping) adalah proses kuantum yang menggambarkan hilangnya informasi kuantum, yakni informasi tentang fase keadaan kuantum, namun tanpa kehilangan energi.
Peredaman fase memiliki dua operator Kraus, yaitu
\[ A_0 = \begin{pmatrix} 1 & 0\\ 0 & \sqrt{1-p} \end{pmatrix}, \ A_1 = \begin{pmatrix} 0 & 0\\ 0 & \sqrt{p} \end{pmatrix} \tag{6.5.37} \]
Contoh: Sebuah qubit dengan keadaan kuantum awal \(\frac{1}{\sqrt{2}}\ket{0} + \frac{1}{\sqrt{2}}\ket{1}\). Tentukan keadaan kuantum qubit setelah mengalami peredaman fase dengan nilai probabilitas \(p = 0.2\).
Seperti pada \((6.5.9)\), operator densitas \(\rho = \begin{pmatrix} 0.5 & 0.5\\ 0.5 & 0.5 \end{pmatrix}\). Dengan \(p = 0.2\) maka
\[ A_0 = \begin{pmatrix} 1 & 0\\ 0 & \sqrt{0.8} \end{pmatrix}, \ A_0' = A_0 \tag{6.5.38} \]
dan
\[ A_1 = \begin{pmatrix} 0 & 0\\ 0 & \sqrt{0.2} \end{pmatrix}, \ A_1' = A_1 \tag{6.5.39} \]
Nilai keadaan akhir qubit \(\Phi (\rho) = A_0 \rho A_0' + A_1 \rho A_1' \) yakni
\[ \Phi \rho = \begin{pmatrix} 1 & 0\\ 0 & \sqrt{0.8} \end{pmatrix} \begin{pmatrix} 0.5 & 0.5\\ 0.5 & 0.5 \end{pmatrix} \begin{pmatrix} 1 & 0\\ 0 & \sqrt{0.8} \end{pmatrix} + \begin{pmatrix} 0 & 0\\ 0 & \sqrt{0.2} \end{pmatrix} \begin{pmatrix} 0.5 & 0.5\\ 0.5 & 0.5 \end{pmatrix} \begin{pmatrix} 0 & 0\\ 0 & \sqrt{0.2} \end{pmatrix} \tag{6.5.40} \]
atau
\[ \Phi \rho = \begin{pmatrix} 0.5 & 0.447\\ 0.447 & 0.5 \end{pmatrix} \tag{6.5.41} \]
Terlihat pada hasil \((6.5.41)\) bahwa setelah mengalami peredaman fase, elemen off-diagonal berubah menjadi (0.447, 0.447) dari fase awal (0.5, 0.5). Adapun elemen diagonal tetap (0.5, 0.5).
Code: Phase Damping
# Phase Damping
from qiskit import QuantumCircuit
from qiskit.quantum_info import Kraus, DensityMatrix
import numpy as np
# Probability
p = 0.2
# Kraus operators for phase damping
A0 = np.array([[1, 0], [0, np.sqrt(1 - p)]])
A1 = np.array([[0, 0], [0, np.sqrt(p)]])
# Phase damping using Kraus operators
phase_damping = Kraus([A0, A1])
# 1-Qubit quantum state
qc = QuantumCircuit(1)
qc.h(0)
# Density matrix
state = DensityMatrix.from_instruction(qc)
# Apply phase damping to state
output_state = state.evolve(phase_damping)
# Print initial and final density matrices
print("rho:")
print(state.data)
print("\nrho':")
print(output_state.data)
Code: Phase Damping (Dinfio)
' Phase Damping
import quantum
qc = quantum_circuit(1)
' Initial state
qc.h(0)
' Probability p = 0.2
p = 0.2
' Kraus operators
A0 = matrix([[1, 0], [0, sqrt(1 - p)]])
A0_T = transpose(A0)
A1 = matrix([[0, 0], [0, sqrt(p)]])
A1_T = transpose(A1)
' Density matrix of H∣0⟩
rho = qc.density_operator()
' Phase damping formula
Phi = A0 * rho * A0_T + A1 * rho * A1_T
Phi.print()
6.6 Tool Informasi Kuantum
Dalam informasi kuantum, berbagai tool seperti operator densitas, trace, trace parsial, trace distance, dan fidelity memainkan peran dalam analisis sistem kuantum. Operator densitas berfungsi sebagai representasi keadaan kuantum. Trace dan trace parsial memungkinkan analisis sifat kemurnian keadaan serta reduksi ke subsistem, sedangkan trace distance mengukur jarak antara dua keadaan kuantum, dan fidelity menilai tingkat kesamaan antar keadaan.
6.6.1 Operator Densitas
Operator densitas merupakan salah satu tool penting dalam komputasi dan informasi kuantum. Jika pada bab-bab sebelumnya operator densitas bekerja pada sistem kuantum 1-qubit, maka di bagian ini akan disajikan uraian tentangnya untuk n-qubit.

Contoh: Sistem kuantum terdiri atas 2 qubit seperti ditunjukkan pada gambar sirkuit. Akan ditentukan operator densitas dari sistem tersebut.
\[ \ket{\phi} = X \ket{0} \otimes H \ket{0} = \ket{1} \otimes \frac{1}{\sqrt{2}}(\ket{0}+\ket{1}) = \frac{1}{\sqrt{2}}(\ket{10}+\ket{11}) \tag{6.6.1} \]
dan
\[ \bra{\phi} = \frac{1}{\sqrt{2}}(\bra{10}+\bra{11}) \tag{6.6.2} \]
sehingga operator densitasnya
\[ \rho = \ket{\phi} \bra{\phi} = \bigg(\frac{1}{\sqrt{2}}(\ket{10}+\ket{11})\bigg) \bigg(\frac{1}{\sqrt{2}}(\bra{10}+\bra{11})\bigg) \tag{6.6.3} \]
atau
\[ \rho = \frac{1}{2} \big( \ket{10}\bra{10} + \ket{10}\bra{11} + \ket{11}\bra{10} + \ket{11}\bra{11} \big) \tag{6.6.4} \]
Jika ditulis dalam bentuk matriks, maka operator densitasnya adalah
\[ \rho = \frac{1}{2} \begin{pmatrix} 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 \\ 0 & 0 & 1 & 1 \\ 0 & 0 & 1 & 1 \\ \end{pmatrix} \tag{6.6.5} \]
Code: Density Operator
# Density Operator
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector
import numpy as np
qc = QuantumCircuit(2)
qc.h(0)
qc.x(1)
# Quantum state
state = Statevector.from_instruction(qc)
# Density operator
density_matrix = state.to_operator().data
print("\nrho:")
print(density_matrix)
Code: Density Operator (Dinfio)
' Density Operator
import quantum
qc = quantum_circuit(2)
qc.h(0)
qc.x(1)
rho = qc.density_operator()
rho.print()
6.6.2 Trace
Tool berikutnya ialah trace. Uraian ini melanjutkan bahasan sebelumnya yakni operator densitas. Akan dicari trace dari operator densitas pada \((6.6.4)\). Persamaan umum trace untuk n-qubit sistem ialah
\[ Tr(\rho) = \sum_{i=0}^{2^n-1} \bra{i}\rho\ket{i} \tag{6.6.6} \]
dengan \(i\) adalah basis komputasi dari n-qubit sistem kuantum. Misal untuk sistem 2-qubit, maka \(i\) terdiri atas 4 basis komputasi yakni \(\ket{00}\), \(\ket{01}\), \(\ket{10}\), dan \(\ket{11}\).
Perlu diingat bahwa nilai \(\braket{00|00}\), \(\braket{01|01}\), \(\braket{10|10}\), dan \(\braket{11|11}\) adalah 1. Adapun yang lainnya adalah 0. Nilai trace per basis komputasi yakni
\[ \bra{00}\rho\ket{00} = \frac{1}{2}(0 \cdot 0 + 0 \cdot 0 + 0 \cdot 0 + 0 \cdot 0) = 0 \tag{6.6.7} \]
\[ \bra{01}\rho\ket{01} = \frac{1}{2}(0 \cdot 0 + 0 \cdot 0 + 0 \cdot 0 + 0 \cdot 0) = 0 \tag{6.6.8} \]
\[ \bra{10}\rho\ket{10} = \frac{1}{2}(1 \cdot 1 + 1 \cdot 0 + 0 \cdot 1 + 0 \cdot 0) = \frac{1}{2} \tag{6.6.9} \]
\[ \bra{11}\rho\ket{11} = \frac{1}{2}(0 \cdot 0 + 0 \cdot 1 + 1 \cdot 0 + 1 \cdot 1) = \frac{1}{2} \tag{6.6.10} \]
Maka nilai \(Tr(\rho) = \frac{1}{2} + \frac{1}{2} = 1\). Nilai ini adalah sama dengan nilai penjumlahan elemen diagonal pada matriks (\(6.6.5)\).
Code: Trace
# Trace
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector
import numpy as np
qc = QuantumCircuit(2)
qc.h(0)
qc.x(1)
# Quantum state
state = Statevector.from_instruction(qc)
# Density operator
density_matrix = state.to_operator().data
# Trace
trace = np.trace(density_matrix).real
print("\nTr(rho):")
print(trace)
6.6.3 Trace Parsial
Ambil sebuah contoh sistem kuantum, misal sistem AB, yang mana ia terdiri atas subsistem A dan subsistem B. Saat hanya ingin mengetahui keadaan subsistem B, maka subsistem A "dihilangkan" dan hanya menyisakan matriks densitas subsistem B. Dalam komputasi dan informasi kuantum, proses ini dikenal sebagai trace parsial.
Persamaan trace parsial dari kondisi diatas yaitu
\[ \rho_B = Tr_A(\rho_{AB}) \tag{6.6.11} \]

Contoh: Digunakan kembali sirkuit kuantum seperti pada subbab sebelumnya. Dari sirkuit, akan dilakukan trace parsial pada qubit \(q_0\) sehingga didapatkan matriks densitas qubit \(q_1\) atau
\[ \rho_{q_1} = Tr_{q_0}(\rho_{q_1q_0}) \tag{6.6.12} \]
Vektor \(\ket{\phi}\) senilai
\[ \ket{\phi} = X \ket{0} \otimes H \ket{0} = \ket{1} \otimes \frac{1}{\sqrt{2}}(\ket{0}+\ket{1}) = \frac{1}{\sqrt{2}} \ket{1} \otimes (\ket{0}+\ket{1}) \tag{6.6.13} \]
dan
\[ \bra{\phi} = \frac{1}{\sqrt{2}} \bra{1} \otimes (\bra{0}+\bra{1}) \tag{6.6.14} \]
Perlu diingat bahwa
\[ (a \otimes b)(a \otimes b) = aa \otimes bb \tag{6.6.15} \]
dan
\[ (\ket{a} \otimes \ket{b})(\bra{a} \otimes \bra{b}) = \ket{a}\bra{a} \otimes \ket{b}\bra{b} \tag{6.6.16} \]
maka
\[ \rho_{q_1q_0} = \ket{\phi} \bra{\phi} = \frac{1}{2} \ket{1}\bra{1} \otimes (\ket{0}+\ket{1})(\bra{0}+\bra{1}) \tag{6.6.17} \]
atau
\[ \rho_{q_1q_0} = \frac{1}{2} \ket{1}\bra{1} \otimes \big(\ket{0}\bra{0} + \ket{0}\bra{1} + \ket{1}\bra{0} + \ket{1}\bra{1}\big) \tag{6.6.18} \]
Karena trace parsial dilakukan pada qubit \(q_0\) maka basis komputasi untuk trace berupa \(\ket{0}\) dan \(\ket{1}\) serta berlangsung hanya di bagian elemen kanan \(\rho_{q_1q_0}\). Perlu diingat juga bahwa nilai \(\braket{0|0}\) dan \(\braket{1|1}\) adalah 1, adapun yang lainnya ialah 0.
Matriks densitas \(\rho_{q_1}\) dari komponen \(\ket{0}\)
\[ \frac{1}{2} \ket{1}\bra{1} \otimes (1 \cdot 1 + 1 \cdot 0 + 0 \cdot 1 + 0 \cdot 0 ) = \frac{1}{2} \ket{1}\bra{1} \tag{6.6.19} \]
dan komponen \(\ket{1}\)
\[ \frac{1}{2} \ket{1}\bra{1} \otimes (0 \cdot 0 + 0 \cdot 1 + 1 \cdot 0 + 1 \cdot 1 ) = \frac{1}{2} \ket{1}\bra{1} \tag{6.6.20} \]
Maka nilai matriks densitas \(\rho_{q_1}\) adalah \(\frac{1}{2} \ket{1}\bra{1} + \frac{1}{2} \ket{1}\bra{1} = \ket{1}\bra{1}\).
Code: Partial Trace
# Partial Trace
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector, partial_trace
qc = QuantumCircuit(2)
qc.h(0)
qc.x(1)
# Quantum state
state = Statevector.from_instruction(qc)
# Partial trace
reduced_q1 = partial_trace(state, [0])
print(reduced_q1)
6.6.4 Trace Distance
Anggap ada dua keadaan kuantum \(\ket{\psi}\) dan \(\ket{\phi}\), masing-masing memiliki matriks densitas \(\rho\) dan \(\sigma\). Untuk mengukur seberapa beda dua keadaan tersebut, digunakanlah trace distance. Trace distance memiliki persamaan
\[ \delta(\rho, \sigma) = \frac{1}{2}Tr|\rho - \sigma| \tag{6.6.21} \]
dengan \(|\rho - \sigma| = \sqrt{(\rho - \sigma)^\dagger (\rho - \sigma)}\).
Contoh: Dua keadaan kuantum \(\ket{\psi} = \ket{0}\) dan \(\ket{\phi} = H\ket{0}\). Akan ditentukan trace distance dari dua keadaan ini.
Nilai \(\rho = \ket{\psi} \bra{\psi} \) dan \(\sigma = \ket{\phi} \bra{\phi}\) dari kedua keadaan kuantum yakni
\[ \rho = \begin{pmatrix} 1 & 0 \\ 0 & 0 \\ \end{pmatrix}, \ \sigma = \frac{1}{2} \begin{pmatrix} 1 & 1 \\ 1 & 1 \\ \end{pmatrix} \tag{6.6.22} \]
sehingga
\[ \rho - \sigma = \begin{pmatrix} \frac{1}{2} & -\frac{1}{2} \\ -\frac{1}{2} & -\frac{1}{2} \\ \end{pmatrix}, \ (\rho - \sigma)^\dagger = \rho - \sigma \tag{6.6.23} \]
maka
\[ (\rho - \sigma)^\dagger (\rho - \sigma) = \begin{pmatrix} \frac{1}{2} & -\frac{1}{2} \\ -\frac{1}{2} & -\frac{1}{2} \\ \end{pmatrix} \begin{pmatrix} \frac{1}{2} & -\frac{1}{2} \\ -\frac{1}{2} & -\frac{1}{2} \\ \end{pmatrix} = \begin{pmatrix} \frac{1}{2} & 0 \\ 0 & \frac{1}{2} \\ \end{pmatrix} = \frac{1}{2} \begin{pmatrix} 1 & 0 \\ 0 & 1 \\ \end{pmatrix} \tag{6.6.24} \]
dan
\[ |\rho - \sigma| = \sqrt{\frac{1}{2}} \begin{pmatrix} 1 & 0 \\ 0 & 1 \\ \end{pmatrix} = \frac{1}{\sqrt{2}} \begin{pmatrix} 1 & 0 \\ 0 & 1 \\ \end{pmatrix} \tag{6.6.25} \]
Nilai
\[ Tr |\rho - \sigma| = \frac{1}{\sqrt{2}} (1 + 1) = \frac{2}{\sqrt{2}} \tag{6.6.26} \]
Akhirnya
\[ \delta (\rho, \sigma) = \frac{1}{2} \cdot \frac{2}{\sqrt{2}} = \frac{1}{\sqrt{2}} \tag{6.6.27} \]
Code: Trace Distance
# Trace Distance
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector
import numpy as np
# |ψ⟩ = |0⟩
psi = QuantumCircuit(1)
state_psi = Statevector.from_instruction(psi)
# |ϕ⟩ = H|0⟩
phi = QuantumCircuit(1)
phi.h(0)
state_phi = Statevector.from_instruction(phi)
# rho & sigma
rho = state_psi.to_operator()
sigma = state_phi.to_operator()
# rho - sigma
diff = rho.data - sigma.data
# |rho - sigma| = sqrt((rho - sigma)^dagger (rho - sigma))
diff_dagger = np.conjugate(diff.T)
diff_square = np.dot(diff_dagger, diff)
eigenvals = np.linalg.eigvals(diff_square)
sqrt_diff_square = np.sqrt(np.abs(eigenvals))
abs_diff = np.diag(sqrt_diff_square)
# Trace distance
trace_distance = 0.5 * np.trace(np.abs(abs_diff))
print(f"Trace distance: {trace_distance:.4f}")
6.6.5 Fidelity
Selanjutnya, untuk mengukur kesamaan antara dua keadaan kuantum, berapa besar dua keadaan saling mirip, digunakan fidelity.
\[ F (\rho, \sigma) = \Big(Tr \sqrt{\rho^{1/2} \sigma \rho^{1/2}} \Big) ^ 2 \tag{6.6.28} \]
Jika keadaan murni, seperti pada \((1.15)\) maka \(\rho^2 = \rho\) dan \(\sigma^2 = \sigma\) diperoleh
\[ F (\rho, \sigma) = \Big( Tr \sqrt{ (\ket{\psi}\bra{\psi}) (\ket{\phi}\bra{\phi}) (\ket{\psi}\bra{\psi}) } \Big) ^ 2 \tag{6.6.29} \]
Karena \(\braket{\phi|\psi} = \braket{\psi|\phi}^* \) maka
\[ \braket{\psi|\phi} \braket{\phi|\psi} = \braket{\psi|\phi} \braket{\psi|\phi}^* = |\braket{\psi|\phi}|^2 \tag{6.6.30} \]
dan diperoleh
\[ F (\rho, \sigma) = \Big( |\braket{\psi|\phi}| Tr \sqrt{ \ket{\psi}\bra{\psi} } \Big) ^ 2 = |\braket{\psi|\phi}| ^ 2 \tag{6.6.31} \]
Dengan contoh \(\ket{\psi}=\ket{0}\) dan \(\ket{\phi}=H\ket{0}\) maka nilai fidelity kedua keadaan kuantum yakni sebesar \(\frac{1}{2}\).
Code: Fidelity
# Fidelity
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector, state_fidelity
import numpy as np
# |ψ⟩ = |0⟩
psi = QuantumCircuit(1)
state_psi = Statevector.from_instruction(psi)
# |ϕ⟩ = H|0>
phi = QuantumCircuit(1)
phi.h(0)
state_phi = Statevector.from_instruction(phi)
# Fidelity
fidelity = state_fidelity(state_psi, state_phi)
print("Fidelity between |ψ⟩ and |ϕ⟩:", fidelity)
Code: Fidelity (Dinfio)
' Fidelity
import quantum
qc1 = quantum_circuit(1)
qc2 = quantum_circuit(1)
qc1.h(0)
psi = qc1.statevector()
phi = qc2.statevector()
f = fidelity(psi, phi)
writeln(f)
6.7 Entropi
Pada pembahasan sebelumnya, seperti pada estimasi fase kuantum atau pada subbab lainnya, telah disinggung secara sekilas tentang nilai eigen. Di subbab ini, sebelum membahas entropi, akan diulas kembali sajian tentang topik tersebut. Nilai eigen sengaja diulas lagi karena urgensinya dalam perhitungan komputasi dan informasi kuantum, termasuk entropi.
Dalam komputasi dan informasi kuantum, nilai eigen suatu keadaan kuantum dihitung dari matriks densitas keadaan kuantum tersebut. Adapun persamaannya ialah
\[ \text{det}(\rho - \lambda I) = 0 \tag{6.7.1} \]
dengan \(\rho\), \(\lambda\), \(I\) berturut-turut adalah matriks densitas, nilai eigen, dan matriks identitas.
Contoh: Akan dicari nilai eigen dari keadaan kuantum \(\ket{0}\).
Telah diketahui dari sebelumnya, bahwa matriks densitas dari keadaan kuantum \(\ket{0}\) yakni \(\rho = \begin{pmatrix} 1 & 0 \\ 0 & 0 \\ \end{pmatrix}\) dan matriks identitas \(I = \begin{pmatrix} 1 & 0 \\ 0 & 1 \\ \end{pmatrix}\) maka
\[ \rho - \lambda I = \begin{pmatrix} 1 & 0 \\ 0 & 0 \\ \end{pmatrix} - \lambda \begin{pmatrix} 1 & 0 \\ 0 & 1 \\ \end{pmatrix} = \begin{pmatrix} 1 - \lambda & 0 \\ 0 & -\lambda \\ \end{pmatrix} \tag{6.7.2} \]
sehingga nilai determinan
\[ \text{det}(\rho - \lambda I) = (1 - \lambda)(-\lambda) - (0 \cdot 0) = (1 - \lambda)(-\lambda) = 0 \tag{6.7.3} \]
Didapat \(\lambda_1 = 1\) dan \(\lambda_2 = 0\).
Code: Eigenvalue
# Eigenvalue
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector
import numpy as np
# Quantum state
psi = QuantumCircuit(1)
state_psi = Statevector.from_instruction(psi)
# Density matrix
rho = state_psi.to_operator()
# Eigenvalue
eigenvalues = np.linalg.eigvals(rho.data)
print("rho:")
print(rho.data)
print("\neigenvalue:", eigenvalues)
Entropi ialah konsep penting dalam informasi kuantum. Entropi mengukur seberapa banyak ketidakpastian atau variasi informasi yang ada pada sistem kuantum. Dalam informasi kuantum, entropi dapat digambarkan oleh matriks densitas dan dikenal sebagai entropi von Neumann. Adapun persamaannya yakni
\[ S (\rho) = -Tr(\rho \log \rho) \tag{6.7.4} \]
atau dalam bentuk nilai eigen sebagai
\[ S (\rho) = - \sum_i \lambda_i \log \lambda_i \tag{6.7.5} \]
Contoh: Akan dicari entropi dari keadaan kuantum \(\ket{0}\).
Dari sebelumnya, diperoleh nilai eigen dari keadaan kuantum \(\ket{0}\) yakni \(\lambda_1 = 1\) dan \(\lambda_2 = 0\) maka nilai entropinya yaitu
\[ S (\rho) = - (1 \cdot \log 1 + 0 \cdot \log 0) = 0 \tag{6.7.6} \]
Nilai ini didapat dari pendekatan limit suku kedua \(\lim_{x \to 0} x \log x = 0\).
Code: Entropy
# Entropy
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector
import numpy as np
# von Neumann entropy
def von_neumann_entropy(rho):
eigenvalues = np.linalg.eigvals(rho.data)
eigenvalues = eigenvalues[np.abs(eigenvalues) > 1e-10]
entropy = -np.sum(eigenvalues * np.log2(eigenvalues))
return entropy
# Quantum state
psi = QuantumCircuit(1)
state_psi = Statevector.from_instruction(psi)
rho = state_psi.to_operator()
# Entropy
entropy_psi = von_neumann_entropy(rho)
print(f"Entropy: {entropy_psi:.4f}")
6.8 Koreksi Eror Kuantum
Koreksi eror kuantum atau Quantum Error Correction (QEC) adalah teknik dalam komputasi kuantum untuk melindungi informasi kuantum dari eror yang disebabkan oleh kebisingan (noise) atau gangguan lingkungan, seperti dekoherensi dan interaksi dengan lingkungan eksternal. Karena qubit sangat sensitif terhadap gangguan, eror dapat dengan mudah terjadi, sehingga diperlukan metode untuk mendeteksi dan memperbaiki eror tanpa merusak informasi kuantum.
Salah satu contoh teknik QEC ialah kode bit flip 3-qubit. Apa itu kode bit flip 3-qubit dan bagaimana langkah-langkah implementasinya? Berikut adalah uraiannya.
Kode bit flip 3-qubit adalah kode QEC sederhana yang digunakan untuk melindungi informasi kuantum dari eror bit flip (perubahan qubit dari \(\ket{0}\) ke \(\ket{1}\) atau sebaliknya). Kode ini adalah salah satu contoh dasar dalam komputasi kuantum untuk memahami prinsip QEC. Adapun prinsip kode bit flip 3-qubit yakni mengkodekan qubit ke dalam tiga qubit logikal.

Tahapan kode bit flip 3-qubit adalah sebagai berikut. (1) Qubit dengan vektor \(\ket{\psi} = \alpha \ket{0} + \beta \ket{1}\); (2) Enkode \(\ket{\psi}\) menjadi 3-qubit keadaan logikal \(\ket{\psi}_l = \alpha \ket{000} + \beta \ket{111}\); (3) Simulasi eror. Akibat eror, vektor \(\ket{\psi}_l\) berubah; (4) Dua qubit ancila. Dua qubit bantuan untuk tujuan cek paritas; (5) Sirkuit stabilisator pertama. Mengukur paritas antara dua qubit pertama; (6) Sirkuit stabilisator kedua. Mengukur paritas antara dua qubit kedua; (7) Deteksi eror. Pengukuran dua bit sindrom \(c_1c_0\); (8) Koreksi eror. Koreksi berdasarkan bit \(c_1c_0\); (9) Vektor logikal kembali ke semula \(\ket{\psi}_l = \alpha \ket{000} + \beta \ket{111}\); (10) Pengukuran vektor \(\ket{\psi}\).
| \(e\) | \(c_1c_0\) | bit flip | \(c\) |
|---|---|---|---|
| \(I \otimes I \otimes I\) | \(00\) | - | \(I \otimes I \otimes I\) |
| \(I \otimes I \otimes X\) | \(01\) | \(q_0\) | \(I \otimes I \otimes X\) |
| \(I \otimes X \otimes I\) | \(11\) | \(q_1\) | \(I \otimes X \otimes I\) |
| \(X \otimes I \otimes I\) | \(10\) | \(q_2\) | \(X \otimes I \otimes I\) |
Contoh: Saat \(c_1c_0\) bernilai '01' maka kode mendeteksi ada eror bit flip pada qubit \(q_0\). Vektor logikal yang semula \(\ket{\psi}_l = \alpha \ket{000} + \beta \ket{111}\) berubah menjadi \(\ket{\psi}_l = \alpha \ket{001} + \beta \ket{110}\) akibat eror tersebut. Oleh karenanya, perlu dilakukan koreksi pada gerbang \(c\) yakni berupa \(I \otimes I \otimes X\). Koreksi ini mengembalikan vektor logikal kembali ke keadaan kuantum semula \(\ket{\psi}_l = \alpha \ket{000} + \beta \ket{111}\).
Code: Quantum Error Correction 3-Qubit Bit Flip Code
# Quantum Error Correction 3-Qubit Bit Flip Code
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector
from qiskit.primitives import StatevectorSampler
qc = QuantumCircuit(5, 2)
# Psi state goes here
# e.g. qc.h(0)
# Encode logical state
qc.cx(0, 1)
qc.cx(0, 2)
# Bit flip error goes here
# e.g. qc.x(0)
# First stabiliser
qc.cx(0, 3)
qc.cx(1, 3)
# Second stabiliser
qc.cx(1, 4)
qc.cx(2, 4)
# Error detection
qc.measure(3, 0)
qc.measure(4, 1)
# Error correction goes here
# e.g. qc.x(0)
state = Statevector(qc)
sampler = StatevectorSampler()
job = sampler.run([(qc, None, 1000)])
result = job.result()
counts = result[0].data.c.get_counts()
print(counts)
qc.draw("mpl")
# Ref.: https://quantum.cloud.ibm.com/learning/en/courses/foundations-of-quantum-error-correction
https://arxiv.org/abs/2304.08678
Bab 7: Algoritma Kuantum Variasional
— Variational quantum algorithm, Hamiltonian, prinsip variasional, noisy intermediate-scale quantum, nilai ekspektasi, energi dasar, variational quantum eigensolver, ansatz, parameterised quantum circuit, optimasi, iterasi, quantum approximate optimisation algorithm, cost Hamiltonian, mixing Hamiltonian, Max-Cut problem, graf.
Algoritma kuantum variasional atau Variational Quantum Algorithm (VQA) adalah algoritma kuantum yang memanfaatkan prinsip variasional pada mekanika kuantum. Ia memanfaatkan perangkat kuantum skala menengah Noisy Intermediate-Scale Quantum, NISQ. VQA juga dikenal sebagai algoritma hibrida karena menggabungkan komputasi kuantum dan komputasi klasik.
7.1 Hamiltonian dan Prinsip Variasional
Hamiltonian merupakan sebuah konsep dalam mekanika kuantum yang digunakan untuk menggambarkan energi suatu sistem kuantum. Ia dapat juga didefinisikan sebagai operator matematis yang merepresentasikan energi sistem
\[ H \ket{\psi} = E \ket{\psi} \tag{7.1.1} \]
dengan \(H\), \(\ket{\psi}\), \(E\) berturut-turut ialah Hamiltonian, state kuantum, dan energi sistem.
Dalam konteks komputasi kuantum, Hamiltonian direpresentasikan sebagai kombinasi linier dari operator Pauli (seperti \(X\), \(Y\), \(Z\)) atau operator lain yang dapat diimplementasikan pada komputasi kuantum.
Prinsip variasional menyatakan bahwa untuk Hamiltonian \(H\), dan sembarang state kuantum \(\ket{\psi}\), nilai ekspektasi (expectation value) energi adalah selalu lebih besar atau sama dengan energi dasar (ground state energy) \(E_0\). Secara matematis, nilai ekspektasi energi dapat ditulis sebagai
\[ \langle H \rangle = \bra{\psi} H \ket{\psi} \tag{7.1.2} \]
sehingga prinsip variasional berupa\[ \langle H \rangle \ge E_0 \tag{7.1.3} \]
Code: Expectation value ⟨Z⟩
# Expectation Value ⟨Z⟩
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector, SparsePauliOp
import numpy as np
# Create a quantum circuit
qc = QuantumCircuit(1)
qc.x(0) # Apply X gate to flip |0⟩ → |1⟩
# Define the observable: Pauli Z operator on qubit 0
observable = SparsePauliOp(["Z"])
# Simulate the final statevector of the circuit
psi = Statevector.from_instruction(qc) # Result: |ψ⟩ = |1⟩
# Compute the expectation value ⟨ψ|Z|ψ⟩
expectation_value = np.real(psi.expectation_value(observable))
# Print the result
print(f"Final state: {psi}")
print(f"Expectation value ⟨Z⟩ = {expectation_value:.4f}")
Lalu, bagaimanakah prinsip variasional dapat dimanfaatkan dalam komputasi kuantum? VQE dan QAOA adalah contohnya.
7.2 Variational Quantum Eigensolver
Variational Quantum Eigensolver (VQE) adalah contoh dari VQA. VQE digunakan untuk mencari energi dasar atau energi terendah dari Hamiltonian \(H\) dengan meminimalkan nilai ekspektasi energi \(\langle H \rangle\). Dalam implementasinya, VQE memiliki lima langkah, yakni Hamiltonian, ansatz, nilai ekspektasi, optimasi, dan iterasi.
Contoh: VQE akan digunakan untuk menemukan energi terendah dari Hamiltonian sederhana, misalnya Hamiltonian Pauli seperti \(H=Z\), dengan \(Z\) adalah matriks Pauli \(Z\). Energi terendah yang diharapkan yakni bernilai -1 (nilai eigen dari operator \(Z\)).
Code: Eigenvalue of Pauli Z
# Eigenvalue of Pauli Z
from qiskit.quantum_info import SparsePauliOp
import numpy as np
op = SparsePauliOp("Z")
op.to_matrix()
result = np.linalg.eigh(op.to_matrix())
print("Eigenvalues:", result.eigenvalues)
Langkah 1: Hamiltonian. Dari contoh dipilih Hamiltonian \(H=Z\), sehingga nilai ekspektasi energi menjadi
\[ \langle Z \rangle = \bra{\psi} Z \ket{\psi} \tag{7.2.1} \]
Langkah 2: Ansatz. Ansatz adalah sirkuit kuantum parametrik atau Parameterised Quantum Circuit (PQC) yang membentuk state kuantum \(\ket{\psi(\theta)}\), sebuah state kuantum dengan parameter \(\theta\). Misal dipilih state kuantum dengan gerbang \(R_y(\theta)\) pada \(\ket{0}\) maka
\[ \ket{\psi(\theta)} = R_y(\theta) \ket{0} \tag{7.2.2} \]
Dengan
\[ R_y(\theta) = \begin{pmatrix} \cos(\theta / 2) & -\sin(\theta / 2) \\ \sin(\theta / 2) & \cos(\theta / 2) \\ \end{pmatrix} \tag{7.2.3} \]
maka
\[ R_y(\theta) \ket{0} = \begin{pmatrix} \cos(\theta / 2) & -\sin(\theta / 2) \\ \sin(\theta / 2) & \cos(\theta / 2) \\ \end{pmatrix} \begin{pmatrix} 1 \\ 0 \\ \end{pmatrix} = \begin{pmatrix} \cos(\theta / 2) \\ \sin(\theta / 2) \\ \end{pmatrix} \tag{7.2.4} \]
didapat
\[ \ket{\psi(\theta)} = \cos(\theta / 2) \ket{0} + \sin(\theta / 2) \ket{1} \tag{7.2.5} \]
dan
\[ \bra{\psi(\theta)} = \cos(\theta / 2) \bra{0} + \sin(\theta / 2) \bra{1} \tag{7.2.6} \]
Langkah 3: Nilai ekspektasi. Persamaan nilai ekspektasi energi menjadi
\[ \langle Z \rangle = \bra{\psi(\theta)} Z \ket{\psi(\theta)} \tag{7.2.7} \]
atau
\[ \langle Z \rangle = \big(\cos(\theta / 2) \bra{0} + \sin(\theta / 2) \bra{1}\big) Z \big(\cos(\theta / 2) \ket{0} + \sin(\theta / 2) \ket{1}\big) \tag{7.2.8} \]
Dengan \(Z\ket{0}=\ket{0}\) dan \(Z\ket{1}=-\ket{1}\) maka
\[ \langle Z \rangle = \big(\cos(\theta / 2) \bra{0} + \sin(\theta / 2) \bra{1}\big) \big(\cos(\theta / 2) \ket{0} - \sin(\theta / 2) \ket{1}\big) \tag{7.2.9} \]
Menggunakan kaidah ortogonal dan ortonormal seperti pada \(1.7\), \(1.8\), \(1.9\), dan \(1.10\), maka diperoleh
\[ \langle Z \rangle = \cos^2(\theta / 2) - \sin^2(\theta / 2) = \cos(\theta) \tag{7.2.10} \]
Langkah 4: Optimasi. Fungsi \(\cos(\theta) = -1\) saat \(\theta = \pi\), maka nilai energi terendah
\[ \langle Z \rangle = \cos(\pi) = -1 \tag{7.2.11} \]
dan dengan \(\theta = \pi\), maka state kuantum-nya adalah
\[ \ket{\psi(\pi)} = \cos(\pi / 2) \ket{0} + \sin(\pi / 2) \ket{1} = \ket{1} \tag{7.2.12} \]
Langkah 5: Iterasi. Proses di atas diulang secara iteratif. Komputer kuantum menghitung nilai ekspektasi energi dan komputer klasik menyesuaikan \(\theta\) menggunakan algoritma optimasi hingga didapat energi terendah.

Code: VQE of Pauli Z
# VQE of Pauli Z
from qiskit import QuantumCircuit
from qiskit.quantum_info import SparsePauliOp
from qiskit.primitives import StatevectorEstimator
import numpy as np
# Define the Hamiltonian: H = Z
hamiltonian = SparsePauliOp.from_list([("Z", 1.0)])
# Create the ansatz: Ry(theta)|0>
def create_ansatz(theta):
qc = QuantumCircuit(1)
qc.ry(theta, 0)
return qc
# Function to compute the expectation value of energy
def compute_expectation(theta):
circuit = create_ansatz(theta)
estimator = StatevectorEstimator()
job = estimator.run([(circuit, hamiltonian)])
result = job.result()[0].data.evs
return result
# Classical optimisation
theta = 0.01 # Initial theta value (avoid 0 to prevent zero gradient)
learning_rate = 1.0 # Larger learning rate
max_iterations = 100 # Maximum number of iterations
tolerance = 1e-3 # Convergence tolerance
for i in range(max_iterations):
# Compute energy (expectation value)
energy = compute_expectation(theta)
# Compute gradient of cos(theta)
gradient = -np.sin(theta)
# Update theta using gradient descent
theta_new = theta - learning_rate * gradient
# Check for convergence
if abs(energy - (-1.0)) < tolerance:
print(f"Convergence achieved at iteration {i + 1}")
break
theta = theta_new
# Print progress every iteration
if (i + 1) % 1 == 0:
print(f"Iteration {i + 1}: Energy = {energy:.4f}, Theta = {theta:.4f}")
# Final result
final_energy = compute_expectation(theta)
print(f"\nVQE Results:")
print(f"Lowest energy: {final_energy:.4f}")
print(f"Optimal theta parameter: {theta:.4f}")
Code: VQE of Pauli Z Using Numerical Gradient
# VQE of Pauli Z Using Numerical Gradient
from qiskit import QuantumCircuit
from qiskit.quantum_info import SparsePauliOp
from qiskit.primitives import StatevectorEstimator
import numpy as np
# Define the Hamiltonian: H = Z
hamiltonian = SparsePauliOp.from_list([("Z", 1.0)])
# Create the ansatz: Ry(theta)|0>
def create_ansatz(theta):
qc = QuantumCircuit(1)
qc.ry(theta, 0)
return qc
# Function to compute the expectation value of energy
def compute_expectation(theta):
circuit = create_ansatz(theta)
estimator = StatevectorEstimator()
job = estimator.run([(circuit, hamiltonian)])
result = job.result()[0].data.evs
return result
# Function to compute the numerical gradient using finite difference
def compute_numerical_gradient(theta, epsilon):
# Compute expectation values at theta + epsilon and theta - epsilon
energy_plus = compute_expectation(theta + epsilon)
energy_minus = compute_expectation(theta - epsilon)
# Approximate gradient: (f(theta + epsilon) - f(theta - epsilon)) / (2 * epsilon)
gradient = (energy_plus - energy_minus) / (2 * epsilon)
return gradient
# Classical optimisation using gradient descent
theta = 0.01 # Initial theta value (avoid 0 to prevent slow convergence)
learning_rate = 1 # Learning rate
max_iterations = 100 # Maximum number of iterations
tolerance = 1e-3 # Convergence tolerance
epsilon = 0.01 # Small perturbation for finite difference
for i in range(max_iterations):
# Compute energy (expectation value)
energy = compute_expectation(theta)
# Compute numerical gradient
gradient = compute_numerical_gradient(theta, epsilon)
# Update theta using gradient descent
theta_new = theta - learning_rate * gradient
# Check for convergence
if abs(energy - (-1.0)) < tolerance:
print(f"Convergence achieved at iteration {i + 1}")
break
theta = theta_new
# Print progress every iteration
if (i + 1) % 1 == 0:
print(f"Iteration {i + 1}: Energy = {energy:.4f}, Theta = {theta:.4f}")
# Final result
final_energy = compute_expectation(theta)
print(f"\nVQE Results:")
print(f"Lowest energy: {final_energy:.4f}")
print(f"Optimal theta parameter: {theta:.4f}")
7.3 Quantum Approximate Optimisation Algorithm
Quantum Approximate Optimisation Algorithm (QAOA) ialah algoritma kuantum yang digunakan untuk menyelesaikan masalah optimasi secara aproksimasi. QAOA menggabungkan komputasi kuantum dan klasik, serta memiliki dua Hamiltonian, yakni cost Hamiltonian dan mixing Hamiltonian.
Contoh: QAOA akan diterapkan pada Max-Cut problem dengan graf sederhana. Graf sederhana berbentuk segitiga (tiga simpul dan tiga sisi).

Langkah 1: Graf. Simpul {\(A, B, C\)}. Sisi {\((A, B), (B, C), (C, A)\)}.
Langkah 2: Cost Hamiltonian \(H_C\). \(H_C\) didesain untuk mendapatkan energi rendah pada partisi yang memotong banyak sisi.
\[ H_C = \frac{1}{2} \sum_{(i,j) \epsilon E} (1 - Z_i Z_j) \tag{7.3.1} \]
dimana \(Z_i\) adalah operator Pauli \(Z\) pada qubit ke-\(i\) dan \(E\) himpunan sisi graf. Pada graf segitiga, nilai \(H_C\) menjadi
\[ H_C = \frac{1}{2} \big( (1 - Z_A Z_B) + (1 - Z_B Z_C) + (1 - Z_C Z_A)\big) \tag{7.3.2} \]
Langkah 3: Mixing Hamiltonian \(H_M\). Persamaan \(H_M\) yakni
\[ H_M = \sum_i X_i \tag{7.3.3} \]
dengan \(X_i\) ialah operator Pauli \(X\) pada qubit ke-\(i\).
Langkah 4: Sirkuit kuantum QAOA. Pertama, superposisi 3 qubit. Lalu gerbang unitary untuk cost Hamiltonian dengan parameter \(\gamma\)
\[ U(H_C, \gamma) = \exp(-i \gamma H_C) \tag{7.3.4} \]
Gerbang ini berupa \(\exp(-i \gamma (\frac{1 - Z_iZ_j}{2}))\) untuk di setiap sisi \((i, j)\). Berikutnya, gerbang unitary dengan parameter \(\beta\) untuk mixing Hamiltonian
\[ U(H_M, \beta) = \exp(-i \beta H_M) \tag{7.3.5} \]
Saat implementasi, kedua gerbang unitary tersebut berupa \(CX_{i \to j} (I \otimes R_{z_j}) CX_{i \to j}\) dan \(R_{x_j}\).
Langkah 5: Optimasi dan iterasi. Iterasi \(\gamma\) dan \(\beta\) hingga didapatkan nilai ekspektasi jumlah sisi yang dipotong maksimal.
Contoh perhitungan notasi bra-ket nilai ekspektasi. Dipilih partisi dengan \(A=1\), \(B=0\), dan \(C=1\). Partisi ini diwakili oleh state kuantum \(\ket{101}\). Perlu diingat kembali bahwa \(Z\ket{0}=0\) dan \(Z\ket{1}=-1\). Nilai ekspektasi untuk sisi (\(A,B)\), sisi (\(B,C)\), dan sisi (\(C,A)\) berturut-turut adalah
\[ \begin{aligned} \langle H_{(A,B)} \rangle &= \bra{101} \frac{1}{2}(1 - Z_A Z_B) \ket{101} \\ &= \frac{1}{2} \bra{101} I \ket{101} - \frac{1}{2} \bra{101} Z_A Z_B \ket{101} \\ &= \frac{1}{2} \cdot 1 - \frac{1}{2} \bra{101} (Z_A \ket{1} \otimes Z_B \ket{0} \otimes \ket{1} ) \\ &= \frac{1}{2} - \frac{1}{2} \bra{101} (- \ket{1} \otimes \ket{0} \otimes \ket{1} ) \\ &= \frac{1}{2} - \frac{1}{2} \bra{101} (-\ket{101}) \\ &= \frac{1}{2} + \frac{1}{2} \braket{101|101} \\ &= \frac{1}{2} + \frac{1}{2} \cdot 1\\ &= 1 \end{aligned} \tag{7.3.6} \]
\[ \begin{aligned} \langle H_{(B,C)} \rangle &= \bra{101} \frac{1}{2}(1 - Z_B Z_C) \ket{101} \\ &= \frac{1}{2} \bra{101} I \ket{101} - \frac{1}{2} \bra{101} Z_B Z_C \ket{101} \\ &= \frac{1}{2} \cdot 1 - \frac{1}{2} \bra{101} (\ket{1} \otimes Z_B \ket{0} \otimes Z_C \ket{1} ) \\ &= \frac{1}{2} - \frac{1}{2} \bra{101} (\ket{1} \otimes \ket{0} \otimes -\ket{1} ) \\ &= \frac{1}{2} - \frac{1}{2} \bra{101} (-\ket{101}) \\ &= \frac{1}{2} + \frac{1}{2} \braket{101|101} \\ &= \frac{1}{2} + \frac{1}{2} \cdot 1\\ &= 1 \end{aligned} \tag{7.3.7} \]
\[ \begin{aligned} \langle H_{(C,A)} \rangle &= \bra{101} \frac{1}{2}(1 - Z_C Z_A) \ket{101} \\ &= \frac{1}{2} \bra{101} I \ket{101} - \frac{1}{2} \bra{101} Z_C Z_A \ket{101} \\ &= \frac{1}{2} \cdot 1 - \frac{1}{2} \bra{101} (Z_A \ket{1} \otimes \ket{0} \otimes Z_C \ket{1} ) \\ &= \frac{1}{2} - \frac{1}{2} \bra{101} (-\ket{1} \otimes \ket{0} \otimes -\ket{1} ) \\ &= \frac{1}{2} - \frac{1}{2} \bra{101} (\ket{101}) \\ &= \frac{1}{2} - \frac{1}{2} \braket{101|101} \\ &= \frac{1}{2} - \frac{1}{2} \cdot 1\\ &= 0 \end{aligned} \tag{7.3.8} \]
Jadi nilai ekspektasi total yaitu 1 + 1 + 0 = 2. Nilai ekspektasi 2 menunjukkan bahwa state kuantum \(\ket{101}\) memotong 2 sisi, yakni sisi (\(A,B)\) dan sisi (\(B,C)\). Nilai ini adalah nilai optimal Max-Cut untuk graf segitiga.
Code: QAOA for Max-Cut on a Triangle Graph
# QAOA for Max-Cut on a Triangle Graph
from qiskit import QuantumCircuit, QuantumRegister
from qiskit.quantum_info import Statevector, Operator
import numpy as np
from scipy.optimize import minimize
# Define the graph and problem Hamiltonian
edges = [(0, 1), (1, 2), (2, 0)]
num_qubits = 3
# Function to create Z_i Z_j operator for edge (i, j)
def zizj_operator(i, j, num_qubits):
# Identity and Pauli-Z matrices
I = np.eye(2)
Z = np.array([[1, 0], [0, -1]])
# Initialise operator as identity for all qubits
op = 1
for k in range(num_qubits):
if k == i or k == j:
op = np.kron(op, Z)
else:
op = np.kron(op, I)
return op
# Problem Hamiltonian: H_C = sum_{(i,j)} 0.5 * (I - Z_i Z_j)
H_C = np.zeros((2 ** num_qubits, 2 ** num_qubits))
for i, j in edges:
H_C += 0.5 * (np.eye(2 ** num_qubits) - zizj_operator(i, j, num_qubits))
# Function to create QAOA circuit
def create_qaoa_circuit(gamma, beta):
# Initialise circuit with 3 qubits
qr = QuantumRegister(num_qubits, 'q')
qc = QuantumCircuit(qr)
# Initialise superposition state |+>^3
for i in range(num_qubits):
qc.h(i)
# Cost operator: U(H_C, gamma) = exp(-i * gamma * H_C)
for i, j in edges:
# Apply e^(-i * gamma * 0.5 * (I - Z_i Z_j)) = e^(-i * gamma/2) * e^(i * gamma/2 * Z_i Z_j)
# Constant factor e^(-i * gamma/2) is ignored as it does not affect measurements
qc.cx(i, j)
qc.rz(gamma, j)
qc.cx(i, j)
# Mixing operator: U(H_M, beta) = exp(-i * beta * sum(X_i))
for i in range(num_qubits):
qc.rx(2 * beta, i) # exp(-i * beta * X) = Rx(2 * beta)
return qc
# Function to compute expectation value
def compute_expectation(params):
gamma, beta = params
# Create QAOA circuit
qc = create_qaoa_circuit(gamma, beta)
# Simulate state using StatevectorSimulator
state = Statevector.from_instruction(qc)
# Compute expectation value:
expectation = state.expectation_value(Operator(H_C)).real
# Return negative for minimisation to maximise the number of cut edges
return -expectation
# Optimise gamma and beta parameters
# Use scipy.optimize.minimize to find optimal parameters
initial_params = [0.5, 0.5] # Initial values for gamma and beta
result = minimize(compute_expectation, initial_params, method='COBYLA')
# Print results
optimal_params = result.x
optimal_value = -result.fun # Optimal expectation value (negated due to minimisation)
print(f"Optimal parameters: gamma = {optimal_params[0]:.4f}, beta = {optimal_params[1]:.4f}")
print(f"Optimal expectation value: {optimal_value:.4f}")
# Simulate final state to see probabilities
qc_optimal = create_qaoa_circuit(optimal_params[0], optimal_params[1])
state_optimal = Statevector.from_instruction(qc_optimal)
probabilities = state_optimal.probabilities_dict()
# Print state probabilities
print("\nState probabilities:")
for state, prob in probabilities.items():
print(f"State |{state}> : {prob:.4f}")
Bab 8: Pembelajaran Mesin Kuantum
— Quantum machine learning, model kuantum, trainable, optimisable, expressivity, trainability, peta fitur kuantum, vektor fitur, ruang fitur kuantum, enkode basis, enkode amplitudo, enkode sudut, enkode fase, enkode sudut padat, kernel kuantum, quantum support vector machine, quantum support vector classifier, quantum support vector regressor, regresi ridge, variational quantum circuit, variational quantum classifier, variational quantum regressor, RealAmplitudes, quantum neural network, perceptron kuantum, quantum convolutional neural network.
Pembelajaran mesin kuantum atau Quantum Machine Learning (QML) adalah pembelajaran mesin yang memanfaatkan sifat unik dalam komputasi kuantum seperti superposisi, entanglement, dan paralelisme kuantum. Dalam implementasinya, QML dilakukan dengan pendekatan hibrid, yakni penggabungan antara komputasi kuantum dengan komputasi klasik.
8.1 Parameterised Quantum Circuit
Taksonomi pembelajaran mesin dapat dikategorikan menjadi empat macam, yakni CC, CQ, QC, dan QQ. Huruf C berarti klasik dan Q adalah kuantum. Huruf yang di depan mencerminkan data dan huruf di belakang menandakan proses. Pada bahasan ini, akan difokuskan pada CQ, yakni pembelajaran mesin dengan data klasik menggunakan proses kuantum (QML dengan data klasik).

QML dengan data klasik - selanjutnya disebut sebagai QML, dapat dimodelkan melalui Parameterised Quantum Circuit (PQC). PQC ini akan sedikit diulas kembali walau sebelumnya telah dibahas secara sekilas pada bab tentang Variational Quantum Algorithm (VQA). Secara matematis, state kuantum PQC dapat ditulis sebagai
\[ \ket{\psi(x,\theta)} = U(x, \theta) \ket{0} \tag{8.1.1} \]
dimana \(U(x,\theta)\) adalah gerbang kuantum unitary dengan input data klasik \(x\) dan parameter \(\theta\). Adapun nilai ekspektasi energi sebesar
\[ \langle H \rangle = \bra{\psi(x,\theta)} H \ket{\psi(x,\theta)} \tag{8.1.2} \]
dengan parameter \(\theta\) telah dilakukan proses optimasi secara klasikal.
PQC berisi gerbang-gerbang kuantum dengan parameter-parameter yang dapat diatur sehingga memungkinkan adanya proses optimasi sesuai dengan nilai ekspektasi yang diharapkan. Dengan konsep hibrid, komputasi dilakukan di sirkuit kuantum, sedangkan optimasi dilakukan oleh komputer klasik. Parameterisasi memungkinkan dibangunnya model kuantum (quantum model) yang dapat dilatih (trainable) dan dioptimalkan (optimisable). Adapun sifat atau karakteristik PQC, dua diantaranya ditentukan oleh ukuran expressivity dan trainability yang ia miliki.
8.2 Peta Fitur Kuantum
Peta fitur kuantum (quantum feature map) merupakan teknik enkode data dalam QML. Sebuah proses atau tahapan awal QML. Ia memetakan data klasik (vektor fitur) atau feature vector ke ruang fitur kuantum (quantum feature space) sedemikian rupa sehingga data tersebut dapat diproses atau ditransformasi dalam sirkuit kuantum. Beberapa contoh jenis peta fitur kuantum diantaranya yaitu enkode basis, enkode amplitudo, enkode sudut, enkode fase, serta enkode sudut padat.
8.2.1 Enkode Basis
Enkode basis (basis encoding) mengkodekan data klasik ke dalam bentuk basis komputasi. Data biner 0 dikodekan menjadi \(\ket{0}\) dan biner 1 ke \(\ket{1}\).
Contoh: Data klasik \([1, 1, 0]\). Hasil enkode basis berupa \(\ket{110}\).
Code: Basis Encoding [1, 1, 0]
# Basis Encoding [1, 1, 0]
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector
from qiskit.visualization import plot_histogram
import numpy as np
# Binary data to be encoded
data = [1, 1, 0] # Will be encoded as |110⟩ in big-endian
# Create a quantum circuit with 3 qubits
qc = QuantumCircuit(3)
# Function to perform basis encoding with big-endian ordering
def basis_encoding(data, circuit, qubits):
n = len(data)
for i, bit in enumerate(data):
if bit == 1:
circuit.x(qubits[n-1-i]) # Apply X gate on qubit (n-1-i) for bit 1 (flips |0⟩ to |1⟩)
# Apply basis encoding
basis_encoding(data, qc, range(3))
# Display the quantum circuit
print("Quantum Circuit:")
print(qc)
# Simulate the statevector to obtain the quantum state
state = Statevector.from_instruction(qc)
# Display the quantum state
print("\nQuantum State:")
print(state.data)
# Simulate measurement outcomes (probabilities)
counts = state.probabilities_dict()
print("\nMeasurement Outcomes (Probabilities):")
print(counts)
# Plot histogram of results
plot_histogram(counts)
8.2.2 Enkode Amplitudo
Enkode amplitudo (amplitude encoding) mengkodekan data klasik ke dalam amplitudo state kuantum. Ia memetakan data klasik (vektor fitur)
\[ x = [x_1, x_2, ..., x_N] \tag{8.2.1} \]
ke bentuk
\[ \ket{\psi} = x_{n_1} \ket{0} + x_{n_2} \ket{1} + \ ... \ + x_{n_N} \ket{N-1} \tag{8.2.2} \]
dengan total probabilitas adalah 1.
Vektor pada \((8.2.1)\) di atas memiliki norma
\[ ||x|| = \sqrt{x_1^2 + x_2^2 + \ ... \ + x_N^2} \tag{8.2.3} \]
sehingga vektor ternormalisasinya yakni
\[ x_\text{normal} = \bigg[\frac{x_1}{||x||}, \frac{x_2}{||x||}, \ ..., \frac{x_N}{||x||} \bigg] \tag{8.2.4} \]
Contoh: Data klasik \([0.5, 0.5]\). Hasil enkode amplitudo berupa \(\ket{\psi} = \sqrt{0.5} \ket{0} + \sqrt{0.5} \ket{1}\).
Code: Amplitude Encoding [0.5, 0.5]
# Amplitude Encoding [0.5, 0.5]
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector
from qiskit.visualization import plot_histogram
import numpy as np
# Classical data to be encoded
data = np.array([0.5, 0.5]) # Vector [0.5, 0.5]
# Normalise the data to ensure valid quantum state (sum of probabilities = 1)
norm = np.sqrt(np.sum(data ** 2))
data_normalized = data / norm
# Create a quantum circuit with 1 qubit (since 2^1 = 2 states can encode 2 values)
qc = QuantumCircuit(1)
# Function for amplitude encoding
def amplitude_encoding(data, circuit):
# Initialise the qubit to the desired state using initialize()
circuit.initialize(data, [0])
# Apply amplitude encoding
amplitude_encoding(data_normalized, qc)
# Display the quantum circuit
print("Quantum Circuit:")
print(qc)
# Simulate the statevector to obtain the quantum state
state = Statevector.from_instruction(qc)
# Display the quantum state
print("\nQuantum State:")
print(state.data)
# Simulate measurement outcomes (probabilities)
counts = state.probabilities_dict()
print("\nMeasurement Outcomes (Probabilities):")
print(counts)
# Plot histogram of results
plot_histogram(counts)
8.2.3 Enkode Sudut
Enkode sudut (angle encoding) mengkodekan data klasik ke dalam sudut rotasi gerbang kuantum, seperti gerbang \(R_x\), \(R_y\), atau \(R_z\). Dengan kata lain, data tersebut dilakukan transformasi rotasi sudut di dalam ruang kuantum-nya. Besar sudut rotasi \(\theta\) adalah senilai dengan data klasiknya (feature value).
Pada enkode sudut ini akan dipilih gerbang \(R_y(\theta)\) sebagai gerbang transformasinya
\[ R_y(\theta) \ket{0} = \cos(\theta/2) \ket{0} + \sin(\theta/2) \ket{1} \tag{8.2.5} \]
Contoh: Data klasik \([\pi/2, \pi/2]\). Pada contoh ini, gerbang transformasi berupa \(R_y(\pi/2)\) dan \(R_y(\pi/2)\) serta menghasilkan output enkode sudut \(\ket{\psi} = \frac{1}{2} \ket{00} + \frac{1}{2} \ket{01} + \frac{1}{2} \ket{10} + \frac{1}{2} \ket{11}\).
Code: Angle Encoding [pi/2, pi/2]
# Angle Encoding [pi/2, pi/2]
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector
from qiskit.visualization import plot_histogram
import numpy as np
# Classical data to be encoded
data = np.array([np.pi/2, np.pi/2])
# Create a quantum circuit with 2 qubits (one qubit per feature)
qc = QuantumCircuit(2)
# Function for angle encoding using Ry gates
def angle_encoding(data, circuit, qubits):
for i, value in enumerate(data):
circuit.ry(value, qubits[i]) # Apply Ry rotation with the feature value as the angle
# Apply angle encoding
angle_encoding(data, qc, range(2))
# Display the quantum circuit
print("Quantum Circuit:")
print(qc)
# Simulate the statevector to obtain the quantum state
state = Statevector.from_instruction(qc)
# Display the quantum state
print("\nQuantum State:")
print(state.data)
# Simulate measurement outcomes (probabilities)
counts = state.probabilities_dict()
print("\nMeasurement Outcomes (Probabilities):")
print(counts)
# Plot histogram of results
plot_histogram(counts)
8.2.4 Enkode Fase
Enkode fase (phase encoding) mengkodekan data klasik ke dalam ruang kuantum dengan cara memetakannya ke fase relatif dari state kuantum. Dalam enkode fase biasanya digunakan gerbang \(H\) dan \(P(\theta)\) sebagai transformasinya.
\[ P(\theta) = \begin{pmatrix} 1 & 0\\ 0 & e^{i\theta} \end{pmatrix} \tag{8.2.6} \]
Contoh: Data klasik \([\pi/2]\). Pada contoh encoding ini, gerbang kuantum yang digunakan berupa \(H\) dan \(P(\pi/2)\) serta menghasilkan output enkode fase \(\ket{\psi} = \frac{1}{\sqrt{2}} \ket{0} + \frac{1}{\sqrt{2}} i\ket{1}\).
Code: Phase Encoding [pi/2]
# Phase Encoding [pi/2]
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector
from qiskit.visualization import plot_histogram
import numpy as np
# Classical data to be encoded
data = np.array([np.pi/2]) # Vector [pi/2]
# Create a quantum circuit with 1 qubit (one qubit per feature)
qc = QuantumCircuit(1)
# Function for phase encoding using P gates
def phase_encoding(data, circuit, qubits):
for i in qubits:
circuit.h(i) # Apply Hadamard to create superposition
for i, value in enumerate(data):
circuit.p(value, qubits[i]) # Apply phase gate P with feature value as the phase
# Apply phase encoding
phase_encoding(data, qc, range(1))
# Display the quantum circuit
print("Quantum Circuit:")
print(qc)
# Simulate the statevector to obtain the quantum state
state = Statevector.from_instruction(qc)
# Display the quantum state
print("\nQuantum State:")
print(state.data)
# Simulate measurement outcomes (probabilities)
counts = state.probabilities_dict()
print("\nMeasurement Outcomes (Probabilities):")
print(counts)
# Plot histogram of results
plot_histogram(counts)
8.2.5 Enkode Sudut Padat
Enkode sudut padat (dense angle encoding, DAE) merupakan kombinasi enkode sudut dan enkode fase. DAE memungkinkan encoding dua vektor hanya ke dalam satu buah qubit. Untuk DAE, digunakan gerbang \(R_y(\theta)\) untuk vektor 1 dan \(R_z(\phi)\) untuk vektor 2.
Contoh: Data klasik \([\pi/2, 2\pi/3]\). "Ilustrasi" vektor 1 (warna teal) adalah \(\ket{\psi_1} = R_y(\pi/2)\ket{0}\) dan vektor 2 (merah muda) berupa \(\ket{\psi_2} = R_z(2\pi/3) R_y(\pi/2) \ket{0}\).

Code: Dense Angle Encoding [pi/2, 2pi/3]
# Dense Angle Encoding [pi/2, 2pi/3]
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector
from math import pi
import numpy as np
import matplotlib.pyplot as plt
from qiskit.visualization.bloch import Bloch
# First circuit: Ry(π/2) on a single qubit
qc1 = QuantumCircuit(1)
qc1.ry(np.pi / 2, 0)
# Second circuit: Ry(π/2) followed by Rz(2π/3) on a single qubit
qc2 = QuantumCircuit(1)
qc2.ry(np.pi / 2, 0)
qc2.rz(2 * np.pi / 3, 0)
# Simulate statevectors for both circuits
state1 = Statevector.from_instruction(qc1)
state2 = Statevector.from_instruction(qc2)
# Store states
states = state1, state2
# Display quantum states
print("Quantum State for qc1 (Ry(π/2)):")
print(state1.data)
print("\nQuantum State for qc2 (Ry(π/2) + Rz(2π/3)):")
print(state2.data)
# Calculate Bloch vector coordinates
# For a state |ψ⟩ = a|0⟩ + b|1⟩, Bloch coordinates are:
# x = 2 * Re(a * b), y = 2 * Im(a * b), z = |a|^2 - |b|^2
def bloch_coordinates(state):
a, b = state.data[0], state.data[1] # Amplitudes for |0⟩ and |1⟩
x = 2 * np.real(np.conj(a) * b)
y = 2 * np.imag(np.conj(a) * b)
z = np.abs(a) ** 2 - np.abs(b) ** 2
return [x, y, z]
bloch1 = bloch_coordinates(state1)
bloch2 = bloch_coordinates(state2)
# Display Bloch coordinates
print("\nBloch Coordinates for qc1 (Ry(π/2)): ", bloch1)
print("Bloch Coordinates for qc2 (Ry(π/2) + Rz(2π/3)): ", bloch2)
# Create a single Bloch sphere with two vectors
fig = plt.figure()
ax = fig.add_subplot(111, projection = '3d')
bloch = Bloch(axes = ax)
# Add vectors for both states
bloch.add_vectors([bloch1, bloch2]) # Add both vectors as a list
bloch.vector_color = ['#008080', '#C11C84'] # Set colors: blue for qc1, red for qc2
# Render the Bloch sphere
bloch.show()
plt.show()
8.3 Kernel Kuantum
Pada subbab sebelumnya telah dijelaskan bahwa data klasik agar dapat diproses dalam sirkuit kuantum, ia terlebih dahulu dilakukan enkode melalui peta fitur kuantum. Peta fitur kuantum memetakan data klasik ke ruang fitur kuantum.
Anggap \(\phi\) adalah peta fitur kuantum dari data klasik \(x\) dan \(x'\), maka kernel kuantum dapat didefinisikan secara matematis sebagai
\[ k(x, x') = |\braket{\phi(x)|\phi(x')}|^2 \tag{8.3.1} \]
Kernel kuantum merupakan hasil inner product dari dua state kuantum hasil enkode data klasik \(x\) dan \(x'\) yakni state \(\ket{\phi(x)}\) dan \(\ket{\phi(x')}\). Adapun salah satu fungsi kernel kuantum dalam komputasi kuantum yaitu digunakan untuk mengukur kemiripan antara dua data dalam ruang fitur kuantum. (Reminder: \(\braket{0|0} = \braket{1|1} = 1\) dan \(\braket{0|1} = \braket{1|0} = 0\)).
Contoh: Akan dicari kernel kuantum \(k\) dari data klasik \(x = [x_1]\) dan \(x' = [x_2]\). Peta fitur kuantum dipilih tipe enkode sudut \(R_y\).
\[ \ket{\phi(x)} = R_y(x_1) \ket{0} = \cos(x_1/2) \ket{0} + \sin(x_1/2) \ket{1} \tag{8.3.2} \]
dan
\[ \ket{\phi(x')} = R_y(x_2) \ket{0} = \cos(x_2/2) \ket{0} + \sin(x_2/2) \ket{1} \tag{8.3.3} \]
maka
\[ k(x, x') = |\cos(x_1/2) \cos(x_2/2) + \sin(x_1/2) \sin(x_2/2)|^2 \tag{8.3.4} \]
Ambil \(x = [0.3]\) dan \(x' = [0.4]\) maka
\[ k(x, x') = |\cos(0.3/2) \cos(0.4/2) + \sin(0.3/2) \sin(0.4/2)|^2 = 0.9975 \tag{8.3.5} \]
dan matriks kernel kuantum-nya adalah
\[ k = \begin{pmatrix} k(x, x) & k(x, x')\\ k(x', x) & k(x', x') \end{pmatrix} = \begin{pmatrix} 1 & 0.9975\\ 0.9975 & 1 \end{pmatrix} \tag{8.3.6} \]
dimana \(k(x', x) = k(x, x')\) merupakan sifat simetri.
Bola Bloch berikut menyajikan "ilustrasi" seberapa dekat dua data tersebut dalam ruang fitur kuantum.

Adapun sirkuit kuantum implementasi kernel kuantum dari contoh di atas adalah sebagai berikut. Implementasi menggunakan metode tes SWAP. Qubit \(q_0\) adalah ancilla, sedang \(q_1\) dan \(q_2\) untuk representasi data \(x_1\) dan \(x_2\). Kolom kiri pada sirkuit (dipisahkan oleh barrier) merupakan peta fitur kuantum tipe dekode sudut dengan gerbang \(R_y\). Kolom tengah ialah tes SWAP. Tujuan tes ini yakni ketika ancilla bernilai 1, maka state di \(q_1\) dan \(q_2\) ditukar. Kolom kanan adalah pengukuran.
Hasil pengukuran ancilla memiliki persamaan
\[ P(0) = \frac{1 + |\braket{\phi(x)|\phi(x')}|^2}{2} \tag{8.3.7} \]
sehingga nilai kernel kuantum \(k\) sebesar
\[ |\braket{\phi(x)|\phi(x')}|^2 = 2 P(0) - 1 \tag{8.3.8} \]

Code: Quantum Kernel
# Quantum Kernel
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector
import numpy as np
# Data input
x = [0.3]
x_prime = [0.4]
data = [x, x_prime]
# Initialise kernel matrix
n = len(data)
kernel_matrix = np.zeros((n, n))
# Calculate kernel for each pair
for i in range(n):
for j in range(i, n):
# Create quantum circuit for state |phi(x_i)>
qc_i = QuantumCircuit(1)
qc_i.ry(data[i][0], 0)
state_i = Statevector.from_instruction(qc_i)
# Create quantum circuit for state |phi(x_j)>
qc_j = QuantumCircuit(1)
qc_j.ry(data[j][0], 0)
state_j = Statevector.from_instruction(qc_j)
# Calculate inner product and kernel
inner_product = np.abs(state_i.inner(state_j)) ** 2
kernel_matrix[i, j] = inner_product
kernel_matrix[j, i] = inner_product # Symmetry
# Print kernel matrix
print("Quantum Kernel Matrix:")
print(kernel_matrix)
Code: Quantum Kernel Circuit
# Quantum Kernel Circuit
from qiskit import QuantumCircuit
from qiskit.primitives import StatevectorSampler
# Classical data
x1 = 0.3
x2 = 0.4
# n Qubit quantum system
qc = QuantumCircuit(3, 1)
# Quantum feature map - angle encoding
qc.ry(x1, 1)
qc.ry(x2, 2)
# Barrier
qc.barrier()
# SWAP test
qc.h(0)
qc.cswap(0, 1, 2)
qc.h(0)
# Barrier
qc.barrier()
# Measurement on ancilla
qc.measure(0, 0)
# Running on simulator
sampler = StatevectorSampler()
job = sampler.run([(qc, None, 1024)])
result = job.result()
# Measurement counts
counts = result[0].data.c.get_counts()
# Total shots
shots = sum(counts.values())
# Probability P(|0>)
p0 = counts.get('0', 0) / shots
# Kernel value k = |<ψ_x|ψ_x'>|^2
k = 2 * p0 - 1
print(f"{k:.4f}")
qc.draw("mpl", style = {"backgroundcolor": "#f5f5f5"})
8.4 Quantum Support Vector Machine
Quantum Support Vector Machine (QSVM) merupakan algoritma QML yang menggunakan kernel kuantum sebagai input pada SVM klasik untuk menentukan support vector, menghitung bias, dan melakukan prediksi label atau regresi. Dengan kata lain, QSVM menggabungkan komputasi kuantum dengan komputasi klasik.
Sisi komputasi kuantum yakni pada bagian peta fitur kuantum yang memetakan data klasik ke ruang fitur kuantum, melakukan inner product state kuantum hasil enkode, hingga didapat kernel kuantum beserta matriksnya. Selebihnya, SVM klasik yang berperan sampai didapat prediksi label atau regresinya.
8.4.1 Quantum Support Vector Classifier
Quantum Support Vector Classifier (QSVC) merupakan QSVM untuk tugas klasifikasi. Berikut disajikan dua contoh QSVC untuk data linier dan non linier. Jumlah data klasik masing-masing contoh adalah 6 data, oleh karenanya matriks kernel kuantum-nya berdimensi 6 x 6. Adapun peta fitur kuantum yang dipilih yakni tipe enkode sudut dengan gerbang rotasi \(R_y\).


Code: QSVC
# QSVC
import numpy as np
import matplotlib.pyplot as plt
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector
from scipy.optimize import minimize
# Classical data
X = np.array([[0.2, 0.7], [0.4, 0.5], [0.3, 0.6], [0.8, 0.3], [0.7, 0.6], [0.5, 0.8]])
y = np.array([-1, -1, -1, 1, 1, 1])
n = len(X)
# Quantum feature map: angle encoding
def angle_encoding_circuit(x):
qc = QuantumCircuit(len(x))
for i in range(len(x)):
qc.ry(x[i], i)
return qc
# Quantum kernel: |⟨ψ(x1)|ψ(x2)⟩|^2
def quantum_kernel(x1, x2):
sv1 = Statevector(angle_encoding_circuit(x1))
sv2 = Statevector(angle_encoding_circuit(x2))
return np.abs(sv1.data.conj().dot(sv2.data)) ** 2
# Compute the kernel matrix
K = np.zeros((n,n))
for i in range(n):
for j in range(n):
K[i,j] = quantum_kernel(X[i], X[j])
print("Quantum kernel matrix:")
print(np.round(K, 3))
# Dual SVM objective function
def dual_objective(alpha):
return 0.5 * np.sum(alpha[:,None] * alpha[None,:] * y[:,None] * y[None,:] * K) - np.sum(alpha)
# Constraint: sum of α_i * y_i = 0
constraints = {'type':'eq', 'fun': lambda a: np.dot(a, y)}
# Bound: α_i >= 0
bounds = [(0, None) for _ in range(n)]
# Initial guess
alpha0 = np.zeros(n)
# Optimise alpha
res = minimize(dual_objective, alpha0, bounds = bounds, constraints = constraints)
alpha = res.x
print("Alpha vector:", np.round(alpha, 3))
# Compute bias b
tol = 1e-5
sv_idx = np.where(alpha > tol)[0]
b = 0
for k in sv_idx:
b += y[k] - np.sum(alpha * y * K[:,k])
b /= len(sv_idx)
print("Bias b:", b)
# QSVC prediction
def predict(x_new):
s = np.sum(alpha * y * np.array([quantum_kernel(X[i], x_new) for i in range(n)]))
s += b
return np.sign(s)
preds = [predict(X[i]) for i in range(n)]
print("QSVC predictions:", preds)
print("Actual labels :", y.tolist())
# Plot QSVC decision boundary
x_min, x_max = 0, 1
y_min, y_max = 0, 1
xx, yy = np.meshgrid(np.linspace(x_min, x_max, 200),
np.linspace(y_min, y_max, 200))
grid_points = np.c_[xx.ravel(), yy.ravel()]
Z = np.array([predict(p) for p in grid_points]).reshape(xx.shape)
plt.figure(figsize = (5,4), facecolor = '#f5f5f5')
plt.contourf(xx, yy, Z, alpha = 0.2, colors = ['#C11C84','#008080'])
plt.scatter(X[y == -1][:,0], X[y == -1][:,1], color = '#C11C84', label = 'Class -1')
plt.scatter(X[y == 1][:,0], X[y == 1][:,1], color = '#008080', label = 'Class 1')
plt.scatter(X[sv_idx][:,0], X[sv_idx][:,1], s = 150, facecolors = 'none', edgecolors = 'k', label = 'Support Vector')
plt.xlabel('x1')
plt.ylabel('x2')
plt.title('QSVC')
plt.legend()
plt.show()
Code: QSVC Non Linear Data
# QSVC Non Linear Data
import numpy as np
import matplotlib.pyplot as plt
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector
from scipy.optimize import minimize
# Classical data
X = np.array([
[0.1, 0.1],
[0.9, 0.9],
[0.1, 0.9],
[0.9, 0.1],
[0.5, 0.2],
[0.2, 0.8]
])
y = np.array([-1, -1, 1, 1, -1, 1])
n = len(X)
# Quantum feature map: angle encoding
def angle_encoding_circuit(x):
qc = QuantumCircuit(len(x))
for i in range(len(x)):
qc.ry(x[i], i)
return qc
# Quantum kernel: |⟨ψ(x1)|ψ(x2)⟩|^2
def quantum_kernel(x1, x2):
sv1 = Statevector(angle_encoding_circuit(x1))
sv2 = Statevector(angle_encoding_circuit(x2))
return np.abs(sv1.data.conj().dot(sv2.data)) ** 2
# Compute the kernel matrix
K = np.zeros((n,n))
for i in range(n):
for j in range(n):
K[i,j] = quantum_kernel(X[i], X[j])
print("Quantum kernel matrix:")
print(np.round(K, 3))
# Dual SVM objective function
def dual_objective(alpha):
return 0.5 * np.sum(alpha[:,None] * alpha[None,:] * y[:,None] * y[None,:] * K) - np.sum(alpha)
# Constraint: sum of α_i * y_i = 0
constraints = {'type':'eq', 'fun': lambda a: np.dot(a, y)}
# Bound: α_i >= 0
bounds = [(0, None) for _ in range(n)]
# Initial guess
alpha0 = np.zeros(n)
# Optimise alpha
res = minimize(dual_objective, alpha0, bounds = bounds, constraints = constraints)
alpha = res.x
print("Alpha vector:", np.round(alpha, 3))
# Compute bias b
tol = 1e-5
sv_idx = np.where(alpha > tol)[0]
b = 0
for k in sv_idx:
b += y[k] - np.sum(alpha * y * K[:,k])
b /= len(sv_idx)
print("Bias b:", b)
# QSVC prediction
def predict(x_new):
s = np.sum(alpha * y * np.array([quantum_kernel(X[i], x_new) for i in range(n)]))
s += b
return np.sign(s)
preds = [predict(X[i]) for i in range(n)]
print("QSVC predictions:", preds)
print("Actual labels :", y.tolist())
# Plot QSVC decision boundary
x_min, x_max = 0, 1
y_min, y_max = 0, 1
xx, yy = np.meshgrid(np.linspace(x_min, x_max, 200),
np.linspace(y_min, y_max, 200))
grid_points = np.c_[xx.ravel(), yy.ravel()]
Z = np.array([predict(p) for p in grid_points]).reshape(xx.shape)
plt.figure(figsize = (5,4), facecolor = '#f5f5f5')
plt.contourf(xx, yy, Z, alpha = 0.2, colors = ['#C11C84','#008080'])
plt.scatter(X[y == -1][:,0], X[y == -1][:,1], color = '#C11C84', label = 'Class -1')
plt.scatter(X[y == 1][:,0], X[y == 1][:,1], color = '#008080', label = 'Class 1')
plt.scatter(X[sv_idx][:,0], X[sv_idx][:,1], s = 150, facecolors = 'none', edgecolors = 'k', label = 'Support Vector')
plt.xlabel('x1')
plt.ylabel('x2')
plt.title('QSVC Non Linear Data')
plt.legend()
plt.show()
8.4.2 Quantum Support Vector Regressor
Quantum Support Vector Regressor (QSVR) merupakan jenis QSVM untuk tujuan regresi. Berikut disajikan contoh perhitungan sederhana QSVR dari dua titik data yakni \(x_1 = [0, 0]\), target \(y_1 = 0\) dan \(x_2 = [1, 1]\), target \(y_2 = 1\). QSVR menggunakan enkode sudut \(R_y\) pada sistem dua qubit dan regresi ridge dengan \(\lambda = 0.01\).
Tahap 1: Enkode sudut \(R_y\). State \(\ket{\psi_1} = R_y(x_1) \ket{0} \otimes R_y(x_1) \ket{0}\) dan \(\ket{\psi_2} = R_y(x_2) \ket{0} \otimes R_y(x_2) \ket{0}\). Dengan
\[ R_y(\theta) \ket{0} = \cos(\theta/2) \ket{0} + \sin(\theta/2) \ket{1} \tag{8.4.1} \]
maka
\[ \ket{\psi_1} = R_y(0) \ket{0} \otimes R_y(0) \ket{0} = \ket{00} \tag{8.4.2} \]
dan
\[ \ket{\psi_2} = R_y(1) \ket{0} \otimes R_y(1) \ket{0} \approx 0.7701 \ket{00} + 0.4207 \ket{01} + 0.4207 \ket{10} + 0.2298 \ket{11} \tag{8.4.3} \]
Tahap 2: Kernel kuantum. Nilai kernel \(k(0,0)\), \(k(1,1)\), \(k(0,1)\), dan \(k(1,0)\) berturut-turut yaitu
\[ k(0,0) = |\braket{\psi_1 | \psi_1}| ^ 2 = 1 \ (\text{normal}) \tag{8.4.4} \]
\[ k(1,1) = |\braket{\psi_2 | \psi_2}| ^ 2 = 1 \ (\text{normal}) \tag{8.4.5} \]
\[ k(0,1) = k(1,0) = |\braket{\psi_1 | \psi_2}| ^ 2 = 0.7701 ^ 2 \approx 0.5931 \ (\text{simetri}) \tag{8.4.6} \]
Diperoleh matriks kernel
\[ k = \begin{pmatrix} 1 & 0.5931 \\ 0.5931 & 1 \end{pmatrix} \tag{8.4.7} \]
Tahap 3: Regresi ridge. Tiga parameter dalam regresi ridge:
\[ \alpha = (k + \lambda I) ^ {-1} y, \quad \lambda = 0.01, \quad y = \begin{pmatrix} 0 \\ 1 \end{pmatrix} \tag{8.4.8} \]
Didapat nilai \(\alpha_1 \approx -0.888\) dan \(\alpha_2 \approx 1.511\).
Tahap 4: Fungsi prediksi \(f(x)\). Persamaan fungsi prediksi yakni
\[ f(x) = \sum_{i = 1} ^ N \alpha_i k(x, x_i) \tag{8.4.9} \]
sehingga
\[ f(x) = \alpha_1 k(x, x_1) + \alpha_2 k(x, x_2) \tag{8.4.10} \]
Tahap 5: Contoh prediksi.
Contoh 1: Titik data \(x = [0, 0]\). Nilai kernel \(k(x, x_1) = 1\) dan \(k(x, x_2) = 0.5931\), sehingga
\[ f([0, 0]) = (-0.888)(1) + (1.511)(0.5931) \approx -0.888 + 0.896 = 0.008 \tag{8.4.11} \]
Contoh 2: Titik data \(x = [1, 1]\). Nilai kernel \(k(x, x_1) = 0.5931\) dan \(k(x, x_2) = 1\), sehingga
\[ f([1, 1]) = (-0.888)(0.5931) + (1.511)(1) \approx -0.527 + 1.511 = 0.984 \tag{8.4.12} \]
Code: QSVR
# QSVR
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector
import numpy as np
# Define the data
x1 = [0.0, 0.0] # target y1 = 0
x2 = [1.0, 1.0] # target y2 = 1
y = np.array([0.0, 1.0])
lam = 0.01 # ridge regularisation parameter
print("Data points:")
print("x1 =", x1, " → y1 = 0")
print("x2 =", x2, " → y2 = 1")
print("λ =", lam)
print()
# Encode each input x as Ry(x[0]) ⊗ Ry(x[1])
# Encode x1 = [0,0]
qc1 = QuantumCircuit(2)
qc1.ry(x1[0], 0) # Ry(0) on qubit 0
qc1.ry(x1[1], 1) # Ry(0) on qubit 1
psi1 = Statevector.from_instruction(qc1) # |00⟩
# Encode x2 = [1,1]
qc2 = QuantumCircuit(2)
qc2.ry(x2[0], 0) # Ry(1) on qubit 0
qc2.ry(x2[1], 1) # Ry(1) on qubit 1
psi2 = Statevector.from_instruction(qc2)
print("Quantum states created:")
print("|ψ₁⟩ = Ry(0)|0⟩ ⊗ Ry(0)|0⟩ = |00⟩")
print("|ψ₂⟩ = Ry(1)|0⟩ ⊗ Ry(1)|0⟩ → mixed state")
print()
# Compute the quantum kernel matrix k_ij = |⟨ψ_i|ψ_j⟩|²
k11 = np.abs(psi1.inner(psi1)) ** 2 # 1.0
k12 = np.abs(psi1.inner(psi2)) ** 2 # overlap between x1 and x2
k21 = k12
k22 = np.abs(psi2.inner(psi2)) ** 2 # 1.0
k = np.array([[k11, k12],
[k21, k22]])
print("Quantum kernel matrix k:")
print(np.round(k, 4))
print()
# Ridge regression → α = (k + λI)⁻¹ y
I = np.eye(2)
alpha = np.linalg.inv(k + lam * I) @ y
print("Ridge regression coefficients α:")
print("α₁ =", np.round(alpha[0], 4))
print("α₂ =", np.round(alpha[1], 4))
print()
# Define prediction function f(x)
# f(x) = α₁ k(x,x₁) + α₂ k(x,x₂)
def predict(x):
# Encode new input x
qc = QuantumCircuit(2)
qc.ry(x[0], 0)
qc.ry(x[1], 1)
psi_x = Statevector.from_instruction(qc)
# Compute kernel elements
kx1 = np.abs(psi1.inner(psi_x)) ** 2
kx2 = np.abs(psi2.inner(psi_x)) ** 2
# Final prediction
return alpha[0] * kx1 + alpha[1] * kx2
# Test predictions
print("Predictions f(x):")
print("f([0.0, 0.0]) =", np.round(predict([0.0, 0.0]), 4)) # ~0.008
print("f([1.0, 1.0]) =", np.round(predict([1.0, 1.0]), 4)) # ~0.984
print("f([0.5, 0.5]) =", np.round(predict([0.5, 0.5]), 4))
print("f([0.0, 1.0]) =", np.round(predict([0.0, 1.0]), 4))
print("f([1.0, 0.0]) =", np.round(predict([1.0, 0.0]), 4))
8.5 Variational Quantum Circuit
Variational Quantum Circuit (VQC) adalah algoritma QML dengan sirkuit variasional yang digunakan untuk tugas klasifikasi atau regresi. Sama seperti VQE dan QAOA, VQC merupakan algoritma hibrida yakni gabungan komputasi kuantum dan komputasi klasik, dengan optimasi parameter sirkuit kuantum hingga didapatkan prediksi yang sesuai. Adapun bagian atau tahapan VQC meliputi data klasik, peta fitur kuantum, ansatz, optimasi, serta pengukuruan nilai ekspektasi.
8.5.1 Variational Quantum Classifier
Variational Quantum Classifier (VQC) merupakan jenis VQC untuk tugas klasifikasi, seperti memprediksi label 0 atau 1 dari data input.
Contoh: VQC akan digunakan untuk memprediksi label klasifikasi data \(x = [x_1, x_2]\) dengan kondisi berikut
\[ \text{prediksi label} = \begin{cases} 0 & \text{jika } x_1 + x_2 \le 1 \\ 1 & \text{jika } x_1 + x_2 > 1 \end{cases} \tag{8.5.1} \]
Misal dipilih data \(x = [0.7, 0.8]\) dan akan diprediksi dengan VQC 2-qubit dan VQC 1-qubit.
8.5.1.a VQC 2-Qubit
Tahap 1: Data klasik. Data klasik \(x = [0.7, 0.8]\). Dari data didapat \(0.7+0.8=1.5\) sehingga ia lebih dari 1, maka true label bernilai 1.
Tahap 2: Peta fitur kuantum - enkode sudut. Dibutuhkan dua qubit untuk peta fitur kuantum ini yakni \(q_0\) dan \(q_1\). Selanjutnya, diterapkan gerbang kuantum \(R_y(x_1)\) pada \(q_0\) dan \(R_y(x_2)\) pada \(q_1\), atau gerbang \(R_y(0.7)\) pada \(q_0\) serta \(R_y(0.8)\) pada \(q_1\).
Tahap 3: Ansatz. Ansatz terdiri dari gerbang \(CX\) dengan qubit \(q_0\) sebagai kontrol dan \(q_1\) sebagai target, serta gerbang rotasi dengan parameter \(\theta\) atau \(R_y(\theta)\) pada \(q_0\). Pada contoh ini, nilai \(\theta\) telah ditentukan sebesar \(\pi\). Adapun pada proses komputasi sebenarnya, nilai parameter \(\theta\) didapat dengan menggunakan teknik optimasi.
Tahap 4: Nilai Ekspektasi. Pengukuran nilai ekspektasi \(\langle Z \rangle\) dari state kuantum akhir pada qubit \(q_0\).

Hubungan nilai ekspektasi \(\langle Z \rangle\) dengan probabilitas \(P\). Kedua besaran tersebut memiliki hubungan yakni
\[ \langle Z \rangle\ = P(\ket{0}) \cdot (+1) + P(\ket{1}) \cdot (-1) \tag{8.5.2} \]
dengan \(P(\ket{0}) + P(\ket{1}) = 1\). Selanjutnya, persamaan di atas dapat ditulis sebagai
\[ \langle Z \rangle\ = P(\ket{0}) - P(\ket{1}) = P(\ket{0}) - (1 - P(\ket{0})) = 2 P(\ket{0}) - 1 \tag{8.5.3} \]
atau
\[ P(\ket{0}) = \frac{1 + \langle Z \rangle}{2} \tag{8.5.4} \]
Jika \(\langle Z \rangle\ < 0\) maka \(P(\ket{0}) < 0.5\). Ini berarti probabilitas menemukan state lebih besar ke \(\ket{1}\), prediksi label pada VQC diklasifikasikan 1. Sebaliknya, jika \(\langle Z \rangle\ \ge 0\) maka \(P(\ket{0}) \ge 0.5\), prediksi label VQC diberi 0.
State kuantum dari sirkuit kuantum di atas yakni
\[ \ket{\psi} = -0.1335307 \ket{00} + 0.86521956 \ket{01} - 0.3158298 \ket{10} + 0.36580896 \ket{11} \tag{8.5.5} \]
sehingga didapat nilai ekspektasi \(\langle Z \rangle\) pada qubit \(q_0\) sebesar
\[ \langle Z \rangle = \bra{\psi} Z \ket{\psi} = -0.7648421872844884 \tag{8.5.6} \]
Nilai ekspektasi \(\langle Z \rangle\) \(< 0\), maka hasil prediksi label VQC ialah 1. Hal ini sesuai dengan true label dari \(x = [0.7, 0.8]\) yang bernilai 1.
Lalu, bagaimanakah jika ansatz dikembangkan dan dilakukan optimasi parameter \(\theta\)-nya? Berikut ialah salah satu contohnya. Ada beberapa gerbang yang ditambahkan pada ansatz sedemikian rupa sehingga sirkuit menjadi lebih ekspresif.

Adapun nilai ekspektasi dari sirkuit ini yaitu
\[ \langle Z \rangle = -0.9999999960339767 \tag{8.5.7} \]
Code: 2-Qubit VQC
# 2-Qubit VQC
from qiskit import QuantumCircuit
from qiskit.quantum_info import Operator, Statevector
import numpy as np
# Data input
x = [0.7, 0.8] # Features
theta = np.pi # Variational parameter, explicitly set to pi
# 2-Qubit quantum system
qc = QuantumCircuit(2)
# Feature map
qc.ry(x[0], 0)
qc.ry(x[1], 1)
# Ansatz
qc.cx(0, 1)
qc.ry(theta, 0)
# Statevector
statevector = Statevector.from_instruction(qc)
# Expectation value
i_z = Operator([[1, 0, 0, 0],
[0, -1, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, -1]])
expectation_value = statevector.expectation_value(i_z).real
# Print results
print("Statevector:", statevector.data)
print(f"Expectation value on q0: {expectation_value}")
print(f"Probability of |0> for q0: {(1 + expectation_value) / 2}")
print(f"Predicted label: {1 if expectation_value < 0 else 0}")
Code: Optimised 2-Qubit VQC
# Optimised 2-Qubit VQC
from qiskit import QuantumCircuit
from qiskit.quantum_info import Operator, Statevector
from qiskit.visualization import circuit_drawer
import numpy as np
from scipy.optimize import minimize
import matplotlib.pyplot as plt
# Input data
x = [0.7, 0.8] # Features
# Operator for expectation value (I ⊗ Z)
i_z = Operator([[1, 0, 0, 0],
[0, -1, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, -1]])
# Function to create the quantum circuit with an enhanced ansatz
def create_circuit(theta, x):
qc = QuantumCircuit(2)
# Feature map
qc.ry(x[0], 0) # Rotation Y on qubit 0 based on feature x[0]
qc.ry(x[1], 1) # Rotation Y on qubit 1 based on feature x[1]
# Enhanced ansatz
qc.cx(0, 1) # CNOT for entanglement
qc.ry(theta[0], 0) # Y rotation on qubit 0
qc.rz(theta[1], 0) # Z rotation on qubit 0
qc.ry(theta[2], 1) # Y rotation on qubit 1
qc.cx(1, 0) # Additional CNOT for entanglement
qc.rz(theta[3], 1) # Z rotation on qubit 1
return qc
# Objective function for optimisation (maximising expectation value)
def objective_function(theta, x):
qc = create_circuit(theta, x)
statevector = Statevector.from_instruction(qc)
expectation_value = statevector.expectation_value(i_z).real
return expectation_value # Negative to maximise expectation value
# Initialise parameters randomly for robust optimisation
initial_theta = np.random.uniform(0, 2 * np.pi, 4)
print("Initial theta parameters:", initial_theta)
# Optimise theta parameters using COBYLA
result = minimize(objective_function, initial_theta, args = (x,), method = 'COBYLA', options = {'maxiter': 1000})
# Optimised theta parameters
optimal_theta = result.x
print("Optimised theta parameters:", optimal_theta)
# Create circuit with optimised parameters
qc_optimal = create_circuit(optimal_theta, x)
# Calculate statevector and expectation value
statevector_optimal = Statevector.from_instruction(qc_optimal)
expectation_value_optimal = statevector_optimal.expectation_value(i_z).real
# Print results
print("Statevector:", statevector_optimal.data)
print("Expectation value for q0:", expectation_value_optimal)
print("Probability of |0> for q0:", (1 + expectation_value_optimal) / 2)
print("Predicted label:", 1 if expectation_value_optimal < 0 else 0)
# Visualise the circuit and save it as a file
qc_optimal.draw('mpl', style={"backgroundcolor": "#f5f5f5"})
8.5.1.b VQC 1-Qubit
Jika pada VQC 2-qubit menggunakan enkode sudut, maka pada VQC 1-qubit ini di dalam tahapan peta fitur kuantum-nya memakai enkode amplitudo. Data klasik atau vektor \(x = [0.7, 0.8]\) terdiri atas 2 data, maka cukup dibutuhkan sebanyak \(\log_2 2 = 1\) qubit saja. Adapun ansatz berupa gerbang \(R_y(\theta)\) dengan nilai \(\theta\) yang telah ditentukan yakni \(\theta=\pi/2\). Terakhir, dilakukan pengukuran nilai ekspektasi energi yaitu \(\bra{\psi_q} Z \ket{\psi_q}\).

State kuantum dari sirkuit di atas yakni
\[ \ket{\psi_q} = -0.0665 \ket{0} + 0.9978 \ket{1} \tag{8.5.8} \]
sehingga nilai ekspektasi energinya sebesar
\[ \langle Z \rangle = -0.9912 \tag{8.5.9} \]
Nilai \(\langle Z \rangle\ < 0\) maka \(P(\ket{0}) < 0.5\), berarti probabilitas menemukan state lebih besar ke \(\ket{1}\), prediksi label pada VQC adalah 1.
Selanjutnya, disajikan satu contoh VQC 1-qubit versi hasil pengembangan di bagian ansatz, yaitu dengan menambahkan gerbang \(R_z\) serta melakukan optimasi pada parameter \(\theta\).

Code: 1-Qubit VQC
# 1-Qubit VQC
from qiskit import QuantumCircuit
from qiskit.quantum_info import Operator, Statevector
from qiskit.circuit.library import Initialize
import numpy as np
# Feature vector
x = np.array([0.7, 0.8])
# Normalise the vector
norm = np.linalg.norm(x)
normalised_x = x / norm
# 1-Qubit quantum circuit
qc = QuantumCircuit(1)
# Quantum feature map: Amplitude encoding
qc.initialize(normalised_x, 0) # Encode [x1, x2] into |0⟩ and |1⟩
# Initial gate after normalisation
init_gate = Initialize(normalised_x)
# Variational layer: Parameterised circuit (Ansatz)
qc.ry(np.pi/2, 0) # Ry gate with pi/2
# Statevector
statevector = Statevector.from_instruction(qc)
# Expectation value
Z = Operator([[1, 0], [0, -1]])
expectation_value = statevector.expectation_value(Z).real
# Print results
print("Original vector:", x)
print("Normalised vector:", normalised_x)
print("Statevector:", statevector.data)
print(f"Expectation value: {expectation_value}")
print(f"Probability of |0> : {(1 + expectation_value) / 2}")
print(f"Predicted label: {1 if expectation_value < 0 else 0}")
# Draw quantum circuit
qc.draw("mpl", style={"backgroundcolor": "#f5f5f5"})
Code: Optimised 1-Qubit VQC
# Optimised 1-Qubit VQC
from qiskit import QuantumCircuit
from qiskit.quantum_info import Operator, Statevector
from qiskit.circuit.library import Initialize
import numpy as np
from scipy.optimize import minimize
# Feature vector for encoding
x = np.array([0.7, 0.8])
# Normalise the feature vector
norm = np.linalg.norm(x)
normalised_x = x / norm
# Define a function to create the quantum circuit with a parameterised ansatz
def create_circuit(params):
# Initialise a 1-qubit quantum circuit
qc = QuantumCircuit(1)
# Encode the normalised feature vector using amplitude encoding
qc.initialize(normalised_x, 0)
# Apply a parameterised ansatz: Ry and Rz gates
qc.ry(params[0], 0) # Ry gate with parameter theta_1
qc.rz(params[1], 0) # Rz gate with parameter theta_2
return qc
# Define the cost function for optimisation
def cost_function(params):
# Create the circuit with the given parameters
qc = create_circuit(params)
# Compute the statevector of the circuit
statevector = Statevector.from_instruction(qc)
# Define the Pauli-Z operator
Z = Operator([[1, 0], [0, -1]])
# Calculate the expectation value of Z
expectation = statevector.expectation_value(Z).real
return expectation # Objective: minimise the expectation value
# Set initial parameters for optimisation (randomly chosen)
initial_params = np.random.uniform(0, 2 * np.pi, 2)
# Perform optimisation using the COBYLA algorithm
result = minimize(cost_function, initial_params, method = 'COBYLA', options = {'maxiter': 100})
# Extract the optimised parameters
optimal_params = result.x
# Create the circuit with optimised parameters
qc_opt = create_circuit(optimal_params)
# Compute the statevector for the optimised circuit
statevector_opt = Statevector.from_instruction(qc_opt)
# Define the Pauli-Z operator for expectation value
Z = Operator([[1, 0], [0, -1]])
# Calculate the optimised expectation value
expectation_value_opt = statevector_opt.expectation_value(Z).real
# Print results
print("Original vector:", x)
print("Normalised vector:", normalised_x)
print("Optimised parameters:", optimal_params)
print("Optimised statevector:", statevector_opt.data)
print(f"Optimised expectation value: {expectation_value_opt}")
print(f"Probability of |0⟩: {(1 + expectation_value_opt) / 2}")
print(f"Predicted label: {1 if expectation_value_opt < 0 else 0}")
# Draw the optimised circuit
qc_opt.draw("mpl", style={"backgroundcolor": "#f5f5f5"})
8.5.1.c VQC N Poin Vektor
Dua subsubbab sebelumnya telah menyajikan VQC untuk 1 poin vektor, dimana untuk yang pertama menggunakan VQC 2-qubit dengan peta fitur kuantum tipe enkode sudut dan untuk yang kedua melalui VQC 1-qubit berjenis enkode amplitudo pada peta fitur kuantum-nya.
Disini, akan diberikan satu contoh VQC 1-qubit untuk N poin vektor. Di VQC ini, peta fitur kuantum berupa gerbang \(R_y(x_1 * \pi)\) dan \(R_z(x_2 * \pi)\), sedangkan ansatz-nya terdiri atas gerbang \(R_y(\theta_1)\) dan \(R_z(\theta_2)\).


Code: 1-Qubit VQC for N Vector Points
# 1-Qubit VQC for N Vector Points
from qiskit import QuantumCircuit
from qiskit.quantum_info import Operator, Statevector
import numpy as np
from scipy.optimize import minimize
import matplotlib.pyplot as plt
# Generate synthetic dataset: 1000 data points with 2D feature vectors and binary labels
np.random.seed(42) # For reproducibility
n_samples = 1000
X = np.random.uniform(0, 1, (n_samples, 2)) # 1000 random 2D vectors
true_labels = np.array([0 if x[0] + x[1] <= 1 else 1 for x in X]) # Label 0 if x1 + x2 <= 1, else 1
# Define a function to create the quantum circuit with angle encoding and parameterised ansatz
def create_circuit(feature_vector, params):
# Initialise a 1-qubit quantum circuit
qc = QuantumCircuit(1)
# Angle encoding: encode x1 and x2 into rotations
qc.ry(feature_vector[0] * np.pi, 0) # Ry(x1 * pi) on qubit 0
qc.rz(feature_vector[1] * np.pi, 0) # Rz(x2 * pi) on qubit 0
# Parameterised ansatz: Ry, Rz gates
qc.ry(params[0], 0) # Ry gate with parameter theta_1
qc.rz(params[1], 0) # Rz gate with parameter theta_2
return qc
# Define a function to compute the expectation value for a single data point
def compute_expectation(feature_vector, params):
# Create the circuit with the given parameters and feature vector
qc = create_circuit(feature_vector, params)
# Compute the statevector of the circuit
statevector = Statevector.from_instruction(qc)
# Define the Pauli-Z operator
Z = Operator([[1, 0], [0, -1]])
# Calculate the expectation value of Z
return statevector.expectation_value(Z).real
# Define the loss function: Binary cross-entropy
def loss_function(params, X, true_labels):
loss = 0
for x, true_label in zip(X, true_labels):
z = compute_expectation(x, params)
prob_one = (1 - z) / 2 # P(label=1) = (1 - ) / 2
# Avoid log(0) by clipping probabilities
prob_one = np.clip(prob_one, 1e-10, 1 - 1e-10)
loss += - (true_label * np.log(prob_one) + (1 - true_label) * np.log(1 - prob_one))
return loss / len(X)
# Optimise a single set of parameters for the entire dataset
initial_params = np.zeros(2) # Start with zeros for stability
result = minimize(lambda params: loss_function(params, X, true_labels),
initial_params, method = 'BFGS', options = {'maxiter': 300})
optimal_params = result.x
# Print optimised parameters and minimum loss
print("Optimised parameters:", optimal_params)
print("Minimum loss: {:.4f}".format(result.fun))
# Predict labels for all data points using the optimised parameters
predicted_labels = []
for x in X:
z = compute_expectation(x, optimal_params)
predicted_label = 1 if z < 0 else 0
predicted_labels.append(predicted_label)
predicted_labels = np.array(predicted_labels)
# Calculate accuracy
accuracy = np.mean(predicted_labels == true_labels) * 100
# Print results
print("Dataset size:", n_samples)
print("Accuracy of predictions: {:.2f}%".format(accuracy))
# Plotting: True labels (left) and predicted labels (right)
fig, (ax1, ax2) = plt.subplots(1, 2, figsize = (9, 4))
# Set background colour for figure and axes
fig.patch.set_facecolor('#f5f5f5')
ax1.set_facecolor('#f5f5f5')
ax2.set_facecolor('#f5f5f5')
for ax in [ax1, ax2]:
for spine in ax.spines.values():
spine.set_color('#111')
ax.xaxis.label.set_color('#111')
ax.yaxis.label.set_color('#111')
ax.tick_params(colors = '#111')
ax.title.set_color('#111')
# Plot 1: True labels
for x, label in zip(X, true_labels):
color = '#008080' if label == 0 else '#C11C84'
ax1.scatter(x[0], x[1], c = color, s = 20)
ax1.set_xlabel('x1')
ax1.set_ylabel('x2')
ax1.set_title('True Labels, Dataset of 1000 Points')
ax1.grid(True)
# Plot 2: Predicted labels
for x, pred in zip(X, predicted_labels):
color = '#008080' if pred == 0 else '#C11C84'
ax2.scatter(x[0], x[1], c = color, s = 20)
ax2.set_xlabel('x1')
ax2.set_ylabel('x2')
ax2.set_title(f'Predicted Labels, {accuracy:.2f}% Accuracy')
ax2.grid(True)
plt.tight_layout()
plt.show()
# Draw the circuit for the last data point as an example
qc_example = create_circuit(X[-1], optimal_params)
qc_example.draw("mpl", style = {"backgroundcolor": "#f5f5f5"})
8.5.2 Variational Quantum Regressor
Variational Quantum Regressor (VQR) adalah jenis Variational Quantum Circuit untuk tujuan regresi. Berikut disajikan contoh sederhana VQR. Diberikan dua titik data yakni \(x_1 = [0, 0]\) dan \(x_2 = [1, 1]\) dengan target \(y_1 = 0\) dan \(y_2 = 1\). Sirkuit VQR akan digunakan untuk memprediksi regresi pada dua titik data ini serta pada satu titik data tes, misal \([0.5, 0.5]\).
Alurnya yaitu VQR menggunakan sirkuit sistem dua qubit, enkode sudut \(R_x\) dan \(R_y\), ansatz dengan RealAmplitudes, prediksi dengan nilai ekspektasi \(\langle Z \rangle\) pada \(q_0\), dan optimasi parameter \(\theta\) dengan teknik optimasi. Sirkuit implementasi VQR ini disajikan dalam gambar (bagian atas).
RealAmplitudes sendiri ialah ansatz kuantum parametrik dalam pustaka Qiskit Circuit Library yang didesain khusus untuk melatih model kuantum variasional (variational quantum models) seperti VQE dan VQR. Sirkuit kuantum hasil decompose RealAmplitudes ditunjukkan pada gambar (bagian bawah).


Code: VQR
# VQR
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector
from qiskit.circuit.library import RealAmplitudes
from scipy.optimize import minimize
import numpy as np
import matplotlib.pyplot as plt
# Training data
X_train = np.array([[0.0, 0.0], [1.0, 1.0]])
y_train = np.array([0.0, 1.0])
# Scale features to [0, π] for rotation gates
X_train_scaled = X_train * np.pi
# Test point (added at the end)
x_test = np.array([0.5, 0.5]) # Mid-point between [0,0] and [1,1]
x_test_scaled = x_test * np.pi
# y_test_expected = 0.5 # Linear interpolation expectation
# Encoding circuit: RX(x0) on q0, RY(x1) on q1
def encoding_circuit(x):
qc = QuantumCircuit(2)
qc.rx(x[0], 0)
qc.ry(x[1], 1)
return qc
# Ansatz: Hardware-efficient (RealAmplitudes, 1 repetition)
ansatz = RealAmplitudes(num_qubits = 2, reps = 1, entanglement = 'linear')
print(f"Ansatz depth: {ansatz.depth()}, parameters: {ansatz.num_parameters}")
# Full variational circuit: encoding + ansatz
def vqr_circuit(x, theta):
qc = encoding_circuit(x)
qc = qc.compose(ansatz.assign_parameters(theta))
return qc
# Prediction: on qubit 0 → scaled to [0,1]
def predict(x, theta):
qc = vqr_circuit(x, theta)
sv = Statevector.from_instruction(qc)
probs = sv.probabilities()
# _q0 = P(|q0 = 0>) - P(|q0 = 1>) = P00 + P10 - (P01 + P11)
exp_z_q0 = probs[0] + probs[2] - probs[1] - probs[3]
return (exp_z_q0 + 1.0) / 2.0 # Map from [-1,1] to [0,1]
# Loss function: Mean Squared Error
def loss(theta):
predictions = np.array([predict(x, theta) for x in X_train_scaled])
return np.mean((predictions - y_train) ** 2)
# Optimisation using COBYLA
print("\nStarting parameter optimisation...")
initial_theta = np.random.uniform(0, 2 * np.pi, ansatz.num_parameters)
result = minimize(
loss, initial_theta,
method = 'COBYLA',
options = {'maxiter': 300, 'tol': 1e-10}
)
optimal_theta = result.x
final_loss = result.fun
print(f"Optimisation complete.")
print(f"Final loss (MSE): {final_loss:.2e}")
print(f"Optimal parameters: {np.round(optimal_theta, 4)}")
# Final predictions on training data
pred_0 = predict(X_train_scaled[0], optimal_theta)
pred_1 = predict(X_train_scaled[1], optimal_theta)
print(f"\n--- Training Results ---")
print(f"Input [0.0, 0.0] → Prediction: {pred_0:.6f} (target: 0.0)")
print(f"Input [1.0, 1.0] → Prediction: {pred_1:.6f} (target: 1.0)")
# Test point prediction
pred_test = predict(x_test_scaled, optimal_theta)
print(f"\n--- Test Point ---")
print(f"Input {x_test} → Prediction: {pred_test:.6f} (expected ~0.5)")
# Draw and display the quantum circuit
print(f"\nGenerating quantum circuit diagram...")
circuit_with_params = vqr_circuit(x_test_scaled, optimal_theta)
# Draw using matplotlib
fig = circuit_with_params.draw('mpl')
plt.tight_layout()
plt.show()
# Optional: save to file
fig.savefig("vqr_circuit.png")
print("Circuit diagram saved as 'vqr_circuit.png'")
Code: RealAmplitudes
# RealAmplitudes
from qiskit.circuit.library import RealAmplitudes
ansatz = RealAmplitudes(num_qubits = 2, reps = 1, entanglement = 'linear')
ansatz.decompose().draw('mpl')
8.6 Quantum Neural Network
Jaringan saraf tiruan kuantum (Quantum Neural Network, QNN) adalah algoritma pembelajaran mesin kuantum (QML) yang memanfaatkan PQC. Sirkuit QNN berupa lapisan gerbang kuantum yang dikenal sebagai perceptron kuantum, menyerupai struktur dan fungsi perceptron pada jaringan saraf klasik.
Contoh: Implementasi QNN untuk memodelkan dan memprediksi hasil fungsi XOR. Guna implementasi contoh ini, akan digunakan QNN 2-qubit dan QNN 1-qubit.
| \(x_1\) | \(x_2\) | \(x_1 ⊕ x_2\) |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 0 |
8.6.1 QNN 2-Qubit
QNN 2-qubit memiliki dua buah qubit untuk proses peta fitur kuantum, ansatz, optimasi, dan pengukuran.

Qubit \(q_0\) dan \(q_1\) sebagai input, qubit \(q_1\) juga untuk output. Gerbang \(R_x(\pi * x_1)\) pada pada \(q_0\) dan \(R_x(\pi * x_2)\) di \(q_1\) adalah peta fitur kuantum jenis enkode sudut, dan gerbang kuantum selebihnya merupakan ansatz. Parameter \(\theta\) didapat dengan teknik optimasi. Adapun nilai ekspektasi diukur pada state kuantum akhir qubit \(q_1\) atau
\[ \langle Z \rangle = \bra{\psi_{q_1}} Z \ket{\psi_{q_1}} \tag{8.6.1} \]
Berikut disajikan tiga kode Qiskit implementasi QNN 2-qubit dari contoh di atas. Kode pertama, nilai parameter \(\theta\) telah ditentukan yakni sebesar \(\frac{\pi}{6}\). Untuk kode kedua dan ketiga, parameter \(\theta\) dicari dengan teknik optimasi. Adapun visualisasi heatmap implementasi QNN-nya disajikan pada kode ketiga.
Code: 2-Qubit QNN for XOR
# 2-Qubit QNN for XOR
from qiskit import QuantumCircuit
from qiskit.quantum_info import Operator, Statevector
import numpy as np
# Data input for XOR
inputs = [(0, 0), (0, 1), (1, 0), (1, 1)]
# Define Pauli-Z and identity matrices
Z = np.array([[1, 0], [0, -1]])
I = np.eye(2)
# Calculate Z ⊗ I for expectation value
ZI = np.kron(Z, I)
ZI_operator = Operator(ZI)
print("Quantum VQC XOR with Statevector and Expectation Value\n")
for x1, x2 in inputs:
# Initialise quantum circuit with 2 qubits
qc = QuantumCircuit(2)
# Feature map: Angle encoding
qc.rx(np.pi * x1, 0) # Rx rotation based on x1
qc.rx(np.pi * x2, 1) # Rx rotation based on x2
# Ansatz: CNOT gates and Ry rotation
qc.cx(0, 1) # CNOT from qubit 0 to qubit 1
qc.ry(np.pi/6, 1) # Ry(π/6) rotation on qubit 1
# Create statevector from circuit
statevector = Statevector.from_instruction(qc)
# Calculate expectation value
expectation_value = statevector.expectation_value(ZI_operator).real
# Print results
print(f"Input: ({x1}, {x2})")
print("Statevector:", statevector.data)
print(f"Expectation value on q1: {expectation_value}")
print(f"Probability of |0> for q1: {(1 + expectation_value) / 2}")
print(f"Predicted label: {1 if expectation_value < 0 else 0}\n")
Code: Optimised 2-Qubit QNN for XOR
# Optimised 2-Qubit QNN for XOR
from qiskit import QuantumCircuit
from qiskit.quantum_info import Operator, Statevector
import numpy as np
from scipy.optimize import minimize
# Data input for XOR
inputs = [(0, 0), (0, 1), (1, 0), (1, 1)]
# Define Pauli-Z and identity matrices
Z = np.array([[1, 0], [0, -1]])
I = np.eye(2)
# Calculate Z ⊗ I for expectation value
ZI = np.kron(Z, I)
ZI_operator = Operator(ZI)
# Function to create circuit with theta
def get_circuit(x1, x2, theta):
# Initialise quantum circuit with 2 qubits
qc = QuantumCircuit(2)
# Feature map: Angle encoding
qc.rx(np.pi * x1, 0) # Rx rotation based on x1
qc.rx(np.pi * x2, 1) # Rx rotation based on x2
# Ansatz: CNOT gates and Ry rotation
qc.cx(0, 1) # CNOT from qubit 0 to qubit 1
qc.ry(theta, 1) # Theta as a variable parameter
return qc
# Cost function for optimisation
def cost(params):
theta = params[0]
expectation_values = []
# Calculate expectation values for all inputs
for x1, x2 in inputs:
qc = get_circuit(x1, x2, theta)
statevector = Statevector.from_instruction(qc)
expectation_value = statevector.expectation_value(ZI_operator).real
expectation_values.append(expectation_value)
# Objective: maximise separation between input groups
# For example, push (0,0) and (1,1) to positive expectation values,
# and (0,1), (1,0) to negative expectation values
# Cost = - (variance of expectation values) to encourage separation
variance = np.var(expectation_values)
return -variance # Negative to maximise variance
# Run optimisation
initial_params = [0.0] # Initial guess for theta
result = minimize(cost, initial_params, method = 'COBYLA', tol = 1e-6)
optimal_theta = result.x[0]
print(f"Optimal theta: {optimal_theta}")
print(f"Minimum cost (negative variance): {result.fun}\n")
print("Quantum VQC XOR with Statevector and Expectation Value after Unsupervised Optimisation\n")
for x1, x2 in inputs:
qc = get_circuit(x1, x2, optimal_theta)
statevector = Statevector.from_instruction(qc)
expectation_value = statevector.expectation_value(ZI_operator).real
# Print results
print(f"Input: ({x1}, {x2})")
print("Statevector:", statevector.data)
print(f"Expectation value on q1: {expectation_value}")
print(f"Probability of |0> for q1: {(1 + expectation_value) / 2}")
# Predict cluster based on threshold on expectation value
print(f"Predicted cluster: {1 if expectation_value < 0 else 0}\n")
Code: Visualisation of 2-Qubit QNN for XOR
# Visualisation of 2-Qubit QNN for XOR
from qiskit import QuantumCircuit
from qiskit.quantum_info import Operator, Statevector
import numpy as np
from scipy.optimize import minimize
import matplotlib.pyplot as plt
# Data input for XOR (for reference)
inputs = [(0, 0), (0, 1), (1, 0), (1, 1)]
# Define Pauli-Z and identity matrices
Z = np.array([[1, 0], [0, -1]])
I = np.eye(2)
# Calculate Z ⊗ I for expectation value
ZI = np.kron(Z, I)
ZI_operator = Operator(ZI)
# Function to create circuit with theta and continuous input
def get_circuit(x1, x2, theta):
# Initialise quantum circuit with 2 qubits
qc = QuantumCircuit(2)
# Feature map: Angle encoding
qc.rx(np.pi * x1, 0) # Rx rotation based on x1
qc.rx(np.pi * x2, 1) # Rx rotation based on x2
# Ansatz: CNOT gates and Ry rotation
qc.cx(0, 1) # CNOT from qubit 0 to qubit 1
qc.ry(theta, 1) # Theta as a variable parameter
return qc
# Cost function for optimisation
def cost(params):
theta = params[0]
expectation_values = []
# Calculate expectation values for all inputs
for x1, x2 in inputs:
qc = get_circuit(x1, x2, theta)
statevector = Statevector.from_instruction(qc)
expectation_value = statevector.expectation_value(ZI_operator).real
expectation_values.append(expectation_value)
# Objective: maximise separation between input groups
# For example, push (0,0) and (1,1) to positive expectation values,
# and (0,1), (1,0) to negative expectation values
# Cost = - (variance of expectation values) to encourage separation
variance = np.var(expectation_values)
return -variance # Negative to maximise variance
# Run optimisation
initial_params = [0.0] # Initial guess for theta
result = minimize(cost, initial_params, method = 'COBYLA', tol = 1e-6)
optimal_theta = result.x[0]
print(f"Optimal theta: {optimal_theta}")
print(f"Minimum cost (negative variance): {result.fun}\n")
# Create grid for heatmap
n_points = 50 # Grid resolution
x1_range = np.linspace(0, 1, n_points)
x2_range = np.linspace(0, 1, n_points)
X1, X2 = np.meshgrid(x1_range, x2_range)
Z = np.zeros((n_points, n_points)) # To store probability of |1>
# Calculate probabilities for each point in the grid
for i in range(n_points):
for j in range(n_points):
qc = get_circuit(X1[i, j], X2[i, j], optimal_theta)
statevector = Statevector.from_instruction(qc)
expectation_value = statevector.expectation_value(ZI_operator).real
Z[i, j] = (1 - expectation_value) / 2 # Probability of |1>
# Create heatmap
plt.figure(figsize = (6, 4))
plt.gcf().set_facecolor('#f5f5f5')
plt.contourf(X1, X2, Z, cmap = 'viridis', levels = 50)
plt.colorbar(label = 'Probability of |1> (XOR output)')
plt.scatter([0, 0, 1, 1], [0, 1, 0, 1], c = 'red', marker = 'x', s = 100, label = 'XOR Inputs')
plt.xlabel('x1')
plt.ylabel('x2')
plt.title('2-Qubit QNN for XOR')
plt.legend()
plt.grid(True)
plt.show()
# Print results for discrete inputs
print("Quantum VQC XOR with Statevector and Expectation Value after Unsupervised Optimisation\n")
for x1, x2 in inputs:
qc = get_circuit(x1, x2, optimal_theta)
statevector = Statevector.from_instruction(qc)
expectation_value = statevector.expectation_value(ZI_operator).real
print(f"Input: ({x1}, {x2})")
print("Statevector:", statevector.data)
print(f"Expectation value on q1: {expectation_value}")
print(f"Probability of |1> for q1: {(1 - expectation_value) / 2}")
print(f"Predicted cluster: {1 if expectation_value < 0 else 0}\n")

8.6.2 QNN 1-Qubit
QNN 1-qubit hanya membutuhkan satu buah qubit untuk implementasi pemodelan dan prediksi hasil fungsi XOR. Gerbang \(H\), gerbang \(R_z\), dan gerbang \(R_x\).

Gerbang \(H\) untuk superposisi, dan gerbang \(R_z(\theta_1 * x_1 + \alpha)\) serta \(R_x(\theta_2 * x_2 + \alpha)\) dua-duanya berperan sekaligus sebagai peta fitur kuantum juga ansatz. Ia disebut peta fitur kuantum karena pada gerbang rotasinya ada variabel \(x\), yakni \([x_1, x_2]\). Variabel \(x\) dipetakan ke ruang fitur kuantum. Ia juga dinamakan ansatz karena memiliki variabel parametrik \(\theta\) dan \(\alpha\) guna optimasi. Adapun nilai ekspektasi sebesar
\[ \langle Z \rangle = \bra{\psi_{q}} Z \ket{\psi_{q}} \tag{8.6.2} \]
Code: 1-Qubit QNN for XOR
# Code: 1-Qubit QNN for XOR
from qiskit import QuantumCircuit
from qiskit.quantum_info import Operator, Statevector
import numpy as np
# Data input for XOR
inputs = [(0, 0), (0, 1), (1, 0), (1, 1)]
# Define Pauli-Z
Z = np.array([[1, 0], [0, -1]])
print("Quantum VQC XOR with Statevector and Expectation Value\n")
# Parameters
theta1 = np.pi
theta2 = np.pi
alpha = - np.pi / 2
for x1, x2 in inputs:
# Initialise quantum circuit
qc = QuantumCircuit(1)
# Superposition
qc.h(0)
# Feature map and ansatz
qc.rz(theta1 * x1 + alpha, 0)
qc.rx(theta2 * x2 + alpha, 0)
# Create statevector from circuit
statevector = Statevector.from_instruction(qc)
# Calculate expectation value
expectation_value = statevector.expectation_value(Z).real
# Print results
print(f"Input: ({x1}, {x2})")
print("Statevector:", statevector.data)
print(f"Expectation value: {expectation_value}")
print(f"Probability of |0>: {(1 + expectation_value) / 2}")
print(f"Predicted label: {1 if expectation_value < 0 else 0}\n")
Code: Optimised 1-Qubit QNN for XOR
# Code: Optimised 1-Qubit QNN for XOR
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector
import numpy as np
from scipy.optimize import minimize
# XOR input data (binary combinations)
inputs = [(0, 0), (0, 1), (1, 0), (1, 1)]
# Pauli-Z observable
Z = np.array([[1, 0], [0, -1]])
# Function to construct the quantum circuit
def get_circuit(x1, x2, theta1, theta2, alpha):
qc = QuantumCircuit(1)
qc.h(0) # Create superposition
qc.rz(theta1 * x1 + alpha, 0) # Feature map and ansatz
qc.rx(theta2 * x2 + alpha, 0) # Feature map and ansatz
return qc
# Cost function
def cost(params):
theta1, theta2, alpha = params
# Group inputs: same vs different values
same_inputs = [(0, 0), (1, 1)] # Inputs where x₁ == x₂
diff_inputs = [(0, 1), (1, 0)] # Inputs where x₁ ≠ x₂
exp_same = []
exp_diff = []
# Calculate expectation values for inputs with same values
for x1, x2 in same_inputs:
qc = get_circuit(x1, x2, theta1, theta2, alpha)
statevector = Statevector.from_instruction(qc)
ev = statevector.expectation_value(Z).real
exp_same.append(ev)
# Calculate expectation values for inputs with differing values
for x1, x2 in diff_inputs:
qc = get_circuit(x1, x2, theta1, theta2, alpha)
statevector = Statevector.from_instruction(qc)
ev = statevector.expectation_value(Z).real
exp_diff.append(ev)
# Aim: maximise separation between the two groups
mean_same = np.mean(exp_same)
mean_diff = np.mean(exp_diff)
separation = (mean_same - mean_diff) ** 2 # Larger is better
cost_value = -separation # Minimise negative separation
return cost_value
# Perform parameter optimisation
initial_params = np.random.uniform(-np.pi, np.pi, 3)
result = minimise = minimize(cost, initial_params, method = 'COBYLA', tol = 1e-6)
# Extract optimal parameters
theta1_opt, theta2_opt, alpha_opt = result.x
# Report optimisation result
print(f"Optimisation successful: {result.success}")
print(f"Number of function evaluations: {result.nfev}")
print(f"Optimal θ₁: {theta1_opt}")
print(f"Optimal θ₂: {theta2_opt}")
print(f"Optimal α : {alpha_opt}")
print(f"Final cost value (−separation²): {result.fun:.6f}\n")
# Evaluate final circuit behaviour for all XOR inputs
print("Final circuit behaviour for all XOR input combinations:\n")
for x1, x2 in inputs:
qc = get_circuit(x1, x2, theta1_opt, theta2_opt, alpha_opt)
statevector = Statevector.from_instruction(qc)
ev = statevector.expectation_value(Z).real
prob_0 = (1 + ev) / 2 # Probability of measuring |0⟩
predicted_label = 1 if ev < 0 else 0
print(f"Input: ({x1}, {x2})")
print(f" Expectation value ⟨Z⟩: {ev:.4f}")
print(f" Probability of measuring |0⟩: {prob_0:.4f}")
print(f" Predicted label: {predicted_label}\n")
Code: Visualisation of 1-Qubit QNN for XOR
# Code: Visualisation of 1-Qubit QNN for XOR
from qiskit import QuantumCircuit
from qiskit.quantum_info import Operator, Statevector
import numpy as np
from scipy.optimize import minimize
import matplotlib.pyplot as plt
# XOR input data
inputs = [(0, 0), (0, 1), (1, 0), (1, 1)]
# Pauli-Z observable operator
Z_op = np.array([[1, 0], [0, -1]])
# Function to build a quantum circuit with parameters theta1, theta2, alpha
def get_circuit(x1, x2, theta1, theta2, alpha):
qc = QuantumCircuit(1)
qc.h(0) # Superposition
qc.rz(theta1 * x1 + alpha, 0) # Feature map and ansatz
qc.rx(theta2 * x2 + alpha, 0) # Feature map and ansatz
return qc
# Cost function
def cost(params):
theta1, theta2, alpha = params
same_group = [(0, 0), (1, 1)] # Inputs with x1 == x2
diff_group = [(0, 1), (1, 0)] # Inputs with x1 ≠ x2
exp_same = []
exp_diff = []
for x1, x2 in same_group:
qc = get_circuit(x1, x2, theta1, theta2, alpha)
statevector = Statevector.from_instruction(qc)
ev = statevector.expectation_value(Z_op).real
exp_same.append(ev)
for x1, x2 in diff_group:
qc = get_circuit(x1, x2, theta1, theta2, alpha)
statevector = Statevector.from_instruction(qc)
ev = statevector.expectation_value(Z_op).real
exp_diff.append(ev)
# Maximise the squared difference between the group means
separation = (np.mean(exp_same) - np.mean(exp_diff)) ** 2
return -separation # Negated for minimisation
# Optimisation of parameters
initial_params = np.random.uniform(-np.pi, np.pi, 3)
print(f"Initial parameters: {initial_params}")
result = minimize(cost, initial_params, method = 'COBYLA', tol = 1e-6)
# Optimisation results
print(f"\nOptimisation successful: {result.success}")
print(f"Number of function evaluations: {result.nfev}")
optimal_theta1, optimal_theta2, optimal_alpha = result.x
print(f"Optimal θ₁: {optimal_theta1}")
print(f"Optimal θ₂: {optimal_theta2}")
print(f"Optimal α : {optimal_alpha}")
print(f"Maximum group separation²: {-result.fun:.6f}\n")
# Create input grid for visualisation
n_points = 50
x1_range = np.linspace(0, 1, n_points)
x2_range = np.linspace(0, 1, n_points)
X1, X2 = np.meshgrid(x1_range, x2_range)
Z_grid = np.zeros((n_points, n_points)) # Holds output probabilities for |1⟩
# Evaluate the circuit on each point in the grid
for i in range(n_points):
for j in range(n_points):
qc = get_circuit(X1[i, j], X2[i, j], optimal_theta1, optimal_theta2, optimal_alpha)
statevector = Statevector.from_instruction(qc)
exp_val = statevector.expectation_value(Z_op).real
Z_grid[i, j] = (1 - exp_val) / 2 # Probability of measuring |1⟩
# Plot visualisation with light background
plt.figure(figsize = (6, 4))
plt.gcf().set_facecolor('#f5f5f5') # Figure background
plt.gca().set_facecolor('#f5f5f5') # Plot area background
contour = plt.contourf(X1, X2, Z_grid, cmap = 'YlGnBu', levels = 50)
plt.colorbar(contour, label='Probability of |1⟩ (XOR output)')
plt.scatter([0, 0, 1, 1], [0, 1, 0, 1], c = 'red', marker = 'x', s = 100, label = 'XOR Inputs')
plt.xlabel('x1')
plt.ylabel('x2')
plt.title('1-Qubit QNN for XOR')
plt.legend()
plt.grid(True)
plt.show()
# Final predictions for all XOR inputs using optimised parameters
print("Final predictions using optimised parameters:\n")
for x1, x2 in inputs:
qc = get_circuit(x1, x2, optimal_theta1, optimal_theta2, optimal_alpha)
statevector = Statevector.from_instruction(qc)
exp_val = statevector.expectation_value(Z_op).real
prob_1 = (1 - exp_val) / 2
predicted_label = 1 if exp_val < 0 else 0
print(f"Input: ({x1}, {x2})")
print(f" Statevector: {statevector.data}")
print(f" Expectation value ⟨Z⟩: {exp_val:.4f}")
print(f" Probability of |1⟩: {prob_1:.4f}")
print(f" Predicted label: {predicted_label}\n")

8.7 Quantum Convolutional Neural Network
Pada subbab Quantum Convolutional Neural Network (QCNN) ini akan disajikan implementasi QCNN pada dataset untuk klasifikasi pola gambar 3×3 pixel. Adapun dataset yang dimaksud yakni dataset "3x3 Pixel Pattern Classification Dataset: 12 Adjacent Pair Classes" — https://doi.org/10.5281/zenodo.17576072. Sebuah dataset untuk klasifikasi pola gambar kecil (3×3 pixel), di mana setiap gambar merepresentasikan pola hubungan antara pasangan piksel yang berdekatan (adjacent pair). Total ada 12 kategori kelas yang berbeda, berdasarkan pola adjacency (kedekatan) di dalam blok 3×3 tersebut.

Untuk contoh implementasi QCNN ini dipilih dua kelas, yakni kelas 1 (gambar atas paling kiri - Horizontal r1c1 - r1c2) dan kelas 2 (gambar atas nomor 2 dari kiri - Horizontal r1c2 - r1c3). Masing-masing kelas terdiri atas 80 data latih dan 20 data tes.

Gambar di atas menunjukkan sirkuit kuantum implementasi QCNN untuk klasifikasi pola gambar 3x3 pixel. Sirkuit terdiri atas 9 qubit, enkode sudut \(R_y\), lapisan konvolusi pertama (melibatkan gerbang \(CX\) dan \(R_y\)), serta lapisan konvolusi kedua (gerbang \(CX\) dan \(R_z\)). Untuk implementasi ini, nilai parameter optimal \(\theta\) telah ditentukan sebelumnya, yakni \(\pi / 4\) untuk lapisan pertama dan \(\pi / 3\) untuk lapisan kedua. Detail langkah demi langkah implementasi QCNN disajikan dalam kode berikut.
Code: QCNN for 3x3 Pixel Pattern Classification
# Code: QCNN for 3x3 Pixel Pattern Classification
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector, Pauli, SparsePauliOp
from PIL import Image
import numpy as np
import glob, os
# Load image and convert to feature vector
def load_image_as_features(path, size=(3, 3)):
"""
Open a greyscale image, resize to `size`, normalise to [0, 1]
and scale to [0, π] (suitable for RY rotations).
"""
img = Image.open(path).convert('L') # convert to greyscale
img = img.resize(size, Image.NEAREST) # keep pixel-perfect values
arr = np.asarray(img, dtype = np.float32) / 255.0
return (arr.flatten() * np.pi) # feature vector in [0, π]
# Construct a minimal QCNN circuit
def build_qcnn_circuit(features):
"""
Create a QuantumCircuit with:
• RY rotations according to the feature vector
• a chain of CX + RY(π/4) gates
• a second layer of CX + RZ(π/3) gates (stride 3)
"""
n = len(features)
qc = QuantumCircuit(n, name = 'QCNN')
# Encode features
for i, f in enumerate(features):
qc.ry(f, i)
# First convolution layer
for i in range(n - 1):
qc.cx(i, i + 1)
qc.ry(np.pi / 4, i + 1)
qc.barrier()
# Second convolution layer (stride 3)
for i in range(0, n, 3):
if i + 2 < n:
qc.cx(i, i + 2)
qc.rz(np.pi / 3, i)
return qc
# Expectation value of Pauli-Z on a single qubit
def expectation_Z(state, qubit, num_qubits):
"""
Compute ⟨ψ| Z_q |ψ⟩ where Z_q acts on `qubit` and identity elsewhere.
"""
op = SparsePauliOp(Pauli('I' * qubit + 'Z' + 'I' * (num_qubits - qubit - 1)))
return np.real(state.expectation_value(op))
# Full QCNN forward pass for one image
def qcnn_output_from_image(img_path):
"""
Return the average ⟨Z⟩ over selected observable qubits.
For 9-pixel images we measure qubits 0, 3 and 6.
"""
features = load_image_as_features(img_path)
qc = build_qcnn_circuit(features)
state = Statevector.from_instruction(qc)
obs_qubits = [0, 3, 6] if len(features) >= 9 else [0]
return np.mean([expectation_Z(state, q, len(features)) for q in obs_qubits])
# Dataset paths
train_class1_folder = ".../train/h_r1c1_r1c2" # class 1
train_class2_folder = ".../train/h_r1c2_r1c3" # class 2
test_folder = ".../test/..." # unlabelled
train_class1_images = glob.glob(os.path.join(train_class1_folder, "*.png"))
train_class2_images = glob.glob(os.path.join(train_class2_folder, "*.png"))
test_images = glob.glob(os.path.join(test_folder, "*.png"))
print(f"Train class 1: {len(train_class1_images)} images")
print(f"Train class 2: {len(train_class2_images)} images")
print(f"Test (unlabelled): {len(test_images)} images")
# Compute QCNN outputs for training data
print("\nComputing QCNN outputs for training images...")
train_outputs_class1 = [qcnn_output_from_image(p) for p in train_class1_images]
train_outputs_class2 = [qcnn_output_from_image(p) for p in train_class2_images]
class_means = {
1: np.mean(train_outputs_class1),
2: np.mean(train_outputs_class2)
}
print("Class centroid (mean) outputs:", class_means)
# QCNN outputs for test images
print("\nProcessing test images...")
test_outputs = [qcnn_output_from_image(p) for p in test_images]
# Classification with OOD threshold
threshold = 0.3 # maximum distance to a centroid to be considered known
predictions = []
for out in test_outputs:
dist1 = abs(out - class_means[1])
dist2 = abs(out - class_means[2])
min_dist = min(dist1, dist2)
if min_dist > threshold:
pred = 0 # out-of-distribution / unknown
else:
pred = 1 if dist1 < dist2 else 2
predictions.append(pred)
# Display results
results = [(os.path.basename(p), pred) for p, pred in zip(test_images, predictions)]
print("\n=== QCNN Test Predictions ===")
for name, pred_lbl in results:
if pred_lbl == 0:
label_str = "Unknown ?"
else:
label_str = f"Class {pred_lbl}"
print(f"{name:25s} | Predicted: {label_str}")
Referensi
D. McMahon, Quantum Computing Explained, 1st ed., New Jersey: John Wiley & Sons, Inc., 2008.
E. Rieffel dan W. Polak, Quantum Computing A Gentle Introduction, 1st ed., Cambridge: The MIT Press,
2011.
M. Nielsen dan I. Chuang, Quantum Computation and Quantum Information, Cambridge: Cambridge
University Press, 2010.
N. Zettili, Quantum Mechanics Concepts and Applications, 2nd ed., West Sussex: John Wiley & Sons,
Ltd, 2009.
S. Kurgalin dan S. Borzunov, Concise Guide to Quantum Computing Algorithms, Exercises, and
Implementations, Cham: Springer, 2021.
I. Grossu, Single Qubit Neural Quantum Circuit for Solving Exclusive-OR, MethodsX 8, 101573,
2021.
A. Chatterjee, K. Phalak, dan S. Ghosh, Quantum Error Correction For Dummies, arXiv:2304.08678.
E. Strubell, An Introduction to Quantum Algorithms, Github. URL: https://strubell.github.io.
M. Christandl, M. Ozols, M. Walter, dan F. Witteveen, Quantum Information Theory. URL: https://qi.rub.de.
O. Simeone, An Introduction to Quantum Machine Learning for Engineers, arXiv:2205.09510.
IBM Quantum Learning. URL: https://learning.quantum.ibm.com.
MathWorks, Solve XOR Problem Using Quantum Neural Network (QNN). URL:
https://www.mathworks.com.
M. Nur Hidayat dan M. Faruq Nuruddinsyah, 3x3 Pixel Pattern Classification Dataset: 12 Adjacent Pair Classes [Dataset].
Pi Quantum. URL: https://doi.org/10.5281/zenodo.17576072.