{ "cells": [ { "attachments": {}, "cell_type": "markdown", "id": "681e955a", "metadata": {}, "source": [ "# Advanced Operations of Quantum Circuit\n", "\n", "[![Download Notebook](https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/website-images/master/resource/_static/logo_notebook_en.svg)](https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/notebook/master/mindquantum/en/beginner/mindspore_advanced_operations_of_quantum_circuit.ipynb) \n", "[![Download Code](https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/website-images/master/resource/_static/logo_download_code_en.svg)](https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/notebook/master/mindquantum/en/beginner/mindspore_advanced_operations_of_quantum_circuit.py) \n", "[![View source on Gitee](https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/website-images/master/resource/_static/logo_source_en.svg)](https://gitee.com/mindspore/docs/blob/master/docs/mindquantum/docs/source_en/beginner/advanced_operations_of_quantum_circuit.ipynb)\n", "\n", "In previous tutorial we introduced the basic usage of [quantum circuit](https://mindspore.cn/mindquantum/docs/en/master/beginner/parameterized_quantum_circuit.html#quantum-circuit). In this tutorial, we will introduce how to operator the circuit in high level.\n", "\n", "## [mindquantum.core.circuit.controlled](https://www.mindspore.cn/mindquantum/docs/en/master/core/circuit/mindquantum.core.circuit.controlled.html)\n", "\n", "The [controlled](https://www.mindspore.cn/mindquantum/docs/en/master/core/circuit/mindquantum.core.circuit.controlled.html) method is used to add control qubits (which can be multiple) to any quantum circuit or quantum operator.\n", "\n", "For example, let's build a quantum circuit containing only two qubits and add a control qubit - $q_2$ to it by a [controlled](https://www.mindspore.cn/mindquantum/docs/en/master/core/circuit/mindquantum.core.circuit.controlled.html) method:" ] }, { "cell_type": "code", "execution_count": 1, "id": "c44755ab", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "q0: q1: H PS π/2 H " ], "text/plain": [ "" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from mindquantum.algorithm.library import qft\n", "from mindquantum.core.circuit import controlled\n", "\n", "u1 = qft(range(2)) # Build the quantum circuit\n", "u1.svg()" ] }, { "cell_type": "code", "execution_count": 2, "id": "9330f35e", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "q0: q1: q2: H PS π/2 H " ], "text/plain": [ "" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "u2 = controlled(u1)(2) # Add control qubit q2 to the circuit, returning a new circuit\n", "u2.svg()" ] }, { "cell_type": "markdown", "id": "4d63b2ef", "metadata": {}, "source": [ "Actually, [controlled()](https://www.mindspore.cn/mindquantum/docs/en/master/core/circuit/mindquantum.core.circuit.controlled.html) returns a function. E.g:" ] }, { "cell_type": "code", "execution_count": 3, "id": "6144080f", "metadata": {}, "outputs": [], "source": [ "u3 = controlled(u1)" ] }, { "cell_type": "markdown", "id": "3c2a5acf", "metadata": {}, "source": [ "We can add control qubits to the initial circuit u1 by calling u3, which has the same effect as above:" ] }, { "cell_type": "code", "execution_count": 4, "id": "39a3af2d", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "q0: q1: q2: H PS π/2 H " ], "text/plain": [ "" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "u4 = u3(2)\n", "u4.svg()" ] }, { "cell_type": "markdown", "id": "5381a350", "metadata": {}, "source": [ "Note: The added control qubit cannot be the target qubit of a gate that already exists in the circuit, otherwise an error will be reported!\n", "\n", "In addition, we can batch add control qubits to the quantum circuit. For example, in the following example we add control qubits - $q_2$ and $q_3$ to $q_0$ and $q_1$ respectively:" ] }, { "cell_type": "code", "execution_count": 5, "id": "bb5e74ff", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "q0: q1: q2: q3: H PS π/2 H " ], "text/plain": [ "" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "u = controlled(qft)\n", "u = u([2, 3], [0, 1]) # Bulk add control qubits\n", "u.svg()" ] }, { "cell_type": "markdown", "id": "f991b869", "metadata": {}, "source": [ "## [mindquantum.core.circuit.dagger](https://www.mindspore.cn/mindquantum/docs/en/master/core/circuit/mindquantum.core.circuit.dagger.html)\n", "\n", "The [dagger](https://www.mindspore.cn/mindquantum/docs/en/master/core/circuit/mindquantum.core.circuit.dagger.html) method is used to find the Hermitian conjugates of quantum circuits or quantum operators.\n", "\n", "The following examples provide two ways of doing dagger operations:" ] }, { "cell_type": "code", "execution_count": 6, "id": "7d203008", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "q0: q1: q2: H PS π/2 PS π/4 H PS π/2 H " ], "text/plain": [ "" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from mindquantum.core.circuit import dagger\n", "\n", "u1 = qft(range(3))\n", "u1.svg()" ] }, { "cell_type": "code", "execution_count": 7, "id": "1229c41f", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "q0: q1: q2: H PS -π/2 H PS -π/4 PS -π/2 H " ], "text/plain": [ "" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "u2 = dagger(u1)\n", "u2.svg()" ] }, { "cell_type": "code", "execution_count": 8, "id": "26239556", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "q0: q1: q2: H PS -π/2 H PS -π/4 PS -π/2 H " ], "text/plain": [ "" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "u3 = dagger(qft)\n", "u4 = u3(range(3))\n", "u4.svg()" ] }, { "cell_type": "markdown", "id": "69117023", "metadata": {}, "source": [ "It can be seen that the circuits obtained by the two methods are the same.\n", "\n", "## [mindquantum.core.circuit.apply](https://www.mindspore.cn/mindquantum/docs/en/master/core/circuit/mindquantum.core.circuit.apply.html)\n", "\n", "The [apply](https://www.mindspore.cn/mindquantum/docs/en/master/core/circuit/mindquantum.core.circuit.apply.html) method is used to apply a quantum circuit or quantum operator to the specified qubits (which can be multiple)." ] }, { "cell_type": "code", "execution_count": 9, "id": "865da650", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "q0: q1: H PS π/2 H " ], "text/plain": [ "" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from mindquantum.core.circuit import apply\n", "\n", "u1 = qft([0, 1])\n", "circuit1 = apply(u1, [1, 0]) # Apply quantum circuit u1 to qubits q1, q0\n", "circuit1.svg()" ] }, { "cell_type": "code", "execution_count": 10, "id": "67ed697a", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "q0: q1: H PS π/2 H " ], "text/plain": [ "" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "u2 = apply(qft, [1, 0]) # Apply qft to qubits q0, q1\n", "circuit2 = u2([0, 1])\n", "circuit2.svg()" ] }, { "cell_type": "markdown", "id": "553beec8", "metadata": {}, "source": [ "## [mindquantum.core.circuit.add_prefix](https://www.mindspore.cn/mindquantum/docs/en/master/core/circuit/mindquantum.core.circuit.add_prefix.html)\n", "\n", "The [add_prefix](https://www.mindspore.cn/mindquantum/docs/en/master/core/circuit/mindquantum.core.circuit.add_prefix.html) method is used to prefix the parameter names of parameterized quantum circuits or parameterized quantum operators. This is useful in neural network layering, for example:" ] }, { "cell_type": "code", "execution_count": 11, "id": "5c70b2f8", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "q0: RX theta " ], "text/plain": [ "" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from mindquantum.core.circuit import add_prefix, Circuit\n", "from mindquantum.core.gates import RX, H\n", "\n", "circ = Circuit().rx(\"theta\", 0)\n", "circ.svg()" ] }, { "cell_type": "code", "execution_count": 12, "id": "3ecfc597", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "q0: RX l0_theta " ], "text/plain": [ "" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# After adding, the parameter \"theta\" becomes \"l0_theta\"\n", "circ = add_prefix(circ, 'l0')\n", "circ.svg()" ] }, { "cell_type": "markdown", "id": "e3c09fbc", "metadata": {}, "source": [ "We can prefix the parameter name of a parameterized qubit after it acts on a specific qubit, or we can add it when it has not yet been applied to the qubit. E.g:" ] }, { "cell_type": "code", "execution_count": 13, "id": "71f56c75", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "q0: H RX ansatz_a " ], "text/plain": [ "" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "u = lambda qubit: Circuit([H.on(0), RX('a').on(qubit)])\n", "\n", "u1 = u(0)\n", "u1 = add_prefix(u1, 'ansatz')\n", "u1.svg()" ] }, { "cell_type": "code", "execution_count": 14, "id": "edbf7b03", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "q0: H RX ansatz_a " ], "text/plain": [ "" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "\n", "u2 = add_prefix(u, 'ansatz')\n", "u2 = u2(0)\n", "u2.svg()" ] }, { "cell_type": "markdown", "id": "c05a8195", "metadata": {}, "source": [ "## [mindquantum.core.circuit.change_param_name](https://www.mindspore.cn/mindquantum/docs/en/master/core/circuit/mindquantum.core.circuit.change_param_name.html)\n", "\n", "The [change_param_name](https://www.mindspore.cn/mindquantum/docs/en/master/core/circuit/mindquantum.core.circuit.change_param_name.html) method is used to modify the parameter name of a parameterized quantum circuit or a parameterized quantum operator." ] }, { "cell_type": "code", "execution_count": 15, "id": "d844ba22", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "q0: H RX b " ], "text/plain": [ "" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from mindquantum.core.circuit import change_param_name, Circuit\n", "from mindquantum.core.gates import RX, H\n", "\n", "u = lambda qubit: Circuit([H.on(0), RX('a').on(qubit)])\n", "\n", "u1 = u(0)\n", "u1 = change_param_name(u1, {'a': 'b'})\n", "u1.svg()" ] }, { "cell_type": "code", "execution_count": 16, "id": "3a1d5d5f", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "q0: H RX b " ], "text/plain": [ "" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "u2 = change_param_name(u, {'a': 'b'})\n", "u2 = u2(0)\n", "u2.svg()" ] }, { "cell_type": "markdown", "id": "522ec9fc", "metadata": {}, "source": [ "## [mindquantum.core.circuit.UN](https://www.mindspore.cn/mindquantum/docs/en/master/core/circuit/mindquantum.core.circuit.UN.html)\n", "\n", "The [UN](https://www.mindspore.cn/mindquantum/docs/en/master/core/circuit/mindquantum.core.circuit.UN.html) module is used to actuate quantum gates on different target qubits and control qubits.\n", "\n", "The general format is as follows: `mindquantum.circuit.UN(gate, maps_obj, maps_ctrl=None)`, the parameter `gate` is the gate to be executed, `maps_obj` is the target qubit to be executed, and `maps_Ctrl` is the control qubit (None if there are no control qubits). If each qubit implements the same quantum gate without parameters, `UN(gate, N)` can be used directly, where `N` represents the number of qubits.\n", "\n", "Here is a simple example where we apply an [H-gate](https://www.mindspore.cn/mindquantum/docs/en/master/core/gates/mindquantum.core.gates.HGate.html) to each qubit in the [circuit](https://www.mindspore.cn/mindquantum/docs/en/master/core/circuit/mindquantum.core.circuit.Circuit.html) we build:" ] }, { "cell_type": "code", "execution_count": 17, "id": "6ba3b3ff", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "q0: q1: q2: q3: H H H H " ], "text/plain": [ "" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from mindquantum.core.circuit import change_param_name, Circuit, UN\n", "from mindquantum.core.gates import X, H, SWAP\n", "\n", "circuit1 = Circuit()\n", "circuit1 += UN(H, 4) # Apply the H gate to each qubit\n", "circuit1.svg()" ] }, { "cell_type": "markdown", "id": "52a24be7", "metadata": {}, "source": [ "In the following example, we add a [CNOT](https://www.mindspore.cn/mindquantum/docs/en/master/core/gates/mindquantum.core.gates.XGate.html) gate to the qubits $q_2$ and $q_0$, $q_3$ and $q_1$ respectively, where $q_2$ is the control bit, $q_0$ is the target bit; $q_3$ is the control bit , $q_1$ is the target bit:" ] }, { "cell_type": "code", "execution_count": 18, "id": "3fbb0af7", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "q0: q1: q2: q3: " ], "text/plain": [ "" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "circuit2 = UN(X, maps_obj=[0, 1], maps_ctrl=[2, 3])\n", "circuit2.svg()" ] }, { "attachments": {}, "cell_type": "markdown", "id": "e44d378e", "metadata": {}, "source": [ "For [SWAP](https://www.mindspore.cn/mindquantum/docs/en/master/core/gates/mindquantum.core.gates.SWAPGate.html) gate, the usage is as follows:" ] }, { "cell_type": "code", "execution_count": 19, "id": "2ccd1cf8", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "q0: q1: q2: q3: " ], "text/plain": [ "" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "circuit3 = UN(SWAP, maps_obj=[[0, 1], [2, 3]]).x(2, 1)\n", "circuit3.svg()" ] }, { "cell_type": "markdown", "id": "9b0d1910", "metadata": {}, "source": [ "## [mindquantum.core.circuit.shift](https://www.mindspore.cn/mindquantum/docs/en/master/core/circuit/mindquantum.core.circuit.shift.html)\n", "\n", "The [shift](https://www.mindspore.cn/mindquantum/docs/en/master/core/circuit/mindquantum.core.circuit.shift.html) method is used to modify the qubit range of a given circuit, and the parameter is the step size to be shifted. Note that the step size cannot be negative. Moreover, it can only move to the last qubit, and cannot cycle to $q_0$ (the first qubit)." ] }, { "cell_type": "code", "execution_count": 20, "id": "71d000ca", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "q0: q1: " ], "text/plain": [ "" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from mindquantum.core.circuit import shift, Circuit\n", "from mindquantum.core.gates import X\n", "\n", "circ = Circuit().x(1, 0)\n", "circ.svg()" ] }, { "cell_type": "code", "execution_count": 21, "id": "180fde8c", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "q1: q2: " ], "text/plain": [ "" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "circ = shift(circ, 1)\n", "circ.svg() # The qubit acting on the circuit changes from q0, q1 to q1, q2" ] }, { "attachments": {}, "cell_type": "markdown", "id": "b5050bd9", "metadata": {}, "source": [ "### Case - Iris Classification: Building Encoder\n", "\n", "The above examples of higher-order operations show the applicability and convenience of higher-order operations in quantum circuits. What magic will happen if we further combine them to build quantum circuits?\n", "\n", "Next we will start with [Classification of irises by quantum neural network](https://mindspore.cn/mindquantum/docs/en/master/case_library/classification_of_iris_by_qnn.html). Build the Encoder part as an example, build the quantum circuit shown in the figure below:\n", "\n", "![encoder classification of iris by qnn](https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/website-images/master/docs/mindquantum/docs/source_zh_cn/images/encoder_classification_of_iris_by_qnn.png)\n" ] }, { "cell_type": "code", "execution_count": 22, "id": "89bbaf78", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
                                    Circuit Summary                                     \n",
       "╭──────────────────────┬───────────────────────────────────────────────────────────────╮\n",
       "│ Info                  value                                                         │\n",
       "├──────────────────────┼───────────────────────────────────────────────────────────────┤\n",
       "│ Number of qubit      │ 4                                                             │\n",
       "├──────────────────────┼───────────────────────────────────────────────────────────────┤\n",
       "│ Total number of gate │ 17                                                            │\n",
       "│ Barrier              │ 0                                                             │\n",
       "│ Noise Channel        │ 0                                                             │\n",
       "│ Measurement          │ 0                                                             │\n",
       "├──────────────────────┼───────────────────────────────────────────────────────────────┤\n",
       "│ Parameter gate       │ 7                                                             │\n",
       "│ 7 ansatz parameters  │ 0_alpha, 1_alpha, 2_alpha, 3_alpha, 4_alpha, 5_alpha, 6_alpha │\n",
       "╰──────────────────────┴───────────────────────────────────────────────────────────────╯\n",
       "
\n" ], "text/plain": [ "\u001b[1;38;2;255;0;0m Circuit Summary \u001b[0m\n", "╭──────────────────────┬───────────────────────────────────────────────────────────────╮\n", "│\u001b[1m \u001b[0m\u001b[1;38;2;59;59;149mInfo\u001b[0m\u001b[1m \u001b[0m\u001b[1m \u001b[0m│\u001b[1m \u001b[0m\u001b[1;38;2;59;59;149mvalue\u001b[0m\u001b[1m \u001b[0m\u001b[1m \u001b[0m│\n", "├──────────────────────┼───────────────────────────────────────────────────────────────┤\n", "│ \u001b[1mNumber of qubit\u001b[0m │ 4 │\n", "├──────────────────────┼───────────────────────────────────────────────────────────────┤\n", "│ \u001b[1mTotal number of gate\u001b[0m │ 17 │\n", "│ Barrier │ 0 │\n", "│ Noise Channel │ 0 │\n", "│ Measurement │ 0 │\n", "├──────────────────────┼───────────────────────────────────────────────────────────────┤\n", "│ \u001b[1mParameter gate\u001b[0m │ 7 │\n", "│ 7 ansatz parameters │ \u001b[38;2;72;201;176m0_alpha, 1_alpha, 2_alpha, 3_alpha, 4_alpha, 5_alpha, 6_alpha\u001b[0m │\n", "╰──────────────────────┴───────────────────────────────────────────────────────────────╯\n" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from mindquantum.core.circuit import shift, add_prefix, Circuit, UN\n", "from mindquantum.core.gates import RZ, X, H\n", "\n", "template = Circuit([X.on(1, 0), RZ('alpha').on(1), X.on(1, 0)])\n", "encoder = UN(H, 4) + (RZ(f'{i}_alpha').on(i) for i in range(4)) + sum(add_prefix(shift(template, i), f'{i+4}') for i in range(3))\n", "encoder.summary()" ] }, { "cell_type": "code", "execution_count": 23, "id": "1686faa1", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "q0: q1: q2: q3: H H H H RZ 0_alpha RZ 1_alpha RZ 2_alpha RZ 3_alpha RZ 4_alpha RZ 5_alpha RZ 6_alpha " ], "text/plain": [ "" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "encoder.svg()" ] }, { "cell_type": "markdown", "id": "8dcb676b", "metadata": {}, "source": [ "In the above code, we use the UN module to apply the parameter-free H gate to the target qubits $q_0$~$q_3$, and then apply the RZ(i_alpha) gate to the i-th qubit.\n", "Next, it is observed that there are three identical modules in the circuit, and they are all composed of a controlled X gate, a RZ gate and a controlled X gate. Therefore, we construct the corresponding template template, which is controlled by $q_0$, an X gate acting on $q_1$, an RZ gate acting on $q_1$, and an X gate controlled by $q_0$ acting on $q_1$ are formed. Then we use shift(template, i) to change the qubit range that the template acts on, and build three modules with the same structure but the qubit range differs by 1. The qubit ranges involved are $q_0$ and $q_1$, $q_1$ and $q_2$, $q_2$ and $q_3$.\n", "Finally, we use the add_prefix method to prefix the parameter names of all parameter quantum gates constructed by shift with a number.\n", "\n", "So far, through these advanced operations of quantum circuit provided by MindSpore Quantum, we have built the required Encoder with only two lines of code!" ] }, { "cell_type": "code", "execution_count": 24, "id": "038c6317", "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", " \n", " \n", " \n", " \n", "\n", "\n", "\n", "\n", " \n", " \n", "\n", "\n", "
SoftwareVersion
mindquantum0.9.11
scipy1.10.1
numpy1.24.4
SystemInfo
Python3.8.17
OSLinux x86_64
Memory16.62 GB
CPU Max Thread16
DateTue Jan 2 14:38:22 2024
\n" ], "text/plain": [ "" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from mindquantum.utils.show_info import InfoTable\n", "\n", "InfoTable('mindquantum', 'scipy', 'numpy')" ] } ], "metadata": { "kernelspec": { "display_name": "MindSpore", "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.8.17" } }, "nbformat": 4, "nbformat_minor": 5 }