From ae36504db4dc6f2cab9874d05cb95ce24ecc5f7b Mon Sep 17 00:00:00 2001 From: Rochisha Agarwal Date: Fri, 25 Apr 2025 11:09:37 +0530 Subject: [PATCH 1/7] add error correction codes --- src/qutip_qip/algorithms/__init__.py | 1 + .../algorithms/error_correction/bit_flip.py | 112 ++++++++++++++++++ 2 files changed, 113 insertions(+) create mode 100644 src/qutip_qip/algorithms/error_correction/bit_flip.py diff --git a/src/qutip_qip/algorithms/__init__.py b/src/qutip_qip/algorithms/__init__.py index f1c4bc07..4971be21 100644 --- a/src/qutip_qip/algorithms/__init__.py +++ b/src/qutip_qip/algorithms/__init__.py @@ -1 +1,2 @@ from .qft import * +from .error_correction.bit_flip import * \ No newline at end of file diff --git a/src/qutip_qip/algorithms/error_correction/bit_flip.py b/src/qutip_qip/algorithms/error_correction/bit_flip.py new file mode 100644 index 00000000..8e5012f9 --- /dev/null +++ b/src/qutip_qip/algorithms/error_correction/bit_flip.py @@ -0,0 +1,112 @@ +# bit_flip_code.py + +import numpy as np +from qutip import Qobj, tensor, basis, sigmax, sigmay +from qutip_qip.operations import Gate +from qutip_qip.circuit import QubitCircuit + +__all__ = ["BitFlipCode"] + +class BitFlipCode: + """ + Implementation of the 3-qubit bit-flip code. + + The bit-flip code protects against X (bit-flip) errors by encoding + a single logical qubit across three physical qubits: + |0⟩ → |000⟩ + |1⟩ → |111⟩ + """ + + @staticmethod + def encode_circuit(): + """ + Create a circuit for encoding a single qubit into the 3-qubit bit-flip code. + + Returns + ------- + qc : instance of QubitCircuit + Encoding circuit for the bit-flip code. + """ + qc = QubitCircuit(3) + qc.add_gate("CNOT", controls=0, targets=1) + qc.add_gate("CNOT", controls=0, targets=2) + return qc + + @staticmethod + def syndrome_measurement_circuit(): + """ + Create a circuit for syndrome measurement of the 3-qubit bit-flip code. + + Returns + ------- + qc : instance of QubitCircuit + Syndrome measurement circuit that uses two ancilla qubits. + """ + qc = QubitCircuit(5) # 3 data qubits + 2 syndrome qubits + + # First syndrome measurement: Parity of qubits 0 and 1 + qc.add_gate("CNOT", controls=0, targets=3) + qc.add_gate("CNOT", controls=1, targets=3) + + # Second syndrome measurement: Parity of qubits 1 and 2 + qc.add_gate("CNOT", controls=1, targets=4) + qc.add_gate("CNOT", controls=2, targets=4) + + return qc + + @staticmethod + def correction_circuit(syndrome): + """ + Create a circuit for error correction based on syndrome measurement. + + Parameters + ---------- + syndrome : tuple + Two-bit syndrome measurement result (s1, s2). + + Returns + ------- + qc : instance of QubitCircuit + Correction circuit applying X gates as needed. + """ + qc = QubitCircuit(3) + s1, s2 = syndrome + + # Syndrome interpretation: + # s1=0, s2=0: No error + # s1=1, s2=0: Error on qubit 0 + # s1=1, s2=1: Error on qubit 1 + # s1=0, s2=1: Error on qubit 2 + + if s1 == 1 and s2 == 0: + # Error on qubit 0 + qc.add_gate("X", targets=0) + elif s1 == 1 and s2 == 1: + # Error on qubit 1 + qc.add_gate("X", targets=1) + elif s1 == 0 and s2 == 1: + # Error on qubit 2 + qc.add_gate("X", targets=2) + + return qc + + @staticmethod + def decode_circuit(): + """ + Create a circuit for decoding the 3-qubit bit-flip code. + + Returns + ------- + qc : instance of QubitCircuit + Decoding circuit for the bit-flip code. + """ + qc = QubitCircuit(3) + qc.add_gate("CNOT", controls=0, targets=2) + qc.add_gate("CNOT", controls=0, targets=1) + + # Add a Toffoli gate to verify the parity + # If all qubits have the same value, the result is stored in qubit 0 + qc.add_gate("TOFFOLI", controls=[1, 2], targets=0) + + return qc + \ No newline at end of file From 1dc36da6d70861699e5008d5c68efef8af501681 Mon Sep 17 00:00:00 2001 From: Rochisha Agarwal Date: Mon, 28 Apr 2025 12:34:37 +0530 Subject: [PATCH 2/7] add error correction codes --- .../algorithms/error_correction/phase_flip.py | 130 ++++++++++++++++++ .../algorithms/error_correction/shor_code.py | 65 +++++++++ 2 files changed, 195 insertions(+) create mode 100644 src/qutip_qip/algorithms/error_correction/phase_flip.py create mode 100644 src/qutip_qip/algorithms/error_correction/shor_code.py diff --git a/src/qutip_qip/algorithms/error_correction/phase_flip.py b/src/qutip_qip/algorithms/error_correction/phase_flip.py new file mode 100644 index 00000000..dfa93699 --- /dev/null +++ b/src/qutip_qip/algorithms/error_correction/phase_flip.py @@ -0,0 +1,130 @@ +import numpy as np +from qutip import Qobj, tensor, basis, sigmax, sigmay, sigmaz +from qutip_qip.operations import Gate +from qutip_qip.circuit import QubitCircuit + +__all__ = ["PhaseFlipCode"] + +class PhaseFlipCode: + """ + Implementation of the 3-qubit phase-flip code. + The phase-flip code protects against Z (phase-flip) errors by encoding + a single logical qubit across three physical qubits: + |0⟩ → |+++⟩ + |1⟩ → |---⟩ + + This is accomplished by applying Hadamard gates to transform the bit-flip code + into the phase-flip code, as phase errors in the Hadamard basis appear as bit-flips. + """ + + @staticmethod + def encode_circuit(): + """ + Create a circuit for encoding a single qubit into the 3-qubit phase-flip code. + + Returns + ------- + qc : instance of QubitCircuit + Encoding circuit for the phase-flip code. + """ + qc = QubitCircuit(3) + + # First apply Hadamard to the input qubit + qc.add_gate("SNOT", targets=0) + + # Then use the bit-flip encoding structure + qc.add_gate("CNOT", controls=0, targets=1) + qc.add_gate("CNOT", controls=0, targets=2) + + # Apply Hadamard gates to all qubits + qc.add_gate("SNOT", targets=0) + qc.add_gate("SNOT", targets=1) + qc.add_gate("SNOT", targets=2) + + return qc + + @staticmethod + def syndrome_measurement_circuit(): + """ + Create a circuit for syndrome measurement of the 3-qubit phase-flip code. + + Returns + ------- + qc : instance of QubitCircuit + Syndrome measurement circuit that uses two ancilla qubits. + """ + qc = QubitCircuit(5) # 3 data qubits + 2 syndrome qubits + + qc.add_gate("SNOT", targets=0) + qc.add_gate("SNOT", targets=1) + qc.add_gate("SNOT", targets=2) + + qc.add_gate("CNOT", controls=0, targets=3) + qc.add_gate("CNOT", controls=1, targets=3) + + qc.add_gate("CNOT", controls=1, targets=4) + qc.add_gate("CNOT", controls=2, targets=4) + + qc.add_gate("SNOT", targets=0) + qc.add_gate("SNOT", targets=1) + qc.add_gate("SNOT", targets=2) + + return qc + + @staticmethod + def correction_circuit(syndrome): + """ + Create a circuit for error correction based on syndrome measurement. + + Parameters + ---------- + syndrome : tuple + Two-bit syndrome measurement result (s1, s2). + + Returns + ------- + qc : instance of QubitCircuit + Correction circuit applying Z gates as needed. + """ + qc = QubitCircuit(3) + s1, s2 = syndrome + + # Syndrome interpretation: + # s1=0, s2=0: No error + # s1=1, s2=0: Error on qubit 0 + # s1=1, s2=1: Error on qubit 1 + # s1=0, s2=1: Error on qubit 2 + + if s1 == 1 and s2 == 0: + qc.add_gate("Z", targets=0) + elif s1 == 1 and s2 == 1: + qc.add_gate("Z", targets=1) + elif s1 == 0 and s2 == 1: + qc.add_gate("Z", targets=2) + + return qc + + @staticmethod + def decode_circuit(): + """ + Create a circuit for decoding the 3-qubit phase-flip code. + + Returns + ------- + qc : instance of QubitCircuit + Decoding circuit for the phase-flip code. + """ + qc = QubitCircuit(3) + + qc.add_gate("SNOT", targets=0) + qc.add_gate("SNOT", targets=1) + qc.add_gate("SNOT", targets=2) + + qc.add_gate("CNOT", controls=0, targets=2) + qc.add_gate("CNOT", controls=0, targets=1) + + qc.add_gate("TOFFOLI", controls=[1, 2], targets=0) + + qc.add_gate("SNOT", targets=0) + + return qc \ No newline at end of file diff --git a/src/qutip_qip/algorithms/error_correction/shor_code.py b/src/qutip_qip/algorithms/error_correction/shor_code.py new file mode 100644 index 00000000..a573b5ee --- /dev/null +++ b/src/qutip_qip/algorithms/error_correction/shor_code.py @@ -0,0 +1,65 @@ +import numpy as np +from qutip import Qobj, tensor, basis, sigmax, sigmay, sigmaz +from qutip_qip.operations import Gate +from qutip_qip.circuit import QubitCircuit + +__all__ = ["ShorCode"] + +class ShorCode: + """ + Implementation of the 9-qubit Shor code. + + The Shor code protects against arbitrary single-qubit errors by combining + the 3-qubit phase-flip code with the 3-qubit bit-flip code. + + The logical states are encoded as: + |0⟩ → (|000⟩ + |111⟩)(|000⟩ + |111⟩)(|000⟩ + |111⟩) / 2√2 + |1⟩ → (|000⟩ - |111⟩)(|000⟩ - |111⟩)(|000⟩ - |111⟩) / 2√2 + + This encoding allows correction of any single-qubit error (bit-flip, phase-flip, + or both) on any of the 9 physical qubits. + """ + + @staticmethod + def encode_circuit(): + """ + Create a circuit for encoding a single qubit into the 9-qubit Shor code. + + The encoding process: + 1. Apply phase-flip encoding to the input (creating |+++⟩ or |---⟩) + 2. Apply bit-flip encoding to each of the three qubits + + Returns + ------- + qc : instance of QubitCircuit + Encoding circuit for the Shor code. + """ + qc = QubitCircuit(9) + + # Step 1: Phase-flip encoding on the first qubit + # Apply Hadamard to the input qubit + qc.add_gate("SNOT", targets=0) + + # Create the GHZ-like state by using CNOTs + qc.add_gate("CNOT", controls=0, targets=3) + qc.add_gate("CNOT", controls=0, targets=6) + + # Apply Hadamard to all three qubits + qc.add_gate("SNOT", targets=0) + qc.add_gate("SNOT", targets=3) + qc.add_gate("SNOT", targets=6) + + # Step 2: Bit-flip encoding for each of the three blocks + # First block: qubits 0,1,2 + qc.add_gate("CNOT", controls=0, targets=1) + qc.add_gate("CNOT", controls=0, targets=2) + + # Second block: qubits 3,4,5 + qc.add_gate("CNOT", controls=3, targets=4) + qc.add_gate("CNOT", controls=3, targets=5) + + # Third block: qubits 6,7,8 + qc.add_gate("CNOT", controls=6, targets=7) + qc.add_gate("CNOT", controls=6, targets=8) + + return qc \ No newline at end of file From f5c0281bec54999baded2f5323bad245f07c06b9 Mon Sep 17 00:00:00 2001 From: Rochisha Agarwal Date: Mon, 5 May 2025 15:46:51 +0530 Subject: [PATCH 3/7] add tests --- Untitled.ipynb | 136 ++++++++++++++++++++++ src/qutip_qip/algorithms/__init__.py | 4 +- src/qutip_qip/algorithms/untitled.ipynb | 134 +++++++++++++++++++++ src/qutip_qip/circuit/__init__.py | 2 +- src/qutip_qip/circuit/circuit.py | 2 + src/qutip_qip/circuit/circuitsimulator.py | 5 +- src/qutip_qip/circuit/optimise.py | 82 +++++++++++++ tests/test_bit_flip.py | 82 +++++++++++++ tests/test_phase_flip.py | 127 ++++++++++++++++++++ tests/test_shor_code.py | 44 +++++++ 10 files changed, 614 insertions(+), 4 deletions(-) create mode 100644 Untitled.ipynb create mode 100644 src/qutip_qip/algorithms/untitled.ipynb create mode 100644 src/qutip_qip/circuit/optimise.py create mode 100644 tests/test_bit_flip.py create mode 100644 tests/test_phase_flip.py create mode 100644 tests/test_shor_code.py diff --git a/Untitled.ipynb b/Untitled.ipynb new file mode 100644 index 00000000..cd69be0d --- /dev/null +++ b/Untitled.ipynb @@ -0,0 +1,136 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 9, + "id": "2693ed1c-1af0-4667-a776-bbf727fff1f8", + "metadata": {}, + "outputs": [], + "source": [ + "from qutip_qip.algorithms import qft_gate_sequence" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "521f488b-fc92-4ceb-9e9c-720b30e5f753", + "metadata": {}, + "outputs": [], + "source": [ + "qc = qft_gate_sequence(N=2)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "ba97064a-81ea-4b0a-a3cd-d113cd789bef", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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b0mQQiGGUiGBsvGz97UYihbLlI3LdFoZ9Fo55HJ23O4oj8cDq93lk1RY7U44XR44XW7vh9MDh8sNp9MNp9v7+sp1Lpe7cZsW61weOJwt1rk83mM0rne4PPB0cZYiEgFSiRhSqRgyiRgSiQiyxtdSiRhSiaiVdaLG9WLIpC3WtdineZ1YBJlUDLlUgijV5Rt9pVwS8TI3IiKitjBRICIiIiIiP3z0SkREREREfpgoEBERERGRHyYKRERERETkh4kCERERERH5YaJARERERER+mCgQEREREZEfJgpEREREROSHiQIREREREflhokBERERERH6YKBARERERkR8mCkRERERE5IeJAhERERER+WGiQEREREREfpgoEBERERGRHyYKRERERETkh4kCERERERH5YaJARERERER+mCgQEREREZEfJgpEREREROSHiQIREREREflhokBERERERH6YKBARERERkR8mCkRERERE5IeJAhERERER+WGiQEREREREfpgoEBERERGRHyYKRERERETkh4kCERERERH5YaJARERERER+mCgQEREREZGf/w9M7fAmx/+pvwAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "qc" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "8ffd2e9f-d2a0-4119-9339-58389484ca45", + "metadata": {}, + "outputs": [], + "source": [ + "from qutip_qip.algorithms import qpe" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "51e7662e-0ffb-4035-bb83-ae410e8cc4c8", + "metadata": {}, + "outputs": [], + "source": [ + "from qutip import Qobj, basis\n", + "import numpy as np\n", + "theta1 = 0.25 # 1/4 (corresponds to π/2 phase)\n", + "U1 = Qobj([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, np.exp(1j * np.pi/4)]])\n", + " # |1⟩ is an eigenstate of this operator\n", + "eigenstate1 = basis(2, 1)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "94294b6f-b32a-4fc0-b1a3-fab7cad3d750", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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++yzm9z2nHPOUdeuXbV27VotXLiwyW08Hk+jZRdeeKGef/55bdiwQeXl5SotLdWSJUt02223yeFwBG3bs2fPhvdqx44dkqSzzjqrUb3NpqSmpuqvf/2rNmzYoKqqKhUWFuqdd95p9N5FKtokbbIptEkAAAAgOlB2AIgwp59+uiTpq6++avYs0zNnztR1112n4uJizZ07V0lJSTr77LM1adIk/ehHP9Kzzz7b5H5/+9vfNGXKFC1atEh79+7VxIkT9dxzz+ngwYN67733Grb74IMPGpIDF1xwgbp06aK3335bFRUVDdts3br1uDFefvnleuihh7R+/XrNnTtXOTk5GjNmjPr27au1a9dKkk455RR99tlnSk5O1jfffKPt27drzJgxuvPOO3XBBRdo3LhxKi8vb9ZrEkrDhw/Xxx9/rE6dOmnTpk2aM2eOunfvrptuuknnn3++TjvttKBJgmJiYvTJJ59ozJgx2r59u2bNmqWBAwfq/fff17p16xodv/49/+KLL1oU13PPPaeMjAytWLFCK1asUGJiosaMGaNHHnlEkydP1hVXXNGwbUVFRUNtzaSkJF199dU6cOCAPvjgg+M+R7du3fTZZ5+pf//+2rlzp+bNm6esrCxdeumlOu+883T22WdryZIlLYq7o6FN0iabizYJAAAARCADgOXmzp1rSArJ7f777zcMwzAeeeSRZm1/2WWXGYZhGFu2bDGys7Mblo8bN87weDxGRUWF0alTp6B9Pv/8c8MwDGPHjh1Gjx49Gpb/7Gc/MwzDMN5///1jPl/9vj179mxWfPXbu91uY+rUqUHrsrOzjb59+zY8XrFihWEYhnHHHXc0LHM6ncbbb79tGIZhPPjgg8d8nhdeeMEwDMOYOHFis19rwzCM7du3H3cbp9NpbN682TAMw7jnnnuC1l133XVNvv933HGHYRiG8fHHHxsxMTENyx9++OGGv5kj43z99dcNwzCMO++8s0V/K//3f/9npKenBy2LjY01PvnkE8MwDOOMM85ocr+ePXsahmEYn3/+ebPfv8cee8xwOp0Ny8844wyjpqbGWLNmTcj+9iUZBw4caGtzNAzDMJYsWRKymGiTtMnm3iKxTa5evbqtzREAAADo0Cg7AESY+kt5y8rKmrV9/aXFf/zjH1VQUNCw/JtvvtErr7yixMREXXvttU3u++CDD2rXrl0N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AACQnFYHYJX77rtP06ZNU2xsrCZNmqSYmBh98cUXmjx5skaNGiVJOvnkky2OEtEkKyvL6hCADi3UbYg2CbQNbQgAAACI0uTra6+9pmnTpmn06NGaNWuWunXrJknavXu3Ro8erffee0+xsbEaMmSIxZEimmRmZlodAtChhboN0SaBtqENAQAAAFFYdqC8vFy33XabUlNTNWfOnIbEqyR1795dN998syRp6NChcjrrctNvvvmmLrroIuXk5Cg1NVUTJkzQokWLLIkfkYsRQkDbMPIVCC+0IQAAACAKk6/PPvusioqKdNtttyknJ6fR+n79+kkKLjnwz3/+U1lZWXr88cf11ltvqWvXrjr77LO1atWqdosbka+lndT4+HgNGjRIKSkpJkUEWKNTp07q379/wxdgzWV18jU2NlYDBw5Uenp6SOMArJaRkaGBAwcqJiamRfuRfAUAAACisOzA7NmzJUnXXXddk+urq6slBSdf58yZE3Tp3DnnnKOTTjpJjz/+uJ555plWxWEYhqqqqlq1LyJTUlJSs7cdPny45s2bp9zcXFVUVOiaa67RBx98YGJ0QPu48847NWPGDNntdn377bc6//zzVVRU1Kx94+PjVVlZGbJYEhMTm71tnz599NFHH6lv376qqanRD37wA7322mshiwWwyve//30988wzcrlc2rRpk84991zt3r27WfsmJCSEtE0CAAAg8iQkJMhms1kdhrmMKJOcnGzExsYagUCgyfU//vGPDUnGl19+edzjXHvttcY555zT6jgqKioMSdy4ter2zTffBP09FRcXGzabzfK4uHFry23AgAGN/lc++uijlsfVnNv//ve/oLg9Ho+RnJxseVzcuLXllpmZadTW1gb9bb/xxhuWx8WNGzdu3Lhx48Ytcm4VFRWtzq11FFFVdsDr9aq8vFzx8fFNZtVra2s1a9Ys2e12DR8+/JjH8fv9Wrp0aUOJAqC95ebmBj1OT09XQkKCRdEAodFUKZgj63KHs6PbZGxsLJdco8PLzs6Wy+UKWtZR2iQAAAAQLqKq7IDL5VJ6errcbrfcbnejunzTp09Xfn6+BgwYcNxLwB977DHt2rVLt956a6tjSUhIUEVFRav3R+QpKytrlMA5lo8++qhhcjhJWrRoEZd2osNbtWqVDhw4oC5dujQsa245jf79+2vFihUhjccwDGVlZamm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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "qpe(U1, 2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "66e0314e-c0ed-436e-8868-e2bd90782b5a", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "qutip-dev", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/src/qutip_qip/algorithms/__init__.py b/src/qutip_qip/algorithms/__init__.py index 4971be21..c2893b6f 100644 --- a/src/qutip_qip/algorithms/__init__.py +++ b/src/qutip_qip/algorithms/__init__.py @@ -1,2 +1,4 @@ from .qft import * -from .error_correction.bit_flip import * \ No newline at end of file +from .error_correction.bit_flip import * +from .error_correction.phase_flip import * +from .error_correction.shor_code import * \ No newline at end of file diff --git a/src/qutip_qip/algorithms/untitled.ipynb b/src/qutip_qip/algorithms/untitled.ipynb new file mode 100644 index 00000000..aff60d7f --- /dev/null +++ b/src/qutip_qip/algorithms/untitled.ipynb @@ -0,0 +1,134 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 24, + "id": "8f967292", + "metadata": {}, + "outputs": [], + "source": [ + "import qutip_qip" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "2a69ade1", + "metadata": {}, + "outputs": [], + "source": [ + "import qutip_qip.circuit\n", + "\n", + "\n", + "qc = qutip_qip.circuit.QubitCircuit(2)" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "ae89dc2f", + "metadata": {}, + "outputs": [], + "source": [ + "qc.add_gate(\"RX\", targets=[0], arg_value=0.2)\n", + "qc.add_gate(\"RY\", targets=[0], arg_value=0.1)\n", + "qc.add_gate(\"RY\", targets=[0], arg_value=0.1)\n", + "\n", + "qc.add_gate(\"RZ\", targets=[0], arg_value=0.3)\n", + "qc.add_gate(\"CNOT\", targets=[0], controls=[1])" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "id": "9a7aa90f", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "qutip_qip.circuit.QubitCircuit.draw(qc)" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "id": "d8a2157e", + "metadata": {}, + "outputs": [], + "source": [ + "from qutip_qip.circuit.optimise import optimise\n", + "\n", + "\n", + "new_qc = optimise(qc)" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "598ef8b4", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "qutip_qip.circuit.QubitCircuit.draw(new_qc)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7a4e83a8", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "694323ad", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "qutip-dev", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/src/qutip_qip/circuit/__init__.py b/src/qutip_qip/circuit/__init__.py index d0264108..54664869 100644 --- a/src/qutip_qip/circuit/__init__.py +++ b/src/qutip_qip/circuit/__init__.py @@ -5,7 +5,7 @@ from .circuit import * from .circuitsimulator import * from ..operations import Gate, Measurement - +from .optimise import * def _add_deprecation(fun, msg): def newfun(*args, **kwargs): diff --git a/src/qutip_qip/circuit/circuit.py b/src/qutip_qip/circuit/circuit.py index dd413c21..e92be52a 100644 --- a/src/qutip_qip/circuit/circuit.py +++ b/src/qutip_qip/circuit/circuit.py @@ -1036,3 +1036,5 @@ def _to_qasm(self, qasm_out): for op in self.gates: op._to_qasm(qasm_out) + + \ No newline at end of file diff --git a/src/qutip_qip/circuit/circuitsimulator.py b/src/qutip_qip/circuit/circuitsimulator.py index 1e73d343..1132b532 100644 --- a/src/qutip_qip/circuit/circuitsimulator.py +++ b/src/qutip_qip/circuit/circuitsimulator.py @@ -8,11 +8,12 @@ Measurement, expand_operator, ) + from qutip import basis, ket2dm, Qobj, tensor import warnings -__all__ = ["CircuitSimulator", "CircuitResult"] +__all__ = ["CircuitSimulator", "CircuitResult", "gate_sequence_product"] def _flatten(lst): @@ -132,7 +133,7 @@ def _expand_overall(tensor_list, overall_inds): return U_overall, overall_inds -def _gate_sequence_product(U_list, ind_list): +def gate_sequence_product(U_list, ind_list): """ Calculate the overall unitary matrix for a given list of unitary operations that are still of original dimension. diff --git a/src/qutip_qip/circuit/optimise.py b/src/qutip_qip/circuit/optimise.py new file mode 100644 index 00000000..be927a9d --- /dev/null +++ b/src/qutip_qip/circuit/optimise.py @@ -0,0 +1,82 @@ +from qutip_qip.decompose.decompose_single_qubit_gate import decompose_one_qubit_gate +from qutip_qip.circuit import QubitCircuit +from qutip_qip.circuit import gate_sequence_product + +__all__ = ["optimise"] + +def optimise(circuit): + optimized_gates = [] + i = 0 + while i < len(circuit.gates): + gate = circuit.gates[i] + if gate.targets and len(gate.targets) == 1 and not gate.controls: + qubit = gate.targets[0] + sq_gates = [] + # Gather all consecutive single-qubit gates on the same qubit + while i < len(circuit.gates): + g = circuit.gates[i] + if g.targets == [qubit] and not g.controls: + sq_gates.append(g) + i += 1 + else: + break + if len(sq_gates) == 1: + optimized_gates.append(sq_gates[0]) + else: + try: + # Get all gate unitaries for the sequence + unitaries = [g.get_unitary() for g in sq_gates] + + # Combine them into a single unitary + u_combined = gate_sequence_product(unitaries) + + # Use the decompose_one_qubit_gate function to decompose into ZYZ form + + # Decompose the combined unitary into ZYZ gates + zyz_gates = decompose_one_qubit_gate(u_combined, decomposition="ZYZ", target=qubit) + + # Add decomposed gates to the optimized circuit + optimized_gates.extend(zyz_gates) + except Exception as e: + print(f"Decomposition failed: {e}") + # Fallback to original gates if decomposition fails + optimized_gates.extend(sq_gates) + else: + optimized_gates.append(gate) + i += 1 + + new_circuit = QubitCircuit(N=circuit.N) + new_circuit.gates = optimized_gates + return new_circuit + +def run_example(): + """Run a complete example of quantum circuit optimization.""" + print("=== Quantum Circuit Optimization Example ===") + + # Example 1: A circuit with 4 single-qubit gates + print("\nExample 1: Four consecutive single-qubit gates") + qc1 = QubitCircuit(N=1) + qc1.add_gate("RX", targets=[0], arg_value=0.2) + qc1.add_gate("RY", targets=[0], arg_value=0.1) + qc1.add_gate("RY", targets=[0], arg_value=0.1) + qc1.add_gate("RZ", targets=[0], arg_value=0.3) + + QubitCircuit.draw(qc1) + optimized_qc1 = optimise(qc1) + QubitCircuit.draw(optimized_qc1) + + # Example 2: A circuit with mixed single and multi-qubit gates + print("\n\nExample 2: Mixed single and multi-qubit gates") + qc2 = QubitCircuit(N=2) + qc2.add_gate("RX", targets=[0], arg_value=0.2) + qc2.add_gate("RY", targets=[0], arg_value=0.3) + qc2.add_gate("CNOT", controls=[0], targets=[1]) + qc2.add_gate("RZ", targets=[1], arg_value=0.1) + qc2.add_gate("RX", targets=[1], arg_value=0.4) + + QubitCircuit.draw(qc2) + optimized_qc2 = optimise(qc2) + QubitCircuit.draw(optimized_qc2) + + +run_example() diff --git a/tests/test_bit_flip.py b/tests/test_bit_flip.py new file mode 100644 index 00000000..342b5215 --- /dev/null +++ b/tests/test_bit_flip.py @@ -0,0 +1,82 @@ +import pytest +import numpy as np +from qutip_qip.algorithms import BitFlipCode + +def test_encode_circuit_structure(): + """Test that the encoding circuit has the correct structure.""" + qc = BitFlipCode.encode_circuit() + + # Check circuit has correct number of qubits + assert qc.N == 3 + + # Check it has 2 CNOT gates + assert len(qc.gates) == 2 + assert all(gate.name == "CNOT" for gate in qc.gates) + + # Check gate connections - QubitCircuit uses lists for controls and targets + assert qc.gates[0].controls == [0] + assert qc.gates[0].targets[0] == 1 + assert qc.gates[1].controls == [0] + assert qc.gates[1].targets[0] == 2 + +def test_syndrome_measurement_circuit_structure(): + """Test that the syndrome measurement circuit has the correct structure.""" + qc = BitFlipCode.syndrome_measurement_circuit() + + # Check circuit has correct number of qubits (3 data + 2 syndrome) + assert qc.N == 5 + + # Check it has 4 CNOT gates + assert len(qc.gates) == 4 + assert all(gate.name == "CNOT" for gate in qc.gates) + + # Check gate connections for syndrome measurement + assert qc.gates[0].controls == [0] and qc.gates[0].targets[0] == 3 + assert qc.gates[1].controls == [1] and qc.gates[1].targets[0] == 3 + assert qc.gates[2].controls == [1] and qc.gates[2].targets[0] == 4 + assert qc.gates[3].controls == [2] and qc.gates[3].targets[0] == 4 + +def test_correction_circuit_no_error(): + """Test correction circuit with no error (syndrome 00).""" + qc = BitFlipCode.correction_circuit((0, 0)) + assert qc.N == 3 + assert len(qc.gates) == 0 # No correction needed + +def test_correction_circuit_qubit0_error(): + """Test correction circuit with error on qubit 0 (syndrome 10).""" + qc = BitFlipCode.correction_circuit((1, 0)) + assert qc.N == 3 + assert len(qc.gates) == 1 + assert qc.gates[0].name == "X" and qc.gates[0].targets[0] == 0 + +def test_correction_circuit_qubit1_error(): + """Test correction circuit with error on qubit 1 (syndrome 11).""" + qc = BitFlipCode.correction_circuit((1, 1)) + assert qc.N == 3 + assert len(qc.gates) == 1 + assert qc.gates[0].name == "X" and qc.gates[0].targets[0] == 1 + +def test_correction_circuit_qubit2_error(): + """Test correction circuit with error on qubit 2 (syndrome 01).""" + qc = BitFlipCode.correction_circuit((0, 1)) + assert qc.N == 3 + assert len(qc.gates) == 1 + assert qc.gates[0].name == "X" and qc.gates[0].targets[0] == 2 + +def test_decode_circuit_structure(): + """Test that the decoding circuit has the correct structure.""" + qc = BitFlipCode.decode_circuit() + + # Check circuit has correct number of qubits + assert qc.N == 3 + + # Check it has 2 CNOT gates and 1 TOFFOLI gate + assert len(qc.gates) == 3 + assert qc.gates[0].name == "CNOT" + assert qc.gates[1].name == "CNOT" + assert qc.gates[2].name == "TOFFOLI" + + # Check gate connections + assert qc.gates[0].controls == [0] and qc.gates[0].targets[0] == 2 + assert qc.gates[1].controls == [0] and qc.gates[1].targets[0] == 1 + assert qc.gates[2].controls == [1, 2] and qc.gates[2].targets[0] == 0 diff --git a/tests/test_phase_flip.py b/tests/test_phase_flip.py new file mode 100644 index 00000000..81a687bb --- /dev/null +++ b/tests/test_phase_flip.py @@ -0,0 +1,127 @@ +import pytest +import numpy as np +from qutip import Qobj, tensor, basis, fidelity +from qutip_qip.algorithms import PhaseFlipCode + +def test_encode_circuit_structure(): + """Test that the encoding circuit has the correct structure.""" + qc = PhaseFlipCode.encode_circuit() + + # Check circuit has correct number of qubits + assert qc.N == 3 + + # Check it has correct number of gates (1 H + 2 CNOT + 3 H = 6 gates) + assert len(qc.gates) == 6 + + # Check first gate is Hadamard on qubit 0 + assert qc.gates[0].name == "SNOT" + assert qc.gates[0].targets[0] == 0 + + # Check CNOT gates + assert qc.gates[1].name == "CNOT" + assert qc.gates[1].controls == [0] + assert qc.gates[1].targets[0] == 1 + + assert qc.gates[2].name == "CNOT" + assert qc.gates[2].controls == [0] + assert qc.gates[2].targets[0] == 2 + + # Check final Hadamard gates on all qubits + assert qc.gates[3].name == "SNOT" + assert qc.gates[3].targets[0] == 0 + + assert qc.gates[4].name == "SNOT" + assert qc.gates[4].targets[0] == 1 + + assert qc.gates[5].name == "SNOT" + assert qc.gates[5].targets[0] == 2 + +def test_syndrome_measurement_circuit_structure(): + """Test that the syndrome measurement circuit has the correct structure.""" + qc = PhaseFlipCode.syndrome_measurement_circuit() + + # Check circuit has correct number of qubits (3 data + 2 syndrome) + assert qc.N == 5 + + # Check it has the correct number of gates (3 H + 4 CNOT + 3 H = 10 gates) + assert len(qc.gates) == 10 + + # Check first three Hadamard gates on data qubits + for i in range(3): + assert qc.gates[i].name == "SNOT" + assert qc.gates[i].targets[0] == i + + # Check CNOT gates for syndrome measurement + assert qc.gates[3].name == "CNOT" + assert qc.gates[3].controls == [0] and qc.gates[3].targets[0] == 3 + + assert qc.gates[4].name == "CNOT" + assert qc.gates[4].controls == [1] and qc.gates[4].targets[0] == 3 + + assert qc.gates[5].name == "CNOT" + assert qc.gates[5].controls == [1] and qc.gates[5].targets[0] == 4 + + assert qc.gates[6].name == "CNOT" + assert qc.gates[6].controls == [2] and qc.gates[6].targets[0] == 4 + + # Check final three Hadamard gates on data qubits + for i in range(3): + assert qc.gates[7+i].name == "SNOT" + assert qc.gates[7+i].targets[0] == i + +def test_correction_circuit_no_error(): + """Test correction circuit with no error (syndrome 00).""" + qc = PhaseFlipCode.correction_circuit((0, 0)) + assert qc.N == 3 + assert len(qc.gates) == 0 # No correction needed + +def test_correction_circuit_qubit0_error(): + """Test correction circuit with error on qubit 0 (syndrome 10).""" + qc = PhaseFlipCode.correction_circuit((1, 0)) + assert qc.N == 3 + assert len(qc.gates) == 1 + assert qc.gates[0].name == "Z" and qc.gates[0].targets[0] == 0 + +def test_correction_circuit_qubit1_error(): + """Test correction circuit with error on qubit 1 (syndrome 11).""" + qc = PhaseFlipCode.correction_circuit((1, 1)) + assert qc.N == 3 + assert len(qc.gates) == 1 + assert qc.gates[0].name == "Z" and qc.gates[0].targets[0] == 1 + +def test_correction_circuit_qubit2_error(): + """Test correction circuit with error on qubit 2 (syndrome 01).""" + qc = PhaseFlipCode.correction_circuit((0, 1)) + assert qc.N == 3 + assert len(qc.gates) == 1 + assert qc.gates[0].name == "Z" and qc.gates[0].targets[0] == 2 + +def test_decode_circuit_structure(): + """Test that the decoding circuit has the correct structure.""" + qc = PhaseFlipCode.decode_circuit() + + # Check circuit has correct number of qubits + assert qc.N == 3 + + # Check it has the correct number of gates (3 H + 2 CNOT + 1 TOFFOLI + 1 H = 7 gates) + assert len(qc.gates) == 7 + + # Check first three Hadamard gates + for i in range(3): + assert qc.gates[i].name == "SNOT" + assert qc.gates[i].targets[0] == i + + # Check the two CNOT gates + assert qc.gates[3].name == "CNOT" + assert qc.gates[3].controls == [0] and qc.gates[3].targets[0] == 2 + + assert qc.gates[4].name == "CNOT" + assert qc.gates[4].controls == [0] and qc.gates[4].targets[0] == 1 + + # Check the TOFFOLI gate + assert qc.gates[5].name == "TOFFOLI" + assert qc.gates[5].controls == [1, 2] and qc.gates[5].targets[0] == 0 + + # Check the final Hadamard gate + assert qc.gates[6].name == "SNOT" + assert qc.gates[6].targets[0] == 0 diff --git a/tests/test_shor_code.py b/tests/test_shor_code.py new file mode 100644 index 00000000..41403d96 --- /dev/null +++ b/tests/test_shor_code.py @@ -0,0 +1,44 @@ +import pytest +from qutip_qip.algorithms import ShorCode + +def test_encode_circuit(): + """Test the Shor code encoding circuit structure.""" + qc = ShorCode.encode_circuit() + + # Check correct number of qubits + assert qc.N == 9 + + # Check total number of gates (1H + 2CNOT + 3H + 6CNOT = 12 gates) + assert len(qc.gates) == 12 + + # Check first Hadamard gate (phase-flip encoding starts) + assert qc.gates[0].name == "SNOT" and qc.gates[0].targets[0] == 0 + + # Check first level CNOTs (create GHZ-like state across blocks) + assert qc.gates[1].name == "CNOT" + assert qc.gates[1].controls == [0] and qc.gates[1].targets[0] == 3 + assert qc.gates[2].name == "CNOT" + assert qc.gates[2].controls == [0] and qc.gates[2].targets[0] == 6 + + # Check three Hadamard gates (complete phase-flip encoding) + assert qc.gates[3].name == "SNOT" and qc.gates[3].targets[0] == 0 + assert qc.gates[4].name == "SNOT" and qc.gates[4].targets[0] == 3 + assert qc.gates[5].name == "SNOT" and qc.gates[5].targets[0] == 6 + + # Check bit-flip encoding CNOTs for first block + assert qc.gates[6].name == "CNOT" + assert qc.gates[6].controls == [0] and qc.gates[6].targets[0] == 1 + assert qc.gates[7].name == "CNOT" + assert qc.gates[7].controls == [0] and qc.gates[7].targets[0] == 2 + + # Check bit-flip encoding CNOTs for second block + assert qc.gates[8].name == "CNOT" + assert qc.gates[8].controls == [3] and qc.gates[8].targets[0] == 4 + assert qc.gates[9].name == "CNOT" + assert qc.gates[9].controls == [3] and qc.gates[9].targets[0] == 5 + + # Check bit-flip encoding CNOTs for third block + assert qc.gates[10].name == "CNOT" + assert qc.gates[10].controls == [6] and qc.gates[10].targets[0] == 7 + assert qc.gates[11].name == "CNOT" + assert qc.gates[11].controls == [6] and qc.gates[11].targets[0] == 8 From 0b9febb858c48f7fba71cedb4dd334b595ca1978 Mon Sep 17 00:00:00 2001 From: Rochisha Agarwal Date: Mon, 5 May 2025 15:48:00 +0530 Subject: [PATCH 4/7] remove unnecessary files --- src/qutip_qip/algorithms/untitled.ipynb | 134 ------------------------ 1 file changed, 134 deletions(-) delete mode 100644 src/qutip_qip/algorithms/untitled.ipynb diff --git a/src/qutip_qip/algorithms/untitled.ipynb b/src/qutip_qip/algorithms/untitled.ipynb deleted file mode 100644 index aff60d7f..00000000 --- a/src/qutip_qip/algorithms/untitled.ipynb +++ /dev/null @@ -1,134 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 24, - "id": "8f967292", - "metadata": {}, - "outputs": [], - "source": [ - "import qutip_qip" - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "id": "2a69ade1", - "metadata": {}, - "outputs": [], - "source": [ - "import qutip_qip.circuit\n", - "\n", - "\n", - "qc = qutip_qip.circuit.QubitCircuit(2)" - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "id": "ae89dc2f", - "metadata": {}, - "outputs": [], - "source": [ - "qc.add_gate(\"RX\", targets=[0], arg_value=0.2)\n", - "qc.add_gate(\"RY\", targets=[0], arg_value=0.1)\n", - "qc.add_gate(\"RY\", targets=[0], arg_value=0.1)\n", - "\n", - "qc.add_gate(\"RZ\", targets=[0], arg_value=0.3)\n", - "qc.add_gate(\"CNOT\", targets=[0], controls=[1])" - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "id": "9a7aa90f", - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "qutip_qip.circuit.QubitCircuit.draw(qc)" - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "id": "d8a2157e", - "metadata": {}, - "outputs": [], - "source": [ - "from qutip_qip.circuit.optimise import optimise\n", - "\n", - "\n", - "new_qc = optimise(qc)" - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "id": "598ef8b4", - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAq0AAAC4CAYAAADJ2NWqAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy80BEi2AAAACXBIWXMAABcSAAAXEgFnn9JSAAAj+ElEQVR4nO3de3RU5d0v8O/ee3KbmdwgCSQkXEIIN0EExQuIoLVe8Fg9orRY1Naet7andLVnnfas9z1eaStvFa3v+7qKVtcpFVsRo4IKSrkUBUUocguXAOGaEAiBJCQzuc3s/Zw/JgkEEnJ79syT2d/PWlmQzMyeZ/9mz+zvfubZz9aEEAJERERERArTI90AIiIiIqLOMLQSERERkfIYWomIiIhIeQytRERERKQ8hlYiIiIiUh5DKxEREREpj6GViIiIiJTH0EpEREREymNoJSIiIiLlMbQSERERkfIYWomIiIhIeQytRERERKQ8hlYiIiIiUh5DKxEREREpj6GViIiIiJTH0EpEREREymNoJSIiIiLlMbQSERERkfIYWomIiIhIeQytRERERKQ8hlYiIiIiUh5DKxEREREpj6GViIiIiJTH0EpEREREymNoJSIiIiLlMbQSERERkfIYWomIiIhIeQytRERERKQ8hlYiIiIiUh5DKxEREREpj6GViIiIiJTH0EpEREREymNoJSIiIiLlMbQSERERkfIYWomIiIhIeQytRERERKQ8hlYiIiIiUh5DKxEREREpj6GViIiIiJTH0EpEREREymNoJSIiIiLlMbQSERERkfIYWomIiIhIeQytRERERKQ8hlYiIiIiUh5DKxEREREpj6GViIiIiJTninQDiIiIVHD6dBWOFJehvq4Jbk8cRowchLS05Eg3i4iaOTK0rl69GgsXLsSWLVugaRpuuukm/OEPf8DSpUvx3HPPYfHixXj00Ucj3UwiIrKZEAJbNhfhw4Iv8dWmfRBCtN5mGDqmzRiH+2dNxTUTh0PTtAi2lIg0cfE71AGeeeYZzJ8/H3FxcZgxYwZiY2Px+eefw+12Y+LEiVi5ciV27dqF8ePHR7qpRERko0AgiAXzl+Lvn33T6X0feGgqfv6/7odhcFQdUaQ4KrS+8847mDNnDiZNmoTly5cjOzsbAFBSUoJJkyahoqICcXFx8Pl8cLkc2QlNROQIlmXhmf/7Fv6xdleXH3Pv/TfiV//6IHtciSLEMYeMtbW1mDdvHpKTk/Hxxx+3BlYAyMnJweOPPw4AGDt2bGtg3bZtGx555BHk5eVB0zQ8+eSTEWk7ERHJtfz9r7oVWAHgow83Y/3anfY0iIg65ZjQ+uabb+LcuXOYN28eMjMzL7s9Ly8PAHDNNde0/u3LL7/E119/jalTpyI5mYPxiYiigRAC7y/b2KPH9vRxRNR7jgmtK1asAADMnj273dvr6+sBtA2t8+bNw8GDB7F48WKkpKTY3kYiIrLfjm+KcfzYmR49dvfOoyg+VCa5RUTUFY4ZuLl9+3bExcVh7Nix7d5eWFgIoG1o1XW5mV4Igbq6OqnLJCKi7vly055ePf6rTXuQmcVv30hNbrc7asddOyK0BgIB1NbWIiUlpd0XsqmpCcuXL4eu67bOGlBXVwev12vb8omIqHO5g2cgM+PqHj/+qSefwaM//Fpii4jk8fl88Hg8kW6GLRwxPCAmJgapqamorq5GVVXVZbcvWLAAZ86cQV5eHkMlEVGUs6xgrx5vWqaklhBRdziipxUAJk6ciHXr1mHBggV44YUXWv++aNEizJ8/H0DboQF2cLvd8Pl8tj4HERFd2ScrtuK//vBRjx//xpv/hWnTr5LYIiJ53G53pJtgG8eE1qeffhrr16/Hiy++iLVr1yI/Px87d+5EaWkp5syZg7ffftv20KppWtR22RMR9RUz770Bbyz6DA0NTd1+bGo/L267fRJiYx2z+yRShiOGBwDAtGnTsGzZMlx11VXYu3cvNmzYgMmTJ2PXrl2tRyUTJkyIbCOJiMh2Xm8Cvn3XpB499p7v3MDAShQhjnrnzZo1C7Nmzbrs79u3bwdg//AAIiJSwyM/+BY2fl6IqsquD9nKzOqHh753i42tIqIrcUxPa0eCwSD27NmDrKwsZGRktLmtoqICBQUFKCgoQF1dHYqKilBQUIBPP/00Qq0lIiIZBmb2w4uv/AuSU7o2ZCsjIwUv/cePkZrKk3WJIkUTQohINyKSdu/ejauvvhozZ87EJ5980ua2DRs2YMaMGZc9ZsiQITh27FiYWkhERHYpLanAq698hK827YVlXb47NAwdt8wYj3m//A7SM1LC30AiauWo4QHt2bFjB4D2x7NOnz4dDs/0RERRLTsnHf/+0uM4faoSBe9uxNK/bmi9be5j38IDs6ciLY0XEiBSgeN7WomIiACgtrYed936b62/f7r+eSQmJkSwRUR0McePaSUiIiIi9TG0EhEREZHyGFqJiIiISHkMrURERESkPIZWIiIiIlIeQysRERERKY+hlYiIiIiUx9BKRERERMpjaCUiIiIi5TG0EhEREZHyGFqJiIiISHkMrURERESkPIZWIiIiIlIeQysRERERKY+hlYiIiIiUx9BKRERERMpjaCUiIiIi5TG0EhEREZHyGFqJiIiISHkMrURERESkPIZWIiIiIlIeQysRERERKY+hlYiIiIiUx9BKRERERMpjaCUiIiIi5TG0EhEREZHyGFqJiIiISHkMrURERESkPIZWIiIiIlIeQysRERERKY+hlYiIiIiUx9BKRERERMpjaCUiIiIi5TG0EhEREZHyXJFuAPUtlhDwBQBfQCBgXfm+mgZ4XRq8MUCsoYWngYoLWhfqZ4or39elA94YDR4X4NJZPwBoNEP18wcEOikf4oxQ/dwuQNdYPyEE6k3AFwDqg51VD0hofu8mGIDG+hGRAhhaqZUlBMrrBEr9AqU+gTMNAv7mgNUStPzBni07Vge8MaEQ4Y0BEmM0JMdpGOTRkOMJ/Rvv6ts7xiZT4FSdQIlP4KRfoLJRtKmdLwA0mD1bdoLRtn7eGA394zVkezRkezVkurU+H2zrgqHtrtQvUOYXqG4S8AcEai+qX2cHSu3RALhdQGKsBq/rQg0zEjTkeDUM8uhIT+jbwVYIgfNNaH7vWiirE6htaq5bMBTyfQF0eqDUHkMLbXuemAv1S4wFstwasr06sj0akmMZbInIfgytDiVEKFgVVloouSgo9CQUdEWTBVQ2ApWNLXvNy/ee6fFo3QmOSNYwtp+ubBCzhMDBaoGiaqs1aJ2u67z3r6fqzdBPRUP79TM0INMdCrDZHg1jUnXkJmnKBolGM7TtHTkfql2Jz0Jloz3PJQD4g4A/2PG2F2cAgzyh2uV4NVzd38AAt5q1A4CaJoGdZy2c8IVqV+oPhVI7mAI43wScb2qvfqGjMG8MmmunY7BXw4Q0HUmx6taPiPomhlaHKfNb2FJuYeuZUG+MSioagIoGCzvOhn53u4BJ6TomZxgYkxr5nkRLCBw6L7D1jIl/nrFwvimizWnDFM29bP6W19REWjxwXYaB6zN0DE2MfIBtag6qW8ot7DxnobGHvc52aDSBIzUCR2pC9fvrIRNDvBquH6DjugwDGQmRD2C+gMC2Cgtby03srxKw6fiyR3wBoKhaoKg69KLqAEanapg8wMC16Tq8MZGvHxH1fZoQQq3kQrYo81tYdtjEjrMq7eq6LiMBeHC4C9el6xEJX3srLbxbHMRxX998u+Qna/juCBeGJ4X/3EtLCGw8ZeGDI0FUKxT0u+OmATpmDXehf3z4t736oMCqEyY+O2GiqQ++fWN14M7BBu4ebCBB8SFAtbX1uOvWf2v9/dP1zyMxMSGCLSKiizG0OsDnZSYWHwjCioJXemKajp+MdYXtxC5LCCw5GMT6k30wLbTjvqEG7htmhC34+wMCr+wO4OD5vr/xxerAT8a6MDHdCNtznvRbeGlnAOdsGjoRTv3igP89IQaDPOpOWsPQSqQ2dT89SIpvKkz8uSg6AisAbD9r4c39QYTrWKvgiBk1gRUAlh8zsaY0PN/LBy2BV/dER2AFQuOyX90TxMHq8GwP1Y0CC6MksAKhMe0LdwZQ3Rgd2wMRhR9DaxSrbhR4bW/QtpODImXLGQv/KLM/OBSes7DyuEIDLyX52yETx2vtr9/Hx0zsq4qurc8UwH8WBtDQhSmjeutP+wK2nZwWKZWNofUiIuoJhtYotv5k3xwD1xWfnTBh2dzb+umJHs7vpTgBYHWJvWG8yRRYezL6Aj8A1AaAr8rtfWOd8FnYG2WBv8XeKoETvij9YCIiW3H2gCgVsAQ2lEVnaACA8nqBPZUC4/vbMzazzB+9oQEAtpRb+G6esG1aoq/LLdumYFLBmlITM7LsOylwrc0HFZG2tsTED0dHvs+ksTGAf245gKJ9JThQVIKi/aVtbp/70L9j1JjBGDkqG6PHDsa1k/PhcoVvTDMRtcXQGqW2KjYlkx3WlJoY39+eHd/aMI37jJSgAP5x0sR3hsn/CBBChG3cbKSU+QX2VQmM7Sc/tPoCwvae3Ej7qtzCQ3kiYlNhlZ08hxUffIWVH21BdbW/w/udPVuDTV/swaYv9gAA+qcl4d77b8S9992A9IyUMLWWiFpE/lCXbLEuykMDAOw+Z6Hchrlm64MCm05Hd2gAQsNH7BhiUVwjcKKPTg3WHetsGv7wxSnTtot8qCJghdYz3OrrG/HKwg8w+/7f4a9vrb9iYG3PubM1+PMbqzHr3t/g9T+uRFNTdA4hIlIVQ2sU8gcEDtdEf2gAgH1V8vfuxeeFUhPf26W6+bKfsu05F+WJq9neSsuW0O+U+oV7PXd8U4xHv/ciCt7d2OvZR0zTwpI/r8WPHnkZRftLJLWQiDrD0BqFjtY6I7ACQPF5G0JrjTNCAwActmE6qsMOqV+DGRomIJMlLlyVK9odqRG2n0zZYvkHX+HnP/kjyk6ek7rcI4dP4cc/eAXr/r5D6nKJqH0MrVHosA1BTlV27OCdEhoA4IjkgOmk0AVA+jcap+sE6h3Qyw8A9WZofe1W8O4XWLjgPdvmdjZNC88+uQSrV22zZflEdAFDaxRyytAAACirE/AH5K2vEMJRob9Y8rZSXifgd9AwP9nbSnGUXIihq+xe37V/345XFn5o63MAoc+N3z33DrZsLrL9uYicjKE1ygghHPP1bAuZPXvl9c4KXWV+uaHfSQdMgPz1ddp71871PVNejReff6/bj/N641t/usOyLDw//x3U1NR1+zmJqGs45VWUqWyE1Pkx7xtm4P5LpkWqDwqcqhPYWm7h76UmzOb9dm6ihqeujUFdEPjV5ibUXRL+NADPXheDoYk6/rQvgC8lnaF/wmdhnKSpr45LHg/cnfr9crwLE9IMvFscxKoT7X9H/OhIF24dZODzMhP/r0hOui7xCYxKlTP1kNPqd9IvELAEYnT16ted2nV0//a8sS8gbXYN2dtLCyEEXnh+Gfz+hm49zuuNx2f/WND6+50z/hU+X9eXce5sDf7jpQ/x1HMPd+t5iahrGFqjjF3X9S6vEzh43oIGoF+8hrwkDbkjXJiUruP3OwMIWMCRWoEvT1u4OdPAvUMNLC1uGxymZuoYmqjjQLUlLbACQJXES11WRbB+yw6bGNdPx8whBjaUmZeF/owEYFqmjoagwPtH5HUHVzfJW+cqicu6mKr1EwBqmoD+3euU65DM16JFV2oHACdqBTZ2MA1VrA5cPyA0qX6NxPmf7VhfAFi/Zie+/mq/LcvuzOpV23Dn3dfiuutHRuT5iaKZI4cHrF69GrfffjuSkpKQnJyMu+66C0VFRXj22WehaRr+8pe/RLqJPXbepp3AwfMW3twfxBv7g/j9jgCe/mcAtU0CI1J03DbowhVilhUHURcUuG2QgbSLduSxOvBArgtBS+AvB+R+/y5zx2fXBRm6Ur+TfoGNpy14YzTcPfjyq+48kOuCS9fwaYkptZ0yt5nzNoV+lesna/uzhJAaCFt09b27/Wzofu39tJwwtbfSwu5KeQecNU2wZQaBZUs/l77M7nhv6RcRfX6iaOW40PrMM8/gzjvvxMaNGzFlyhRMnz4dmzdvxq233opt20Jnf15zzTURbmXPVYfpKlin6kTr9esnpF3YjGoCwIqjJmINDQ8Ov9CRP3OIgdQ4DWtKTZyUPE2QzKBkV8/PpTqq3wdHgmgICnw7x0By7IX7D/ZqmJyho6pRYNVxuaeXV0vsqQ7XVdhUqp+s7c8XQJuv6+3SUe06kpEA3DXYQJMp/4DTFHKHMwHAgaIS7C08Lneh3bT5y/04VVYZ0TYQRSNHhdZ33nkH8+fPx6RJk1BcXIxPP/0UK1asQGFhIYLBIFauXIm4uDiMGTMm0k3tMbt6utrTctWjlNi2f19TaqLMb2Fyho7cRA2pcaGdXlWjwPKj8ufzkdrrGOH6nW8CPisxEWdouHfohdD/QK4BXdPw4ZEgmiSfuyKzpzVcoR9QqX6ylhP59257vj/ChVhDw6oTJsrr5bdR9nqv+GCz1OX1hBACHy2PfDuIoo1jQmttbS3mzZuH5ORkfPzxx8jOzm69LScnB48//jgAYOzYsXC5Luzsdu7ciZtvvhkJCQkYNmwYXn311bC3vTvCueOLa/5m8dLeXVMAfz0UhK5p+O4IFx4c7kKcoeFvh4JosGEOSqlfb4eppxDouH6rTpiobhSYnqUjLR4YkaxhQpqBEp+FL07JP9taVv0aguG9kpgq9ZMV1FXY9i41KU3H1WkGTtdZ+ERyD3UL2eu945tiuQvsoZ2KtIMomjgmtL755ps4d+4c5s2bh8zMzMtuz8vLA9B2aEBFRUXr2NdPPvkEP/3pT/GLX/wCS5YsCVu7uyucO75RKaHN55uKy4PAnkqB7RUmRqbomDLQwN5KC1vP2DO9TYMJNEr6XrUmjKG/o/o1msCHR4Nw6Rr+e64LDzUPs3i3OAg7Wievp1DOcrpKnfrJCq2R3/YuFqsD3xsRqt2Sg8HWE7Zkk/ntht/XgJITFdKW1xuHDpbBNJ01hRmR3Rwze8CKFSsAALNnz2739vr6egBtQ+trr70GTdPw3nvvwe1247bbbsPRo0fxm9/8BnPnzrW/0T1ghWG/lxwLXJ9h4JYsHVvKTaw/2X4PzGclJiamh7p0Vh63d/JTWWMBwzGmsCv1+7zMwrdzLEwZGKrfnkoLhZU2XdFH0mLDdUlO1epnScolKr13AeC/DTWQnqDh63ITe2yqHSD3PXfwQKm8hfVSQ0MTjh8rR+7wyztJiKhnHBNat2/fjri4OIwdO7bd2wsLCwG0Da2rV6/G3XffDbfb3fq3Bx98EIsWLcKRI0eQm5vbrTYIIVBXZ+/E00FThx0d6DdnGrg588KZxgFLYMnBIDaUdbzHviPnwv1vyzawt8q+4Frnr4OQsjUbCM0oK1d36ycAvHfYxC/Gh17LpYfsq52wLPj9/l4vJ3TcZ89Hisr1CwaD8Pt7383c2KghtP3J1ZP37oAEDXcNNlAXFPibjbUDgKamRvglnZx59GhZp/e50kUDPJ74K/7enivN43r0SBkGDEzqdBlEMrndbmia/P2YChwRWgOBAGpra5GSktLuC9nU1ITly5dD13WMHz++9e8HDx7EPffc0+a+o0aNAgAcOHCg26G1rq4OXq+3B2vQdTN++z5ybpwpfbktcz3qGpDl1jAsScfcfBfONgTa7YUZ30/HpHQDJ2ot1ASASekGxqSa2FdlT49N1qAsBPw1vV7O7A9PIi6pv4QWtdXd+gFAie9CqCiRPOPCxfbv3w/vTRN7vZyk7BG47y+FElp0OZXrt3jxYvz45Z/2ejnD75iLKb9+Q0KL2upJ7ebmuxCja1h6KGD7sI8nnvgJDq9+S8qyBqaPx/Aht3Z4+6UXD+jM+5880+l9rnQBgtmzv4dzVYe6/HxEMvh8Png8nkg3wxaOGNMaExOD1NRUVFdXo6qq6rLbFyxYgDNnziAvL69NqKyqqkJKSkqb+6amprbe5iQtcz3+aV8Qz24L4N3i0JjBH46KQcwlW5FLAx7OD/XsvH0oiHeLg7CEwJwRLhv6MPuG7tSPLsf69Vx3a3dtuo5x/XUcrbGw7mRfG5Op2mWEVWsPUd/miJ5WAJg4cSLWrVuHBQsW4IUXXmj9+6JFizB//nwA9s/P6na74fP5bH2OPx7Qsafa1qcAEDpDe1K6jrxkHdOzDKwpvTA27u4hBga6Q2PmDlSHPrS3lFu4caCBGYN0rLdhR1h2sgwJErbmX31jwG/vt6EArly/cBs9ejT+JmG7LK8HntstoUFdoFL9HnvsMayZ/0ivl7O5QsOSIxIa1Ikr1S5WB+aMcMESAosP2HPi2qVee20Rbkz/o5Rlrf37Drz4/PtSliVDQcEyXHd9fqSbQQ5z8ZDGaOOY0Pr0009j/fr1ePHFF7F27Vrk5+dj586dKC0txZw5c/D2229fFlpTU1Nx/vz5Nn+rrq5uva27NE2zvcveZQQAhKd35MOjQfxqQizuGmxg/cnQdcz7xwP3DDHQaAosLb6Q/t4/EsS1GTruH+bC1+VNl11is7fcHjfcLhn9uBJn2u9Ee/WLBE3XuzR2rzMJsABInin+ClSpn8vlgscT0+vlxNWYAMJwxISOa/edYQb6x2tYU2LiWG14ChobGwePR85Y3pEjB1/xdp+vAXfO+NcOb/d44tsMCXjgnufg93c8ZrVlmR22Z9SQqP2aligSHPPF2rRp07Bs2TJcddVV2Lt3LzZs2IDJkydj165drUclEyZMaPOY/Px8FBUVtflby+8jR6p5XelwflW6p1LgeK2F/vEabhoYeuKHR4TmZF153ETlRfmvogH4x0kTSbEa7hsq/2QTWesd6fpFgrzahXfwhzL1k7Q5R3rbG+jWcEdO6CIgBUfCE54Bueudm5cFl+vKL4jP19Dhz6UB1e/v+L4tPx1JSnZjYGb3OzeIqGOOCa0AMGvWLBQWFqKxsRGnT5/GW2+9heHDh2P79u0ALh8ecMcdd2DVqlWt02EBQEFBAUaMGNHtk7DCJTkuvM+3snnC8bsHGxjfP3TyVUW9wKoTl39d+9ExE/VBgduyDQx0yws4Hpe8wJQcF97gdXH9IjXeNyVWzjMndeHqSrJFU/2SJS2nqy6t3QPDDMToGnwBge/nu/Cj0e3/3JIpd7eRIvE9FxvrQu7wgdKW1xsjR2VH7RncRJHiqNDanmAwiD179iArKwsZGRltbnviiSdgWRYeeughrFu3DgsXLsTrr7+Op556KkKt7Vy4d3xbz1gorxPI8uh4eESoh+Od4vYnIq8NhMbTuXQNc/Lk9bbKDJqyAkhXXVy/SemReTsmSwqbsYYGT5gHHKlRP1mhVcpiuuzS2iU2r0eOV2+dJqu9nxEpcusse71vmKLGZbhvuGl0pJtAFHUcM6a1I/v27UNDQ0O7J2Glp6djzZo1+NnPfoaZM2diwIABePnll5W9sAAgP3QtP2pi+dGOT3IRAH79ddfnxPnomImPjsk9aaYr10/vKtk70N7U72wD8Oh6+8fYyuzpSo7V4A/KGwvZF+on69sNma8D0P3abbvC1bHsJHu9773/Rry9eC2scFytoQNxcTG4657JEXt+omjl+NC6Y8cOAJePZ20xYcIEbNq0KYwt6p1w99aoQGbvcrh7qlUgc51T4oAye6+foRxZB4oJRmh8p12XS1VRjB5ab5kGDkzFlJvHYuPne+QuuBtuv3MikpKi9wxuokhx/PCARx99FEII/Pa3v410U6SQ3WvRF8gNXc6rn9yeaufVT9Y6a5om9bXoC1JiYcu4zzlzb43YeFKXy8BD37slIs9NFO0cH1qjTaoDQ1f/3s/W1KpfmE9kU0FqvLxtpp/Dtj+XBiT2frarVk57/9q1vuOuHoYHHppqy7I789jj30bu8MyIPDdRtHP88IBokxSrIS0+NJ7PKYYlyTv2krmsvsDQgByPvOAwLMlZoWtIogZD4lRfuUk6Dp6P3IUSwi3Xxvfbj//nTGz+cj9Olp7t8mMuncf1SlNatSd/VDa+/9ht3XoMEXWds/bQDjHcQcHL0IAhXnmhITVOc1Rv65BEDbGGvPoNT3bOtgfIX9/hyc4K/Xaub0JCHJ773VwkuLv3hu7KHKztSU724JnffL/TeWKJqOectYdxCCft+AZ75YYuwFnBS/YBTj+Hhf48yT3LTjrgBOxf31FjBuP3Lz2O+HiJYzja4U1MwEv/+S8YMnSArc9D5HTO+oR0CCft+PJsCJiyg4jKhtuwrk7a/uSHfrknxqksJTY8Y8gnXjsCf3j1J7adzZ+WnoxXX/8ZRo258iVkiaj3nLN3cZDBXg2SOx+VlWtD6LJznJ1q7OhVznVIT39yrNyTAIHQmfRO6ekfnqyH7Qz/cVcPw5J3/w9unj5O6nLvnHkt3lr6a+SNyJK6XCJqnzM+HR0m1tAwvn/0v7QuDRjXz4bQleSMqYeyPRrSJYcuAJiYFv3bHhBaTztCl5PqF07905Lw/As/wLO/m4uMASm9WlZ2Thp+//KP8OSzD3M+VqIw4uwBUer2bAM7zkb3LOU3Drxw6UmZXLqGWwcZ+OAKVxOKBrfnGLaEroFuHeP6aSisjNwVicLhW9n2nHBz/QAdS4tDlz2OVokxofUMN03T8K1vT8SM2yZg86Z9+KDgS2z9uqhLj9V1DVNuHov7Z03BtZPzoevOOLggUglDa5Qak6ohy62hrC56g8PtNoUGAJg+yMBHx0xIvCKpUjwu4EYbQ8PtOQYKK4O2LT/SxqRqyPbaU78YXcOM5u0vWs0YZCBG4lRh3WUYOqbechWm3nIVqqp8OLC/BEX7S3DowEnU1NQhGAgiJtaF5BQP8kdmY9ToHIwclY2kZE/E2kxEDK1RS9M0fCvbwFsHozM45CdrGJJoX+hKjtUweYCOr05HZ2/1LVkG4mwc+Dyun44BCRrK66Mz9dvVy9pixiADK4+bMKOwfIYWWj9VpKZ6ccNNo3HDTaMj3RQi6gS/34hiUwbqSLNhzKIK7h1q//HW3YMNuKLwnCK3y/7QpWsa7h2qTjCRabBXwzU2j8fsF6dhWmZ0fjxPy9Qdd+U0IpIjOj8VCQAQ79Lwy/ExiI+y7DAr18C4MJxoluPV8aPR0fVlhA7gZ1fFoL/ES7d2ZGqmYesQjkhIjgV+MT4GehjOen8434URUTYTQ16yhofzo+s9RUThowkhovALKLrY4RoLrxYGUNkY6Zb0jqEB9w8zcM8Qe04g6simUyaWHAyioY8PMfS4gP8xxoVr0sIXJC0h8G6xidUlJvr6B02mW8PPx7mQ5Qnfsb4/IPD6viB2nev7w1TG99fxxBgXPDHRFcSJKHwYWh2iyRRYU2pi1QkTvj52VrIO4LoMHQ/kujDAHZkd3vkmgQ+PBrHplIVAH8sP8QZw66BQ2I9UYCjxWXjvsInd56w+F15TYkPDUW7J0uGKwMlDQgjsrrRQcNjECV9fq15oOMWs4QbG9wvfvKxEFJ0YWh0maAnsrxLYesbEtgoLdYqep6UBGJ2q4foMA5PS7ZnaqifqgwI7z1rYesbC7nOWsrMLxOrANWk6JmfoGN9fl36p256qahT45xkTW89YOHRe0eIBSIoJHShNzjCQn6KFZThAV5T6Qtve1jMWTik8M0imW8PkjND2Z9csC0TkPAytDha0BI7UCJT6BUp9VvO/Av4wB1lDA7I8GrJbfrwacpN0JCkSVDtSF2yu30W1O+kXaApzT2y8AQxqrluOR2+un2br7AAyVDYKHKuxUOJr3gb9AqfrBKwwfyIlxgA5Xg3ZzbXL9moYlqhOUG2PEAKn6gSO14rWba/Ub+FsQ/jbkhaPC7XzaBiSqCHTrbFXlYikY2ilNoQQqGoCTvoEztQL+AICviDgCwj4A0BtoPlvAaCpkzGeugZ4YwBvjHbZv4kxoWmlBnk0DHRrEfna1Q6WCNWt1CdQ1Yjm+gnUNqG1lv7m+gU7CbcuPRSo2tbvwv/7xYVOFusfD6UDVncELIFT/lD4P98UqlPL9nbptthZuI0zLt/mLv49I0FDjldT/uCoO+qDodqV+UXze/WS+jX/W28CV/rk1zQgwWj/veuNARJjNGR5Qu/fhGicYoOIlMTQSkRERETK42AjIiIiIlIeQysRERERKY+hlYiIiIiUx9BKRERERMpjaCUiIiIi5TG0EhEREZHyGFqJiIiISHkMrURERESkPIZWIiIiIlIeQysRERERKY+hlYiIiIiUx9BKRERERMpjaCUiIiIi5TG0EhEREZHyGFqJiIiISHkMrURERESkPIZWIiIiIlIeQysRERERKY+hlYiIiIiUx9BKRERERMpjaCUiIiIi5TG0EhEREZHyGFqJiIiISHkMrURERESkPIZWIiIiIlIeQysRERERKY+hlYiIiIiUx9BKRERERMpjaCUiIiIi5TG0EhEREZHy/j8k8gaRWXaTRgAAAABJRU5ErkJggg==", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "qutip_qip.circuit.QubitCircuit.draw(new_qc)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7a4e83a8", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "694323ad", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "qutip-dev", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.3" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} From 6d3b07a5eda5af0363ab0be4f5713cdc7e4c6dda Mon Sep 17 00:00:00 2001 From: Rochisha Agarwal Date: Mon, 5 May 2025 15:52:35 +0530 Subject: [PATCH 5/7] Revert "add tests" This reverts commit f5c0281bec54999baded2f5323bad245f07c06b9. --- Untitled.ipynb | 136 ---------------------- src/qutip_qip/algorithms/__init__.py | 4 +- src/qutip_qip/circuit/__init__.py | 2 +- src/qutip_qip/circuit/circuit.py | 2 - src/qutip_qip/circuit/circuitsimulator.py | 5 +- src/qutip_qip/circuit/optimise.py | 82 ------------- tests/test_bit_flip.py | 82 ------------- tests/test_phase_flip.py | 127 -------------------- tests/test_shor_code.py | 44 ------- 9 files changed, 4 insertions(+), 480 deletions(-) delete mode 100644 Untitled.ipynb delete mode 100644 src/qutip_qip/circuit/optimise.py delete mode 100644 tests/test_bit_flip.py delete mode 100644 tests/test_phase_flip.py delete mode 100644 tests/test_shor_code.py diff --git a/Untitled.ipynb b/Untitled.ipynb deleted file mode 100644 index cd69be0d..00000000 --- a/Untitled.ipynb +++ /dev/null @@ -1,136 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 9, - "id": "2693ed1c-1af0-4667-a776-bbf727fff1f8", - "metadata": {}, - "outputs": [], - "source": [ - "from qutip_qip.algorithms import qft_gate_sequence" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "521f488b-fc92-4ceb-9e9c-720b30e5f753", - "metadata": {}, - "outputs": [], - "source": [ - "qc = qft_gate_sequence(N=2)" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "ba97064a-81ea-4b0a-a3cd-d113cd789bef", - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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b0mQQiGGUiGBsvGz97UYihbLlI3LdFoZ9Fo55HJ23O4oj8cDq93lk1RY7U44XR44XW7vh9MDh8sNp9MNp9v7+sp1Lpe7cZsW61weOJwt1rk83mM0rne4PPB0cZYiEgFSiRhSqRgyiRgSiQiyxtdSiRhSiaiVdaLG9WLIpC3WtdineZ1YBJlUDLlUgijV5Rt9pVwS8TI3IiKitjBRICIiIiIiP3z0SkREREREfpgoEBERERGRHyYKRERERETkh4kCERERERH5YaJARERERER+mCgQEREREZEfJgpEREREROSHiQIREREREflhokBERERERH6YKBARERERkR8mCkRERERE5IeJAhERERER+WGiQEREREREfpgoEBERERGRHyYKRERERETkh4kCERERERH5YaJARERERER+mCgQEREREZEfJgpEREREROSHiQIREREREflhokBERERERH6YKBARERERkR8mCkRERERE5IeJAhERERER+WGiQEREREREfpgoEBERERGRHyYKRERERETkh4kCERERERH5YaJARERERER+mCgQEREREZGf/w9M7fAmx/+pvwAAAABJRU5ErkJggg==", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "qc" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "id": "8ffd2e9f-d2a0-4119-9339-58389484ca45", - "metadata": {}, - "outputs": [], - "source": [ - "from qutip_qip.algorithms import qpe" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "51e7662e-0ffb-4035-bb83-ae410e8cc4c8", - "metadata": {}, - "outputs": [], - "source": [ - "from qutip import Qobj, basis\n", - "import numpy as np\n", - "theta1 = 0.25 # 1/4 (corresponds to π/2 phase)\n", - "U1 = Qobj([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, np.exp(1j * np.pi/4)]])\n", - " # |1⟩ is an eigenstate of this operator\n", - "eigenstate1 = basis(2, 1)" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "94294b6f-b32a-4fc0-b1a3-fab7cad3d750", - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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++yzm9z2nHPOUdeuXbV27VotXLiwyW08Hk+jZRdeeKGef/55bdiwQeXl5SotLdWSJUt02223yeFwBG3bs2fPhvdqx44dkqSzzjqrUb3NpqSmpuqvf/2rNmzYoKqqKhUWFuqdd95p9N5FKtokbbIptEkAAAAgOlB2AIgwp59+uiTpq6++avYs0zNnztR1112n4uJizZ07V0lJSTr77LM1adIk/ehHP9Kzzz7b5H5/+9vfNGXKFC1atEh79+7VxIkT9dxzz+ngwYN67733Grb74IMPGpIDF1xwgbp06aK3335bFRUVDdts3br1uDFefvnleuihh7R+/XrNnTtXOTk5GjNmjPr27au1a9dKkk455RR99tlnSk5O1jfffKPt27drzJgxuvPOO3XBBRdo3LhxKi8vb9ZrEkrDhw/Xxx9/rE6dOmnTpk2aM2eOunfvrptuuknnn3++TjvttKBJgmJiYvTJJ59ozJgx2r59u2bNmqWBAwfq/fff17p16xodv/49/+KLL1oU13PPPaeMjAytWLFCK1asUGJiosaMGaNHHnlEkydP1hVXXNGwbUVFRUNtzaSkJF199dU6cOCAPvjgg+M+R7du3fTZZ5+pf//+2rlzp+bNm6esrCxdeumlOu+883T22WdryZIlLYq7o6FN0iabizYJAAAARCADgOXmzp1rSArJ7f777zcMwzAeeeSRZm1/2WWXGYZhGFu2bDGys7Mblo8bN87weDxGRUWF0alTp6B9Pv/8c8MwDGPHjh1Gjx49Gpb/7Gc/MwzDMN5///1jPl/9vj179mxWfPXbu91uY+rUqUHrsrOzjb59+zY8XrFihWEYhnHHHXc0LHM6ncbbb79tGIZhPPjgg8d8nhdeeMEwDMOYOHFis19rwzCM7du3H3cbp9NpbN682TAMw7jnnnuC1l133XVNvv933HGHYRiG8fHHHxsxMTENyx9++OGGv5kj43z99dcNwzCMO++8s0V/K//3f/9npKenBy2LjY01PvnkE8MwDOOMM85ocr+ePXsahmEYn3/+ebPfv8cee8xwOp0Ny8844wyjpqbGWLNmTcj+9iUZBw4caGtzNAzDMJYsWRKymGiTtMnm3iKxTa5evbqtzREAAADo0Cg7AESY+kt5y8rKmrV9/aXFf/zjH1VQUNCw/JtvvtErr7yixMREXXvttU3u++CDD2rXrl0N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AACQnFYHYJX77rtP06ZNU2xsrCZNmqSYmBh98cUXmjx5skaNGiVJOvnkky2OEtEkKyvL6hCADi3UbYg2CbQNbQgAAACI0uTra6+9pmnTpmn06NGaNWuWunXrJknavXu3Ro8erffee0+xsbEaMmSIxZEimmRmZlodAtChhboN0SaBtqENAQAAAFFYdqC8vFy33XabUlNTNWfOnIbEqyR1795dN998syRp6NChcjrrctNvvvmmLrroIuXk5Cg1NVUTJkzQokWLLIkfkYsRQkDbMPIVCC+0IQAAACAKk6/PPvusioqKdNtttyknJ6fR+n79+kkKLjnwz3/+U1lZWXr88cf11ltvqWvXrjr77LO1atWqdosbka+lndT4+HgNGjRIKSkpJkUEWKNTp07q379/wxdgzWV18jU2NlYDBw5Uenp6SOMArJaRkaGBAwcqJiamRfuRfAUAAACisOzA7NmzJUnXXXddk+urq6slBSdf58yZE3Tp3DnnnKOTTjpJjz/+uJ555plWxWEYhqqqqlq1LyJTUlJSs7cdPny45s2bp9zcXFVUVOiaa67RBx98YGJ0QPu48847NWPGDNntdn377bc6//zzVVRU1Kx94+PjVVlZGbJYEhMTm71tnz599NFHH6lv376qqanRD37wA7322mshiwWwyve//30988wzcrlc2rRpk84991zt3r27WfsmJCSEtE0CAAAg8iQkJMhms1kdhrmMKJOcnGzExsYagUCgyfU//vGPDUnGl19+edzjXHvttcY555zT6jgqKioMSdy4ter2zTffBP09FRcXGzabzfK4uHFry23AgAGN/lc++uijlsfVnNv//ve/oLg9Ho+RnJxseVzcuLXllpmZadTW1gb9bb/xxhuWx8WNGzdu3Lhx48Ytcm4VFRWtzq11FFFVdsDr9aq8vFzx8fFNZtVra2s1a9Ys2e12DR8+/JjH8fv9Wrp0aUOJAqC95ebmBj1OT09XQkKCRdEAodFUKZgj63KHs6PbZGxsLJdco8PLzs6Wy+UKWtZR2iQAAAAQLqKq7IDL5VJ6errcbrfcbnejunzTp09Xfn6+BgwYcNxLwB977DHt2rVLt956a6tjSUhIUEVFRav3R+QpKytrlMA5lo8++qhhcjhJWrRoEZd2osNbtWqVDhw4oC5dujQsa245jf79+2vFihUhjccwDGVlZamm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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "qpe(U1, 2)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "66e0314e-c0ed-436e-8868-e2bd90782b5a", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "qutip-dev", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.3" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/src/qutip_qip/algorithms/__init__.py b/src/qutip_qip/algorithms/__init__.py index c2893b6f..4971be21 100644 --- a/src/qutip_qip/algorithms/__init__.py +++ b/src/qutip_qip/algorithms/__init__.py @@ -1,4 +1,2 @@ from .qft import * -from .error_correction.bit_flip import * -from .error_correction.phase_flip import * -from .error_correction.shor_code import * \ No newline at end of file +from .error_correction.bit_flip import * \ No newline at end of file diff --git a/src/qutip_qip/circuit/__init__.py b/src/qutip_qip/circuit/__init__.py index 54664869..d0264108 100644 --- a/src/qutip_qip/circuit/__init__.py +++ b/src/qutip_qip/circuit/__init__.py @@ -5,7 +5,7 @@ from .circuit import * from .circuitsimulator import * from ..operations import Gate, Measurement -from .optimise import * + def _add_deprecation(fun, msg): def newfun(*args, **kwargs): diff --git a/src/qutip_qip/circuit/circuit.py b/src/qutip_qip/circuit/circuit.py index e92be52a..dd413c21 100644 --- a/src/qutip_qip/circuit/circuit.py +++ b/src/qutip_qip/circuit/circuit.py @@ -1036,5 +1036,3 @@ def _to_qasm(self, qasm_out): for op in self.gates: op._to_qasm(qasm_out) - - \ No newline at end of file diff --git a/src/qutip_qip/circuit/circuitsimulator.py b/src/qutip_qip/circuit/circuitsimulator.py index 1132b532..1e73d343 100644 --- a/src/qutip_qip/circuit/circuitsimulator.py +++ b/src/qutip_qip/circuit/circuitsimulator.py @@ -8,12 +8,11 @@ Measurement, expand_operator, ) - from qutip import basis, ket2dm, Qobj, tensor import warnings -__all__ = ["CircuitSimulator", "CircuitResult", "gate_sequence_product"] +__all__ = ["CircuitSimulator", "CircuitResult"] def _flatten(lst): @@ -133,7 +132,7 @@ def _expand_overall(tensor_list, overall_inds): return U_overall, overall_inds -def gate_sequence_product(U_list, ind_list): +def _gate_sequence_product(U_list, ind_list): """ Calculate the overall unitary matrix for a given list of unitary operations that are still of original dimension. diff --git a/src/qutip_qip/circuit/optimise.py b/src/qutip_qip/circuit/optimise.py deleted file mode 100644 index be927a9d..00000000 --- a/src/qutip_qip/circuit/optimise.py +++ /dev/null @@ -1,82 +0,0 @@ -from qutip_qip.decompose.decompose_single_qubit_gate import decompose_one_qubit_gate -from qutip_qip.circuit import QubitCircuit -from qutip_qip.circuit import gate_sequence_product - -__all__ = ["optimise"] - -def optimise(circuit): - optimized_gates = [] - i = 0 - while i < len(circuit.gates): - gate = circuit.gates[i] - if gate.targets and len(gate.targets) == 1 and not gate.controls: - qubit = gate.targets[0] - sq_gates = [] - # Gather all consecutive single-qubit gates on the same qubit - while i < len(circuit.gates): - g = circuit.gates[i] - if g.targets == [qubit] and not g.controls: - sq_gates.append(g) - i += 1 - else: - break - if len(sq_gates) == 1: - optimized_gates.append(sq_gates[0]) - else: - try: - # Get all gate unitaries for the sequence - unitaries = [g.get_unitary() for g in sq_gates] - - # Combine them into a single unitary - u_combined = gate_sequence_product(unitaries) - - # Use the decompose_one_qubit_gate function to decompose into ZYZ form - - # Decompose the combined unitary into ZYZ gates - zyz_gates = decompose_one_qubit_gate(u_combined, decomposition="ZYZ", target=qubit) - - # Add decomposed gates to the optimized circuit - optimized_gates.extend(zyz_gates) - except Exception as e: - print(f"Decomposition failed: {e}") - # Fallback to original gates if decomposition fails - optimized_gates.extend(sq_gates) - else: - optimized_gates.append(gate) - i += 1 - - new_circuit = QubitCircuit(N=circuit.N) - new_circuit.gates = optimized_gates - return new_circuit - -def run_example(): - """Run a complete example of quantum circuit optimization.""" - print("=== Quantum Circuit Optimization Example ===") - - # Example 1: A circuit with 4 single-qubit gates - print("\nExample 1: Four consecutive single-qubit gates") - qc1 = QubitCircuit(N=1) - qc1.add_gate("RX", targets=[0], arg_value=0.2) - qc1.add_gate("RY", targets=[0], arg_value=0.1) - qc1.add_gate("RY", targets=[0], arg_value=0.1) - qc1.add_gate("RZ", targets=[0], arg_value=0.3) - - QubitCircuit.draw(qc1) - optimized_qc1 = optimise(qc1) - QubitCircuit.draw(optimized_qc1) - - # Example 2: A circuit with mixed single and multi-qubit gates - print("\n\nExample 2: Mixed single and multi-qubit gates") - qc2 = QubitCircuit(N=2) - qc2.add_gate("RX", targets=[0], arg_value=0.2) - qc2.add_gate("RY", targets=[0], arg_value=0.3) - qc2.add_gate("CNOT", controls=[0], targets=[1]) - qc2.add_gate("RZ", targets=[1], arg_value=0.1) - qc2.add_gate("RX", targets=[1], arg_value=0.4) - - QubitCircuit.draw(qc2) - optimized_qc2 = optimise(qc2) - QubitCircuit.draw(optimized_qc2) - - -run_example() diff --git a/tests/test_bit_flip.py b/tests/test_bit_flip.py deleted file mode 100644 index 342b5215..00000000 --- a/tests/test_bit_flip.py +++ /dev/null @@ -1,82 +0,0 @@ -import pytest -import numpy as np -from qutip_qip.algorithms import BitFlipCode - -def test_encode_circuit_structure(): - """Test that the encoding circuit has the correct structure.""" - qc = BitFlipCode.encode_circuit() - - # Check circuit has correct number of qubits - assert qc.N == 3 - - # Check it has 2 CNOT gates - assert len(qc.gates) == 2 - assert all(gate.name == "CNOT" for gate in qc.gates) - - # Check gate connections - QubitCircuit uses lists for controls and targets - assert qc.gates[0].controls == [0] - assert qc.gates[0].targets[0] == 1 - assert qc.gates[1].controls == [0] - assert qc.gates[1].targets[0] == 2 - -def test_syndrome_measurement_circuit_structure(): - """Test that the syndrome measurement circuit has the correct structure.""" - qc = BitFlipCode.syndrome_measurement_circuit() - - # Check circuit has correct number of qubits (3 data + 2 syndrome) - assert qc.N == 5 - - # Check it has 4 CNOT gates - assert len(qc.gates) == 4 - assert all(gate.name == "CNOT" for gate in qc.gates) - - # Check gate connections for syndrome measurement - assert qc.gates[0].controls == [0] and qc.gates[0].targets[0] == 3 - assert qc.gates[1].controls == [1] and qc.gates[1].targets[0] == 3 - assert qc.gates[2].controls == [1] and qc.gates[2].targets[0] == 4 - assert qc.gates[3].controls == [2] and qc.gates[3].targets[0] == 4 - -def test_correction_circuit_no_error(): - """Test correction circuit with no error (syndrome 00).""" - qc = BitFlipCode.correction_circuit((0, 0)) - assert qc.N == 3 - assert len(qc.gates) == 0 # No correction needed - -def test_correction_circuit_qubit0_error(): - """Test correction circuit with error on qubit 0 (syndrome 10).""" - qc = BitFlipCode.correction_circuit((1, 0)) - assert qc.N == 3 - assert len(qc.gates) == 1 - assert qc.gates[0].name == "X" and qc.gates[0].targets[0] == 0 - -def test_correction_circuit_qubit1_error(): - """Test correction circuit with error on qubit 1 (syndrome 11).""" - qc = BitFlipCode.correction_circuit((1, 1)) - assert qc.N == 3 - assert len(qc.gates) == 1 - assert qc.gates[0].name == "X" and qc.gates[0].targets[0] == 1 - -def test_correction_circuit_qubit2_error(): - """Test correction circuit with error on qubit 2 (syndrome 01).""" - qc = BitFlipCode.correction_circuit((0, 1)) - assert qc.N == 3 - assert len(qc.gates) == 1 - assert qc.gates[0].name == "X" and qc.gates[0].targets[0] == 2 - -def test_decode_circuit_structure(): - """Test that the decoding circuit has the correct structure.""" - qc = BitFlipCode.decode_circuit() - - # Check circuit has correct number of qubits - assert qc.N == 3 - - # Check it has 2 CNOT gates and 1 TOFFOLI gate - assert len(qc.gates) == 3 - assert qc.gates[0].name == "CNOT" - assert qc.gates[1].name == "CNOT" - assert qc.gates[2].name == "TOFFOLI" - - # Check gate connections - assert qc.gates[0].controls == [0] and qc.gates[0].targets[0] == 2 - assert qc.gates[1].controls == [0] and qc.gates[1].targets[0] == 1 - assert qc.gates[2].controls == [1, 2] and qc.gates[2].targets[0] == 0 diff --git a/tests/test_phase_flip.py b/tests/test_phase_flip.py deleted file mode 100644 index 81a687bb..00000000 --- a/tests/test_phase_flip.py +++ /dev/null @@ -1,127 +0,0 @@ -import pytest -import numpy as np -from qutip import Qobj, tensor, basis, fidelity -from qutip_qip.algorithms import PhaseFlipCode - -def test_encode_circuit_structure(): - """Test that the encoding circuit has the correct structure.""" - qc = PhaseFlipCode.encode_circuit() - - # Check circuit has correct number of qubits - assert qc.N == 3 - - # Check it has correct number of gates (1 H + 2 CNOT + 3 H = 6 gates) - assert len(qc.gates) == 6 - - # Check first gate is Hadamard on qubit 0 - assert qc.gates[0].name == "SNOT" - assert qc.gates[0].targets[0] == 0 - - # Check CNOT gates - assert qc.gates[1].name == "CNOT" - assert qc.gates[1].controls == [0] - assert qc.gates[1].targets[0] == 1 - - assert qc.gates[2].name == "CNOT" - assert qc.gates[2].controls == [0] - assert qc.gates[2].targets[0] == 2 - - # Check final Hadamard gates on all qubits - assert qc.gates[3].name == "SNOT" - assert qc.gates[3].targets[0] == 0 - - assert qc.gates[4].name == "SNOT" - assert qc.gates[4].targets[0] == 1 - - assert qc.gates[5].name == "SNOT" - assert qc.gates[5].targets[0] == 2 - -def test_syndrome_measurement_circuit_structure(): - """Test that the syndrome measurement circuit has the correct structure.""" - qc = PhaseFlipCode.syndrome_measurement_circuit() - - # Check circuit has correct number of qubits (3 data + 2 syndrome) - assert qc.N == 5 - - # Check it has the correct number of gates (3 H + 4 CNOT + 3 H = 10 gates) - assert len(qc.gates) == 10 - - # Check first three Hadamard gates on data qubits - for i in range(3): - assert qc.gates[i].name == "SNOT" - assert qc.gates[i].targets[0] == i - - # Check CNOT gates for syndrome measurement - assert qc.gates[3].name == "CNOT" - assert qc.gates[3].controls == [0] and qc.gates[3].targets[0] == 3 - - assert qc.gates[4].name == "CNOT" - assert qc.gates[4].controls == [1] and qc.gates[4].targets[0] == 3 - - assert qc.gates[5].name == "CNOT" - assert qc.gates[5].controls == [1] and qc.gates[5].targets[0] == 4 - - assert qc.gates[6].name == "CNOT" - assert qc.gates[6].controls == [2] and qc.gates[6].targets[0] == 4 - - # Check final three Hadamard gates on data qubits - for i in range(3): - assert qc.gates[7+i].name == "SNOT" - assert qc.gates[7+i].targets[0] == i - -def test_correction_circuit_no_error(): - """Test correction circuit with no error (syndrome 00).""" - qc = PhaseFlipCode.correction_circuit((0, 0)) - assert qc.N == 3 - assert len(qc.gates) == 0 # No correction needed - -def test_correction_circuit_qubit0_error(): - """Test correction circuit with error on qubit 0 (syndrome 10).""" - qc = PhaseFlipCode.correction_circuit((1, 0)) - assert qc.N == 3 - assert len(qc.gates) == 1 - assert qc.gates[0].name == "Z" and qc.gates[0].targets[0] == 0 - -def test_correction_circuit_qubit1_error(): - """Test correction circuit with error on qubit 1 (syndrome 11).""" - qc = PhaseFlipCode.correction_circuit((1, 1)) - assert qc.N == 3 - assert len(qc.gates) == 1 - assert qc.gates[0].name == "Z" and qc.gates[0].targets[0] == 1 - -def test_correction_circuit_qubit2_error(): - """Test correction circuit with error on qubit 2 (syndrome 01).""" - qc = PhaseFlipCode.correction_circuit((0, 1)) - assert qc.N == 3 - assert len(qc.gates) == 1 - assert qc.gates[0].name == "Z" and qc.gates[0].targets[0] == 2 - -def test_decode_circuit_structure(): - """Test that the decoding circuit has the correct structure.""" - qc = PhaseFlipCode.decode_circuit() - - # Check circuit has correct number of qubits - assert qc.N == 3 - - # Check it has the correct number of gates (3 H + 2 CNOT + 1 TOFFOLI + 1 H = 7 gates) - assert len(qc.gates) == 7 - - # Check first three Hadamard gates - for i in range(3): - assert qc.gates[i].name == "SNOT" - assert qc.gates[i].targets[0] == i - - # Check the two CNOT gates - assert qc.gates[3].name == "CNOT" - assert qc.gates[3].controls == [0] and qc.gates[3].targets[0] == 2 - - assert qc.gates[4].name == "CNOT" - assert qc.gates[4].controls == [0] and qc.gates[4].targets[0] == 1 - - # Check the TOFFOLI gate - assert qc.gates[5].name == "TOFFOLI" - assert qc.gates[5].controls == [1, 2] and qc.gates[5].targets[0] == 0 - - # Check the final Hadamard gate - assert qc.gates[6].name == "SNOT" - assert qc.gates[6].targets[0] == 0 diff --git a/tests/test_shor_code.py b/tests/test_shor_code.py deleted file mode 100644 index 41403d96..00000000 --- a/tests/test_shor_code.py +++ /dev/null @@ -1,44 +0,0 @@ -import pytest -from qutip_qip.algorithms import ShorCode - -def test_encode_circuit(): - """Test the Shor code encoding circuit structure.""" - qc = ShorCode.encode_circuit() - - # Check correct number of qubits - assert qc.N == 9 - - # Check total number of gates (1H + 2CNOT + 3H + 6CNOT = 12 gates) - assert len(qc.gates) == 12 - - # Check first Hadamard gate (phase-flip encoding starts) - assert qc.gates[0].name == "SNOT" and qc.gates[0].targets[0] == 0 - - # Check first level CNOTs (create GHZ-like state across blocks) - assert qc.gates[1].name == "CNOT" - assert qc.gates[1].controls == [0] and qc.gates[1].targets[0] == 3 - assert qc.gates[2].name == "CNOT" - assert qc.gates[2].controls == [0] and qc.gates[2].targets[0] == 6 - - # Check three Hadamard gates (complete phase-flip encoding) - assert qc.gates[3].name == "SNOT" and qc.gates[3].targets[0] == 0 - assert qc.gates[4].name == "SNOT" and qc.gates[4].targets[0] == 3 - assert qc.gates[5].name == "SNOT" and qc.gates[5].targets[0] == 6 - - # Check bit-flip encoding CNOTs for first block - assert qc.gates[6].name == "CNOT" - assert qc.gates[6].controls == [0] and qc.gates[6].targets[0] == 1 - assert qc.gates[7].name == "CNOT" - assert qc.gates[7].controls == [0] and qc.gates[7].targets[0] == 2 - - # Check bit-flip encoding CNOTs for second block - assert qc.gates[8].name == "CNOT" - assert qc.gates[8].controls == [3] and qc.gates[8].targets[0] == 4 - assert qc.gates[9].name == "CNOT" - assert qc.gates[9].controls == [3] and qc.gates[9].targets[0] == 5 - - # Check bit-flip encoding CNOTs for third block - assert qc.gates[10].name == "CNOT" - assert qc.gates[10].controls == [6] and qc.gates[10].targets[0] == 7 - assert qc.gates[11].name == "CNOT" - assert qc.gates[11].controls == [6] and qc.gates[11].targets[0] == 8 From 78bdc11e50a1cc06c9809f924f5e086abd351a5b Mon Sep 17 00:00:00 2001 From: Rochisha Agarwal Date: Mon, 5 May 2025 17:01:41 +0530 Subject: [PATCH 6/7] clear files --- src/qutip_qip/algorithms/__init__.py | 5 +- tests/test_bit_flip.py | 82 +++++++++++++++++ tests/test_phase_flip.py | 127 +++++++++++++++++++++++++++ tests/test_shor_code.py | 44 ++++++++++ 4 files changed, 257 insertions(+), 1 deletion(-) create mode 100644 tests/test_bit_flip.py create mode 100644 tests/test_phase_flip.py create mode 100644 tests/test_shor_code.py diff --git a/src/qutip_qip/algorithms/__init__.py b/src/qutip_qip/algorithms/__init__.py index 4971be21..21e4e445 100644 --- a/src/qutip_qip/algorithms/__init__.py +++ b/src/qutip_qip/algorithms/__init__.py @@ -1,2 +1,5 @@ from .qft import * -from .error_correction.bit_flip import * \ No newline at end of file +from .qpe import * +from .error_correction.bit_flip import * +from .error_correction.phase_flip import * +from .error_correction.shor_code import * \ No newline at end of file diff --git a/tests/test_bit_flip.py b/tests/test_bit_flip.py new file mode 100644 index 00000000..342b5215 --- /dev/null +++ b/tests/test_bit_flip.py @@ -0,0 +1,82 @@ +import pytest +import numpy as np +from qutip_qip.algorithms import BitFlipCode + +def test_encode_circuit_structure(): + """Test that the encoding circuit has the correct structure.""" + qc = BitFlipCode.encode_circuit() + + # Check circuit has correct number of qubits + assert qc.N == 3 + + # Check it has 2 CNOT gates + assert len(qc.gates) == 2 + assert all(gate.name == "CNOT" for gate in qc.gates) + + # Check gate connections - QubitCircuit uses lists for controls and targets + assert qc.gates[0].controls == [0] + assert qc.gates[0].targets[0] == 1 + assert qc.gates[1].controls == [0] + assert qc.gates[1].targets[0] == 2 + +def test_syndrome_measurement_circuit_structure(): + """Test that the syndrome measurement circuit has the correct structure.""" + qc = BitFlipCode.syndrome_measurement_circuit() + + # Check circuit has correct number of qubits (3 data + 2 syndrome) + assert qc.N == 5 + + # Check it has 4 CNOT gates + assert len(qc.gates) == 4 + assert all(gate.name == "CNOT" for gate in qc.gates) + + # Check gate connections for syndrome measurement + assert qc.gates[0].controls == [0] and qc.gates[0].targets[0] == 3 + assert qc.gates[1].controls == [1] and qc.gates[1].targets[0] == 3 + assert qc.gates[2].controls == [1] and qc.gates[2].targets[0] == 4 + assert qc.gates[3].controls == [2] and qc.gates[3].targets[0] == 4 + +def test_correction_circuit_no_error(): + """Test correction circuit with no error (syndrome 00).""" + qc = BitFlipCode.correction_circuit((0, 0)) + assert qc.N == 3 + assert len(qc.gates) == 0 # No correction needed + +def test_correction_circuit_qubit0_error(): + """Test correction circuit with error on qubit 0 (syndrome 10).""" + qc = BitFlipCode.correction_circuit((1, 0)) + assert qc.N == 3 + assert len(qc.gates) == 1 + assert qc.gates[0].name == "X" and qc.gates[0].targets[0] == 0 + +def test_correction_circuit_qubit1_error(): + """Test correction circuit with error on qubit 1 (syndrome 11).""" + qc = BitFlipCode.correction_circuit((1, 1)) + assert qc.N == 3 + assert len(qc.gates) == 1 + assert qc.gates[0].name == "X" and qc.gates[0].targets[0] == 1 + +def test_correction_circuit_qubit2_error(): + """Test correction circuit with error on qubit 2 (syndrome 01).""" + qc = BitFlipCode.correction_circuit((0, 1)) + assert qc.N == 3 + assert len(qc.gates) == 1 + assert qc.gates[0].name == "X" and qc.gates[0].targets[0] == 2 + +def test_decode_circuit_structure(): + """Test that the decoding circuit has the correct structure.""" + qc = BitFlipCode.decode_circuit() + + # Check circuit has correct number of qubits + assert qc.N == 3 + + # Check it has 2 CNOT gates and 1 TOFFOLI gate + assert len(qc.gates) == 3 + assert qc.gates[0].name == "CNOT" + assert qc.gates[1].name == "CNOT" + assert qc.gates[2].name == "TOFFOLI" + + # Check gate connections + assert qc.gates[0].controls == [0] and qc.gates[0].targets[0] == 2 + assert qc.gates[1].controls == [0] and qc.gates[1].targets[0] == 1 + assert qc.gates[2].controls == [1, 2] and qc.gates[2].targets[0] == 0 diff --git a/tests/test_phase_flip.py b/tests/test_phase_flip.py new file mode 100644 index 00000000..81a687bb --- /dev/null +++ b/tests/test_phase_flip.py @@ -0,0 +1,127 @@ +import pytest +import numpy as np +from qutip import Qobj, tensor, basis, fidelity +from qutip_qip.algorithms import PhaseFlipCode + +def test_encode_circuit_structure(): + """Test that the encoding circuit has the correct structure.""" + qc = PhaseFlipCode.encode_circuit() + + # Check circuit has correct number of qubits + assert qc.N == 3 + + # Check it has correct number of gates (1 H + 2 CNOT + 3 H = 6 gates) + assert len(qc.gates) == 6 + + # Check first gate is Hadamard on qubit 0 + assert qc.gates[0].name == "SNOT" + assert qc.gates[0].targets[0] == 0 + + # Check CNOT gates + assert qc.gates[1].name == "CNOT" + assert qc.gates[1].controls == [0] + assert qc.gates[1].targets[0] == 1 + + assert qc.gates[2].name == "CNOT" + assert qc.gates[2].controls == [0] + assert qc.gates[2].targets[0] == 2 + + # Check final Hadamard gates on all qubits + assert qc.gates[3].name == "SNOT" + assert qc.gates[3].targets[0] == 0 + + assert qc.gates[4].name == "SNOT" + assert qc.gates[4].targets[0] == 1 + + assert qc.gates[5].name == "SNOT" + assert qc.gates[5].targets[0] == 2 + +def test_syndrome_measurement_circuit_structure(): + """Test that the syndrome measurement circuit has the correct structure.""" + qc = PhaseFlipCode.syndrome_measurement_circuit() + + # Check circuit has correct number of qubits (3 data + 2 syndrome) + assert qc.N == 5 + + # Check it has the correct number of gates (3 H + 4 CNOT + 3 H = 10 gates) + assert len(qc.gates) == 10 + + # Check first three Hadamard gates on data qubits + for i in range(3): + assert qc.gates[i].name == "SNOT" + assert qc.gates[i].targets[0] == i + + # Check CNOT gates for syndrome measurement + assert qc.gates[3].name == "CNOT" + assert qc.gates[3].controls == [0] and qc.gates[3].targets[0] == 3 + + assert qc.gates[4].name == "CNOT" + assert qc.gates[4].controls == [1] and qc.gates[4].targets[0] == 3 + + assert qc.gates[5].name == "CNOT" + assert qc.gates[5].controls == [1] and qc.gates[5].targets[0] == 4 + + assert qc.gates[6].name == "CNOT" + assert qc.gates[6].controls == [2] and qc.gates[6].targets[0] == 4 + + # Check final three Hadamard gates on data qubits + for i in range(3): + assert qc.gates[7+i].name == "SNOT" + assert qc.gates[7+i].targets[0] == i + +def test_correction_circuit_no_error(): + """Test correction circuit with no error (syndrome 00).""" + qc = PhaseFlipCode.correction_circuit((0, 0)) + assert qc.N == 3 + assert len(qc.gates) == 0 # No correction needed + +def test_correction_circuit_qubit0_error(): + """Test correction circuit with error on qubit 0 (syndrome 10).""" + qc = PhaseFlipCode.correction_circuit((1, 0)) + assert qc.N == 3 + assert len(qc.gates) == 1 + assert qc.gates[0].name == "Z" and qc.gates[0].targets[0] == 0 + +def test_correction_circuit_qubit1_error(): + """Test correction circuit with error on qubit 1 (syndrome 11).""" + qc = PhaseFlipCode.correction_circuit((1, 1)) + assert qc.N == 3 + assert len(qc.gates) == 1 + assert qc.gates[0].name == "Z" and qc.gates[0].targets[0] == 1 + +def test_correction_circuit_qubit2_error(): + """Test correction circuit with error on qubit 2 (syndrome 01).""" + qc = PhaseFlipCode.correction_circuit((0, 1)) + assert qc.N == 3 + assert len(qc.gates) == 1 + assert qc.gates[0].name == "Z" and qc.gates[0].targets[0] == 2 + +def test_decode_circuit_structure(): + """Test that the decoding circuit has the correct structure.""" + qc = PhaseFlipCode.decode_circuit() + + # Check circuit has correct number of qubits + assert qc.N == 3 + + # Check it has the correct number of gates (3 H + 2 CNOT + 1 TOFFOLI + 1 H = 7 gates) + assert len(qc.gates) == 7 + + # Check first three Hadamard gates + for i in range(3): + assert qc.gates[i].name == "SNOT" + assert qc.gates[i].targets[0] == i + + # Check the two CNOT gates + assert qc.gates[3].name == "CNOT" + assert qc.gates[3].controls == [0] and qc.gates[3].targets[0] == 2 + + assert qc.gates[4].name == "CNOT" + assert qc.gates[4].controls == [0] and qc.gates[4].targets[0] == 1 + + # Check the TOFFOLI gate + assert qc.gates[5].name == "TOFFOLI" + assert qc.gates[5].controls == [1, 2] and qc.gates[5].targets[0] == 0 + + # Check the final Hadamard gate + assert qc.gates[6].name == "SNOT" + assert qc.gates[6].targets[0] == 0 diff --git a/tests/test_shor_code.py b/tests/test_shor_code.py new file mode 100644 index 00000000..41403d96 --- /dev/null +++ b/tests/test_shor_code.py @@ -0,0 +1,44 @@ +import pytest +from qutip_qip.algorithms import ShorCode + +def test_encode_circuit(): + """Test the Shor code encoding circuit structure.""" + qc = ShorCode.encode_circuit() + + # Check correct number of qubits + assert qc.N == 9 + + # Check total number of gates (1H + 2CNOT + 3H + 6CNOT = 12 gates) + assert len(qc.gates) == 12 + + # Check first Hadamard gate (phase-flip encoding starts) + assert qc.gates[0].name == "SNOT" and qc.gates[0].targets[0] == 0 + + # Check first level CNOTs (create GHZ-like state across blocks) + assert qc.gates[1].name == "CNOT" + assert qc.gates[1].controls == [0] and qc.gates[1].targets[0] == 3 + assert qc.gates[2].name == "CNOT" + assert qc.gates[2].controls == [0] and qc.gates[2].targets[0] == 6 + + # Check three Hadamard gates (complete phase-flip encoding) + assert qc.gates[3].name == "SNOT" and qc.gates[3].targets[0] == 0 + assert qc.gates[4].name == "SNOT" and qc.gates[4].targets[0] == 3 + assert qc.gates[5].name == "SNOT" and qc.gates[5].targets[0] == 6 + + # Check bit-flip encoding CNOTs for first block + assert qc.gates[6].name == "CNOT" + assert qc.gates[6].controls == [0] and qc.gates[6].targets[0] == 1 + assert qc.gates[7].name == "CNOT" + assert qc.gates[7].controls == [0] and qc.gates[7].targets[0] == 2 + + # Check bit-flip encoding CNOTs for second block + assert qc.gates[8].name == "CNOT" + assert qc.gates[8].controls == [3] and qc.gates[8].targets[0] == 4 + assert qc.gates[9].name == "CNOT" + assert qc.gates[9].controls == [3] and qc.gates[9].targets[0] == 5 + + # Check bit-flip encoding CNOTs for third block + assert qc.gates[10].name == "CNOT" + assert qc.gates[10].controls == [6] and qc.gates[10].targets[0] == 7 + assert qc.gates[11].name == "CNOT" + assert qc.gates[11].controls == [6] and qc.gates[11].targets[0] == 8 From 9e4dc2b96771f1746f34954b83ac991c9311af91 Mon Sep 17 00:00:00 2001 From: Rochisha Agarwal Date: Mon, 5 May 2025 17:06:34 +0530 Subject: [PATCH 7/7] lint fixes --- .../algorithms/error_correction/bit_flip.py | 36 ++++++------ .../algorithms/error_correction/phase_flip.py | 57 ++++++++++--------- .../algorithms/error_correction/shor_code.py | 33 +++++------ tests/test_bit_flip.py | 25 +++++--- tests/test_phase_flip.py | 57 +++++++++++-------- tests/test_shor_code.py | 19 ++++--- 6 files changed, 122 insertions(+), 105 deletions(-) diff --git a/src/qutip_qip/algorithms/error_correction/bit_flip.py b/src/qutip_qip/algorithms/error_correction/bit_flip.py index 8e5012f9..b4d3a0b8 100644 --- a/src/qutip_qip/algorithms/error_correction/bit_flip.py +++ b/src/qutip_qip/algorithms/error_correction/bit_flip.py @@ -7,10 +7,11 @@ __all__ = ["BitFlipCode"] + class BitFlipCode: """ Implementation of the 3-qubit bit-flip code. - + The bit-flip code protects against X (bit-flip) errors by encoding a single logical qubit across three physical qubits: |0⟩ → |000⟩ @@ -21,7 +22,7 @@ class BitFlipCode: def encode_circuit(): """ Create a circuit for encoding a single qubit into the 3-qubit bit-flip code. - + Returns ------- qc : instance of QubitCircuit @@ -31,39 +32,39 @@ def encode_circuit(): qc.add_gate("CNOT", controls=0, targets=1) qc.add_gate("CNOT", controls=0, targets=2) return qc - + @staticmethod def syndrome_measurement_circuit(): """ Create a circuit for syndrome measurement of the 3-qubit bit-flip code. - + Returns ------- qc : instance of QubitCircuit Syndrome measurement circuit that uses two ancilla qubits. """ qc = QubitCircuit(5) # 3 data qubits + 2 syndrome qubits - + # First syndrome measurement: Parity of qubits 0 and 1 qc.add_gate("CNOT", controls=0, targets=3) qc.add_gate("CNOT", controls=1, targets=3) - + # Second syndrome measurement: Parity of qubits 1 and 2 qc.add_gate("CNOT", controls=1, targets=4) qc.add_gate("CNOT", controls=2, targets=4) - + return qc - + @staticmethod def correction_circuit(syndrome): """ Create a circuit for error correction based on syndrome measurement. - + Parameters ---------- syndrome : tuple Two-bit syndrome measurement result (s1, s2). - + Returns ------- qc : instance of QubitCircuit @@ -71,13 +72,13 @@ def correction_circuit(syndrome): """ qc = QubitCircuit(3) s1, s2 = syndrome - + # Syndrome interpretation: # s1=0, s2=0: No error # s1=1, s2=0: Error on qubit 0 # s1=1, s2=1: Error on qubit 1 # s1=0, s2=1: Error on qubit 2 - + if s1 == 1 and s2 == 0: # Error on qubit 0 qc.add_gate("X", targets=0) @@ -87,14 +88,14 @@ def correction_circuit(syndrome): elif s1 == 0 and s2 == 1: # Error on qubit 2 qc.add_gate("X", targets=2) - + return qc - + @staticmethod def decode_circuit(): """ Create a circuit for decoding the 3-qubit bit-flip code. - + Returns ------- qc : instance of QubitCircuit @@ -103,10 +104,9 @@ def decode_circuit(): qc = QubitCircuit(3) qc.add_gate("CNOT", controls=0, targets=2) qc.add_gate("CNOT", controls=0, targets=1) - + # Add a Toffoli gate to verify the parity # If all qubits have the same value, the result is stored in qubit 0 qc.add_gate("TOFFOLI", controls=[1, 2], targets=0) - + return qc - \ No newline at end of file diff --git a/src/qutip_qip/algorithms/error_correction/phase_flip.py b/src/qutip_qip/algorithms/error_correction/phase_flip.py index dfa93699..c591bfc7 100644 --- a/src/qutip_qip/algorithms/error_correction/phase_flip.py +++ b/src/qutip_qip/algorithms/error_correction/phase_flip.py @@ -5,6 +5,7 @@ __all__ = ["PhaseFlipCode"] + class PhaseFlipCode: """ Implementation of the 3-qubit phase-flip code. @@ -12,75 +13,75 @@ class PhaseFlipCode: a single logical qubit across three physical qubits: |0⟩ → |+++⟩ |1⟩ → |---⟩ - + This is accomplished by applying Hadamard gates to transform the bit-flip code into the phase-flip code, as phase errors in the Hadamard basis appear as bit-flips. """ - + @staticmethod def encode_circuit(): """ Create a circuit for encoding a single qubit into the 3-qubit phase-flip code. - + Returns ------- qc : instance of QubitCircuit Encoding circuit for the phase-flip code. """ qc = QubitCircuit(3) - + # First apply Hadamard to the input qubit qc.add_gate("SNOT", targets=0) - + # Then use the bit-flip encoding structure qc.add_gate("CNOT", controls=0, targets=1) qc.add_gate("CNOT", controls=0, targets=2) - + # Apply Hadamard gates to all qubits qc.add_gate("SNOT", targets=0) qc.add_gate("SNOT", targets=1) qc.add_gate("SNOT", targets=2) - + return qc - + @staticmethod def syndrome_measurement_circuit(): """ Create a circuit for syndrome measurement of the 3-qubit phase-flip code. - + Returns ------- qc : instance of QubitCircuit Syndrome measurement circuit that uses two ancilla qubits. """ qc = QubitCircuit(5) # 3 data qubits + 2 syndrome qubits - + qc.add_gate("SNOT", targets=0) qc.add_gate("SNOT", targets=1) qc.add_gate("SNOT", targets=2) - + qc.add_gate("CNOT", controls=0, targets=3) qc.add_gate("CNOT", controls=1, targets=3) - + qc.add_gate("CNOT", controls=1, targets=4) qc.add_gate("CNOT", controls=2, targets=4) - + qc.add_gate("SNOT", targets=0) qc.add_gate("SNOT", targets=1) qc.add_gate("SNOT", targets=2) - + return qc - + @staticmethod def correction_circuit(syndrome): """ Create a circuit for error correction based on syndrome measurement. - + Parameters ---------- syndrome : tuple Two-bit syndrome measurement result (s1, s2). - + Returns ------- qc : instance of QubitCircuit @@ -88,43 +89,43 @@ def correction_circuit(syndrome): """ qc = QubitCircuit(3) s1, s2 = syndrome - + # Syndrome interpretation: # s1=0, s2=0: No error # s1=1, s2=0: Error on qubit 0 # s1=1, s2=1: Error on qubit 1 # s1=0, s2=1: Error on qubit 2 - + if s1 == 1 and s2 == 0: qc.add_gate("Z", targets=0) elif s1 == 1 and s2 == 1: qc.add_gate("Z", targets=1) elif s1 == 0 and s2 == 1: qc.add_gate("Z", targets=2) - + return qc - + @staticmethod def decode_circuit(): """ Create a circuit for decoding the 3-qubit phase-flip code. - + Returns ------- qc : instance of QubitCircuit Decoding circuit for the phase-flip code. """ qc = QubitCircuit(3) - + qc.add_gate("SNOT", targets=0) qc.add_gate("SNOT", targets=1) qc.add_gate("SNOT", targets=2) - + qc.add_gate("CNOT", controls=0, targets=2) qc.add_gate("CNOT", controls=0, targets=1) - + qc.add_gate("TOFFOLI", controls=[1, 2], targets=0) - + qc.add_gate("SNOT", targets=0) - - return qc \ No newline at end of file + + return qc diff --git a/src/qutip_qip/algorithms/error_correction/shor_code.py b/src/qutip_qip/algorithms/error_correction/shor_code.py index a573b5ee..735a9864 100644 --- a/src/qutip_qip/algorithms/error_correction/shor_code.py +++ b/src/qutip_qip/algorithms/error_correction/shor_code.py @@ -5,61 +5,62 @@ __all__ = ["ShorCode"] + class ShorCode: """ Implementation of the 9-qubit Shor code. - + The Shor code protects against arbitrary single-qubit errors by combining the 3-qubit phase-flip code with the 3-qubit bit-flip code. - + The logical states are encoded as: |0⟩ → (|000⟩ + |111⟩)(|000⟩ + |111⟩)(|000⟩ + |111⟩) / 2√2 |1⟩ → (|000⟩ - |111⟩)(|000⟩ - |111⟩)(|000⟩ - |111⟩) / 2√2 - - This encoding allows correction of any single-qubit error (bit-flip, phase-flip, + + This encoding allows correction of any single-qubit error (bit-flip, phase-flip, or both) on any of the 9 physical qubits. """ - + @staticmethod def encode_circuit(): """ Create a circuit for encoding a single qubit into the 9-qubit Shor code. - + The encoding process: 1. Apply phase-flip encoding to the input (creating |+++⟩ or |---⟩) 2. Apply bit-flip encoding to each of the three qubits - + Returns ------- qc : instance of QubitCircuit Encoding circuit for the Shor code. """ qc = QubitCircuit(9) - + # Step 1: Phase-flip encoding on the first qubit # Apply Hadamard to the input qubit qc.add_gate("SNOT", targets=0) - + # Create the GHZ-like state by using CNOTs qc.add_gate("CNOT", controls=0, targets=3) qc.add_gate("CNOT", controls=0, targets=6) - - # Apply Hadamard to all three qubits + + # Apply Hadamard to all three qubits qc.add_gate("SNOT", targets=0) qc.add_gate("SNOT", targets=3) qc.add_gate("SNOT", targets=6) - + # Step 2: Bit-flip encoding for each of the three blocks # First block: qubits 0,1,2 qc.add_gate("CNOT", controls=0, targets=1) qc.add_gate("CNOT", controls=0, targets=2) - + # Second block: qubits 3,4,5 qc.add_gate("CNOT", controls=3, targets=4) qc.add_gate("CNOT", controls=3, targets=5) - + # Third block: qubits 6,7,8 qc.add_gate("CNOT", controls=6, targets=7) qc.add_gate("CNOT", controls=6, targets=8) - - return qc \ No newline at end of file + + return qc diff --git a/tests/test_bit_flip.py b/tests/test_bit_flip.py index 342b5215..cd7e23ac 100644 --- a/tests/test_bit_flip.py +++ b/tests/test_bit_flip.py @@ -2,46 +2,50 @@ import numpy as np from qutip_qip.algorithms import BitFlipCode + def test_encode_circuit_structure(): """Test that the encoding circuit has the correct structure.""" qc = BitFlipCode.encode_circuit() - + # Check circuit has correct number of qubits assert qc.N == 3 - + # Check it has 2 CNOT gates assert len(qc.gates) == 2 assert all(gate.name == "CNOT" for gate in qc.gates) - + # Check gate connections - QubitCircuit uses lists for controls and targets assert qc.gates[0].controls == [0] assert qc.gates[0].targets[0] == 1 assert qc.gates[1].controls == [0] assert qc.gates[1].targets[0] == 2 + def test_syndrome_measurement_circuit_structure(): """Test that the syndrome measurement circuit has the correct structure.""" qc = BitFlipCode.syndrome_measurement_circuit() - + # Check circuit has correct number of qubits (3 data + 2 syndrome) assert qc.N == 5 - + # Check it has 4 CNOT gates assert len(qc.gates) == 4 assert all(gate.name == "CNOT" for gate in qc.gates) - + # Check gate connections for syndrome measurement assert qc.gates[0].controls == [0] and qc.gates[0].targets[0] == 3 assert qc.gates[1].controls == [1] and qc.gates[1].targets[0] == 3 assert qc.gates[2].controls == [1] and qc.gates[2].targets[0] == 4 assert qc.gates[3].controls == [2] and qc.gates[3].targets[0] == 4 + def test_correction_circuit_no_error(): """Test correction circuit with no error (syndrome 00).""" qc = BitFlipCode.correction_circuit((0, 0)) assert qc.N == 3 assert len(qc.gates) == 0 # No correction needed + def test_correction_circuit_qubit0_error(): """Test correction circuit with error on qubit 0 (syndrome 10).""" qc = BitFlipCode.correction_circuit((1, 0)) @@ -49,6 +53,7 @@ def test_correction_circuit_qubit0_error(): assert len(qc.gates) == 1 assert qc.gates[0].name == "X" and qc.gates[0].targets[0] == 0 + def test_correction_circuit_qubit1_error(): """Test correction circuit with error on qubit 1 (syndrome 11).""" qc = BitFlipCode.correction_circuit((1, 1)) @@ -56,6 +61,7 @@ def test_correction_circuit_qubit1_error(): assert len(qc.gates) == 1 assert qc.gates[0].name == "X" and qc.gates[0].targets[0] == 1 + def test_correction_circuit_qubit2_error(): """Test correction circuit with error on qubit 2 (syndrome 01).""" qc = BitFlipCode.correction_circuit((0, 1)) @@ -63,19 +69,20 @@ def test_correction_circuit_qubit2_error(): assert len(qc.gates) == 1 assert qc.gates[0].name == "X" and qc.gates[0].targets[0] == 2 + def test_decode_circuit_structure(): """Test that the decoding circuit has the correct structure.""" qc = BitFlipCode.decode_circuit() - + # Check circuit has correct number of qubits assert qc.N == 3 - + # Check it has 2 CNOT gates and 1 TOFFOLI gate assert len(qc.gates) == 3 assert qc.gates[0].name == "CNOT" assert qc.gates[1].name == "CNOT" assert qc.gates[2].name == "TOFFOLI" - + # Check gate connections assert qc.gates[0].controls == [0] and qc.gates[0].targets[0] == 2 assert qc.gates[1].controls == [0] and qc.gates[1].targets[0] == 1 diff --git a/tests/test_phase_flip.py b/tests/test_phase_flip.py index 81a687bb..f3005186 100644 --- a/tests/test_phase_flip.py +++ b/tests/test_phase_flip.py @@ -3,71 +3,74 @@ from qutip import Qobj, tensor, basis, fidelity from qutip_qip.algorithms import PhaseFlipCode + def test_encode_circuit_structure(): """Test that the encoding circuit has the correct structure.""" qc = PhaseFlipCode.encode_circuit() - + # Check circuit has correct number of qubits assert qc.N == 3 - + # Check it has correct number of gates (1 H + 2 CNOT + 3 H = 6 gates) assert len(qc.gates) == 6 - + # Check first gate is Hadamard on qubit 0 assert qc.gates[0].name == "SNOT" assert qc.gates[0].targets[0] == 0 - + # Check CNOT gates assert qc.gates[1].name == "CNOT" assert qc.gates[1].controls == [0] assert qc.gates[1].targets[0] == 1 - + assert qc.gates[2].name == "CNOT" assert qc.gates[2].controls == [0] assert qc.gates[2].targets[0] == 2 - + # Check final Hadamard gates on all qubits assert qc.gates[3].name == "SNOT" assert qc.gates[3].targets[0] == 0 - + assert qc.gates[4].name == "SNOT" assert qc.gates[4].targets[0] == 1 - + assert qc.gates[5].name == "SNOT" assert qc.gates[5].targets[0] == 2 + def test_syndrome_measurement_circuit_structure(): """Test that the syndrome measurement circuit has the correct structure.""" qc = PhaseFlipCode.syndrome_measurement_circuit() - + # Check circuit has correct number of qubits (3 data + 2 syndrome) assert qc.N == 5 - + # Check it has the correct number of gates (3 H + 4 CNOT + 3 H = 10 gates) assert len(qc.gates) == 10 - + # Check first three Hadamard gates on data qubits for i in range(3): assert qc.gates[i].name == "SNOT" assert qc.gates[i].targets[0] == i - + # Check CNOT gates for syndrome measurement assert qc.gates[3].name == "CNOT" assert qc.gates[3].controls == [0] and qc.gates[3].targets[0] == 3 - + assert qc.gates[4].name == "CNOT" assert qc.gates[4].controls == [1] and qc.gates[4].targets[0] == 3 - + assert qc.gates[5].name == "CNOT" assert qc.gates[5].controls == [1] and qc.gates[5].targets[0] == 4 - + assert qc.gates[6].name == "CNOT" assert qc.gates[6].controls == [2] and qc.gates[6].targets[0] == 4 - + # Check final three Hadamard gates on data qubits for i in range(3): - assert qc.gates[7+i].name == "SNOT" - assert qc.gates[7+i].targets[0] == i + assert qc.gates[7 + i].name == "SNOT" + assert qc.gates[7 + i].targets[0] == i + def test_correction_circuit_no_error(): """Test correction circuit with no error (syndrome 00).""" @@ -75,6 +78,7 @@ def test_correction_circuit_no_error(): assert qc.N == 3 assert len(qc.gates) == 0 # No correction needed + def test_correction_circuit_qubit0_error(): """Test correction circuit with error on qubit 0 (syndrome 10).""" qc = PhaseFlipCode.correction_circuit((1, 0)) @@ -82,6 +86,7 @@ def test_correction_circuit_qubit0_error(): assert len(qc.gates) == 1 assert qc.gates[0].name == "Z" and qc.gates[0].targets[0] == 0 + def test_correction_circuit_qubit1_error(): """Test correction circuit with error on qubit 1 (syndrome 11).""" qc = PhaseFlipCode.correction_circuit((1, 1)) @@ -89,6 +94,7 @@ def test_correction_circuit_qubit1_error(): assert len(qc.gates) == 1 assert qc.gates[0].name == "Z" and qc.gates[0].targets[0] == 1 + def test_correction_circuit_qubit2_error(): """Test correction circuit with error on qubit 2 (syndrome 01).""" qc = PhaseFlipCode.correction_circuit((0, 1)) @@ -96,32 +102,33 @@ def test_correction_circuit_qubit2_error(): assert len(qc.gates) == 1 assert qc.gates[0].name == "Z" and qc.gates[0].targets[0] == 2 + def test_decode_circuit_structure(): """Test that the decoding circuit has the correct structure.""" qc = PhaseFlipCode.decode_circuit() - + # Check circuit has correct number of qubits assert qc.N == 3 - + # Check it has the correct number of gates (3 H + 2 CNOT + 1 TOFFOLI + 1 H = 7 gates) assert len(qc.gates) == 7 - + # Check first three Hadamard gates for i in range(3): assert qc.gates[i].name == "SNOT" assert qc.gates[i].targets[0] == i - + # Check the two CNOT gates assert qc.gates[3].name == "CNOT" assert qc.gates[3].controls == [0] and qc.gates[3].targets[0] == 2 - + assert qc.gates[4].name == "CNOT" assert qc.gates[4].controls == [0] and qc.gates[4].targets[0] == 1 - + # Check the TOFFOLI gate assert qc.gates[5].name == "TOFFOLI" assert qc.gates[5].controls == [1, 2] and qc.gates[5].targets[0] == 0 - + # Check the final Hadamard gate assert qc.gates[6].name == "SNOT" assert qc.gates[6].targets[0] == 0 diff --git a/tests/test_shor_code.py b/tests/test_shor_code.py index 41403d96..24a9cc08 100644 --- a/tests/test_shor_code.py +++ b/tests/test_shor_code.py @@ -1,42 +1,43 @@ import pytest from qutip_qip.algorithms import ShorCode + def test_encode_circuit(): """Test the Shor code encoding circuit structure.""" qc = ShorCode.encode_circuit() - + # Check correct number of qubits assert qc.N == 9 - + # Check total number of gates (1H + 2CNOT + 3H + 6CNOT = 12 gates) assert len(qc.gates) == 12 - + # Check first Hadamard gate (phase-flip encoding starts) assert qc.gates[0].name == "SNOT" and qc.gates[0].targets[0] == 0 - + # Check first level CNOTs (create GHZ-like state across blocks) assert qc.gates[1].name == "CNOT" assert qc.gates[1].controls == [0] and qc.gates[1].targets[0] == 3 assert qc.gates[2].name == "CNOT" assert qc.gates[2].controls == [0] and qc.gates[2].targets[0] == 6 - + # Check three Hadamard gates (complete phase-flip encoding) assert qc.gates[3].name == "SNOT" and qc.gates[3].targets[0] == 0 assert qc.gates[4].name == "SNOT" and qc.gates[4].targets[0] == 3 assert qc.gates[5].name == "SNOT" and qc.gates[5].targets[0] == 6 - + # Check bit-flip encoding CNOTs for first block - assert qc.gates[6].name == "CNOT" + assert qc.gates[6].name == "CNOT" assert qc.gates[6].controls == [0] and qc.gates[6].targets[0] == 1 assert qc.gates[7].name == "CNOT" assert qc.gates[7].controls == [0] and qc.gates[7].targets[0] == 2 - + # Check bit-flip encoding CNOTs for second block assert qc.gates[8].name == "CNOT" assert qc.gates[8].controls == [3] and qc.gates[8].targets[0] == 4 assert qc.gates[9].name == "CNOT" assert qc.gates[9].controls == [3] and qc.gates[9].targets[0] == 5 - + # Check bit-flip encoding CNOTs for third block assert qc.gates[10].name == "CNOT" assert qc.gates[10].controls == [6] and qc.gates[10].targets[0] == 7