├── .gitignore ├── LICENSE ├── README.md ├── check_min_circuit.ipynb ├── distance_black_box.ipynb ├── final_circuit-Copy1.ipynb ├── final_circuit.ipynb ├── gate_extensions ├── __init__.py └── mct.py ├── how-to-use-custom-mct.ipynb ├── multi_adder_1.ipynb ├── multiple-controlled-toffoli-gate-testing.ipynb ├── oracle_initialize_part-Copy1.ipynb └── oracle_initialize_part.ipynb /.gitignore: -------------------------------------------------------------------------------- 1 | .ipynb_checkpoints/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Solving-TSP-Grover 2 | This project is for team #8 qiskit-camp asia 2019 3 | -------------------------------------------------------------------------------- /check_min_circuit.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 31, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import qiskit\n", 10 | "from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister\n", 11 | "from qiskit import Aer\n", 12 | "\n", 13 | "import numpy as np\n", 14 | "from math import floor, ceil\n", 15 | "\n", 16 | "%matplotlib inline" 17 | ] 18 | }, 19 | { 20 | "cell_type": "code", 21 | "execution_count": 34, 22 | "metadata": {}, 23 | "outputs": [], 24 | "source": [ 25 | "def max_number(arr_size):\n", 26 | " return (2 ** arr_size)-1\n", 27 | "\n", 28 | "def check_min_circuit(a, threshold):\n", 29 | " max = max_number(a)\n", 30 | " foo = max - threshold\n", 31 | " binary = format(foo, 'b')[::-1]\n", 32 | " print(binary)\n", 33 | " extra = a - len(binary)\n", 34 | " for i in range(extra):\n", 35 | " binary = \"0\" + binary\n", 36 | " print(binary)\n", 37 | " for i in range(a):\n", 38 | " if int(binary[i])==1:\n", 39 | " qc1.x(_q[i])" 40 | ] 41 | }, 42 | { 43 | "cell_type": "code", 44 | "execution_count": 36, 45 | "metadata": {}, 46 | "outputs": [ 47 | { 48 | "name": "stdout", 49 | "output_type": "stream", 50 | "text": [ 51 | "1101\n", 52 | "01101\n" 53 | ] 54 | }, 55 | { 56 | "data": { 57 | "text/html": [ 58 | "
              \n",
 59 |        "q6_0: |0>─────\n",
 60 |        "         ┌───┐\n",
 61 |        "q6_1: |0>┤ X ├\n",
 62 |        "         ├───┤\n",
 63 |        "q6_2: |0>┤ X ├\n",
 64 |        "         └───┘\n",
 65 |        "q6_3: |0>─────\n",
 66 |        "         ┌───┐\n",
 67 |        "q6_4: |0>┤ X ├\n",
 68 |        "         └───┘
" 69 | ], 70 | "text/plain": [ 71 | "" 72 | ] 73 | }, 74 | "execution_count": 36, 75 | "metadata": {}, 76 | "output_type": "execute_result" 77 | } 78 | ], 79 | "source": [ 80 | "_q = QuantumRegister(5)\n", 81 | "qc1 = QuantumCircuit(_q)\n", 82 | "check_min_circuit(5, 20)\n", 83 | "qc1.draw()" 84 | ] 85 | }, 86 | { 87 | "cell_type": "code", 88 | "execution_count": null, 89 | "metadata": {}, 90 | "outputs": [], 91 | "source": [] 92 | } 93 | ], 94 | "metadata": { 95 | "kernelspec": { 96 | "display_name": "Python 3", 97 | "language": "python", 98 | "name": "python3" 99 | }, 100 | "language_info": { 101 | "codemirror_mode": { 102 | "name": "ipython", 103 | "version": 3 104 | }, 105 | "file_extension": ".py", 106 | "mimetype": "text/x-python", 107 | "name": "python", 108 | "nbconvert_exporter": "python", 109 | "pygments_lexer": "ipython3", 110 | "version": "3.7.3" 111 | } 112 | }, 113 | "nbformat": 4, 114 | "nbformat_minor": 2 115 | } 116 | -------------------------------------------------------------------------------- /distance_black_box.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 2, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit\n", 10 | "from qiskit import IBMQ, Aer, execute\n", 11 | "from qiskit.tools.visualization import plot_histogram" 12 | ] 13 | }, 14 | { 15 | "cell_type": "code", 16 | "execution_count": 34, 17 | "metadata": {}, 18 | "outputs": [], 19 | "source": [ 20 | "## distance_black_box\n", 21 | "\n", 22 | "distances = {\n", 23 | " \"32\": 3,\n", 24 | " \"31\": 2,\n", 25 | " \"30\": 4,\n", 26 | " \"21\": 7,\n", 27 | " \"20\": 6,\n", 28 | " \"10\": 5,\n", 29 | "}\n", 30 | "\n", 31 | "def dist_single():\n", 32 | " qr = QuantumRegister(2)\n", 33 | " qr_target = QuantumRegister(5)\n", 34 | " qc = QuantumCircuit(qr, qr_target, name='dist_single')\n", 35 | " \n", 36 | " for edge in distances:\n", 37 | " if edge[0] == '3':\n", 38 | " node = format(int(edge[1]), '02b')[::-1]\n", 39 | " d_bin = format(distances[edge], '02b')[::-1]\n", 40 | " \n", 41 | " for idx in range(len(node)):\n", 42 | " if node[idx] == '0':\n", 43 | " qc.x(qr[idx])\n", 44 | " \n", 45 | " for idx in range(len(d_bin)):\n", 46 | " if d_bin[idx] == '1':\n", 47 | " qc.ccx(qr[0], qr[1], qr_target[idx])\n", 48 | " \n", 49 | " for idx in range(len(node)):\n", 50 | " if node[idx] == '0':\n", 51 | " qc.x(qr[idx])\n", 52 | " \n", 53 | " return qc\n", 54 | "\n", 55 | "def dist():\n", 56 | " qr1 = QuantumRegister(2)\n", 57 | " qr2 = QuantumRegister(2)\n", 58 | " qr_target = QuantumRegister(5)\n", 59 | " qr_anc = QuantumRegister(2)\n", 60 | " qc = QuantumCircuit(qr1, qr2, qr_target, qr_anc, name='dist')\n", 61 | " \n", 62 | " for edge in distances:\n", 63 | " if edge[0] != '3':\n", 64 | " # convert to binaries\n", 65 | " node1 = format(int(edge[0]), '02b')[::-1]\n", 66 | " node2 = format(int(edge[1]), '02b')[::-1]\n", 67 | " d_bin = format(distances[edge], '02b')[::-1]\n", 68 | "\n", 69 | " for idx in range(len(node1)): # assume node1 and node2 have the same length\n", 70 | " if node1[idx] == '0':\n", 71 | " qc.x(qr1[idx])\n", 72 | " \n", 73 | " for idx in range(len(node2)):\n", 74 | " if node2[idx] == '0':\n", 75 | " qc.x(qr2[idx])\n", 76 | "\n", 77 | " for idx in range(len(d_bin)):\n", 78 | " if d_bin[idx] == '1':\n", 79 | " qc.mct(qr1[:]+qr2[:], qr_target[idx], qr_anc)\n", 80 | " \n", 81 | " for idx in range(len(node2)): # invert back\n", 82 | " if node2[idx] == '0':\n", 83 | " qc.x(qr2[idx])\n", 84 | "\n", 85 | " for idx in range(len(node1)):\n", 86 | " if node1[idx] == '0':\n", 87 | " qc.x(qr1[idx])\n", 88 | " \n", 89 | " return qc" 90 | ] 91 | }, 92 | { 93 | "cell_type": "code", 94 | "execution_count": 40, 95 | "metadata": {}, 96 | "outputs": [ 97 | { 98 | "data": { 99 | "image/png": "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\n", 100 | "text/plain": [ 101 | "
" 102 | ] 103 | }, 104 | "execution_count": 40, 105 | "metadata": {}, 106 | "output_type": "execute_result" 107 | } 108 | ], 109 | "source": [ 110 | "qr1 = QuantumRegister(2) # node reg.\n", 111 | "qr2 = QuantumRegister(2) # node reg.\n", 112 | "qr_target = QuantumRegister(5) # distance reg.\n", 113 | "qr_anc = QuantumRegister(2)\n", 114 | "c = ClassicalRegister(5)\n", 115 | "qc = QuantumCircuit(qr1, qr2, qr_target, qr_anc, c)\n", 116 | "\n", 117 | "qc.x(qr1[0])\n", 118 | "# qc.x(qr2[0])\n", 119 | "qc.append(dist(), qr1[:] + qr2[:] + qr_target[:] + qr_anc[:])\n", 120 | "qc.measure(qr_target, c)\n", 121 | "\n", 122 | "# qc.draw(output='mpl')\n", 123 | "\n", 124 | "backend = Aer.get_backend('qasm_simulator')\n", 125 | "job = execute(qc, backend, shots=1024)\n", 126 | "counts = job.result().get_counts()\n", 127 | "\n", 128 | "plot_histogram(counts)" 129 | ] 130 | }, 131 | { 132 | "cell_type": "code", 133 | "execution_count": 32, 134 | "metadata": {}, 135 | "outputs": [ 136 | { 137 | "data": { 138 | "text/plain": [ 139 | "'01'" 140 | ] 141 | }, 142 | "execution_count": 32, 143 | "metadata": {}, 144 | "output_type": "execute_result" 145 | } 146 | ], 147 | "source": [ 148 | "format(1, '02b')" 149 | ] 150 | } 151 | ], 152 | "metadata": { 153 | "kernelspec": { 154 | "display_name": "Python 3", 155 | "language": "python", 156 | "name": "python3" 157 | }, 158 | "language_info": { 159 | "codemirror_mode": { 160 | "name": "ipython", 161 | "version": 3 162 | }, 163 | "file_extension": ".py", 164 | "mimetype": "text/x-python", 165 | "name": "python", 166 | "nbconvert_exporter": "python", 167 | "pygments_lexer": "ipython3", 168 | "version": "3.7.3" 169 | } 170 | }, 171 | "nbformat": 4, 172 | "nbformat_minor": 2 173 | } 174 | -------------------------------------------------------------------------------- /final_circuit-Copy1.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit\n", 10 | "from qiskit import IBMQ, Aer, execute\n", 11 | "from qiskit.tools.visualization import plot_histogram" 12 | ] 13 | }, 14 | { 15 | "cell_type": "code", 16 | "execution_count": 2, 17 | "metadata": {}, 18 | "outputs": [], 19 | "source": [ 20 | "## oracle_initialize_part\n", 21 | "\n", 22 | "def OR(qubit_1, qubit_2, k):\n", 23 | " # enter qubit numbers here \n", 24 | " \"\"\" function does the equivalent of a classical OR between qubit numbers a and b and stores the result in qubit number k \"\"\"\n", 25 | "# qc.barrier(q)\n", 26 | " qc.x(q[qubit_1])\n", 27 | " qc.x(q[qubit_2])\n", 28 | "# qc.barrier(q)\n", 29 | " qc.ccx(q[qubit_1], q[qubit_2], q[k])\n", 30 | " qc.x(q[k])\n", 31 | "# qc.barrier(q)\n", 32 | " qc.x(q[qubit_1])\n", 33 | " qc.x(q[qubit_2])\n", 34 | "# qc.barrier(q)\n", 35 | " \n", 36 | "\n", 37 | "def are_not_equal(a_0, b_0, k):\n", 38 | " # enter node numbers here. For example, a is node 0, b is node 1 and c is node 2\n", 39 | " \"\"\" function outputs 1 if nodes a and b are not the same. Node numbering starts from 0\n", 40 | " as in the problem statement. k is the qubit number where the output is XOR-ed. qubit\n", 41 | " numbering also starts from 0 \"\"\"\n", 42 | "# qc.barrier(q)\n", 43 | " qc.cx(q[2*a_0], q[2*b_0])\n", 44 | " qc.cx(q[(2*a_0) + 1], q[(2*b_0) + 1])\n", 45 | " OR(2*b_0, (2*b_0)+1, k)\n", 46 | " qc.cx(q[2*a_0], q[2*b_0])\n", 47 | " qc.cx(q[(2*a_0) + 1], q[(2*b_0) + 1])\n", 48 | "# qc.barrier(q)\n", 49 | "\n", 50 | "def is_not_3(a, k):\n", 51 | " qc.ccx(q[2*a], q[(2*a)+1], q[k])\n", 52 | " qc.x(q[k])\n", 53 | " \n", 54 | "def initialize_oracle_part(n):\n", 55 | " t = 4\n", 56 | "# qc.barrier(q)\n", 57 | " are_not_equal(0, 1, 6) # node a and b are not equal \n", 58 | " are_not_equal(0, 2, 7)\n", 59 | " are_not_equal(1, 2, 8)\n", 60 | " is_not_3(0, 11)\n", 61 | " is_not_3(1, 12)\n", 62 | " is_not_3(2, 13)\n", 63 | "# qc.barrier(q)\n", 64 | " qc.mct([q[6], q[7], q[8], q[11], q[12], q[13]], q[10],[q[9], q[14], q[15], q[16]]) # answer is stored in 10. please keep 9 a clean qubit, it's used as ancilla here \n", 65 | "# qc.barrier(q)\n", 66 | " is_not_3(0, 11)\n", 67 | " is_not_3(1, 12)\n", 68 | " is_not_3(2, 13)\n", 69 | " are_not_equal(0, 1, 6) # node a and b are not equal \n", 70 | " are_not_equal(0, 2, 7)\n", 71 | " are_not_equal(1, 2, 8)" 72 | ] 73 | }, 74 | { 75 | "cell_type": "code", 76 | "execution_count": 3, 77 | "metadata": {}, 78 | "outputs": [], 79 | "source": [ 80 | "## distance_black_box\n", 81 | "\n", 82 | "distances = {\n", 83 | " \"32\": 3,\n", 84 | " \"31\": 2,\n", 85 | " \"30\": 4,\n", 86 | " \"21\": 7,\n", 87 | " \"20\": 6,\n", 88 | " \"10\": 5,\n", 89 | "}\n", 90 | "\n", 91 | "def dist_single():\n", 92 | " qr = QuantumRegister(2)\n", 93 | " qr_target = QuantumRegister(5)\n", 94 | " qc = QuantumCircuit(qr, qr_target, name='dist_single')\n", 95 | " \n", 96 | " for edge in distances:\n", 97 | " if edge[0] == '3':\n", 98 | " node = format(int(edge[1]), '02b')\n", 99 | " d_bin = format(distances[edge], '02b')\n", 100 | " \n", 101 | " for idx in range(len(node)):\n", 102 | " if node[idx] == '0':\n", 103 | " qc.x(qr[idx])\n", 104 | " \n", 105 | " for idx in range(len(d_bin)):\n", 106 | " if d_bin[idx] == '1':\n", 107 | " qc.ccx(qr[0], qr[1], qr_target[idx])\n", 108 | " \n", 109 | " for idx in range(len(node)):\n", 110 | " if node[idx] == '0':\n", 111 | " qc.x(qr[idx])\n", 112 | " \n", 113 | " return qc\n", 114 | "\n", 115 | "def dist():\n", 116 | " qr1 = QuantumRegister(2)\n", 117 | " qr2 = QuantumRegister(2)\n", 118 | " qr_target = QuantumRegister(5)\n", 119 | " qr_anc = QuantumRegister(2)\n", 120 | " qc = QuantumCircuit(qr1, qr2, qr_target, qr_anc, name='dist')\n", 121 | " \n", 122 | " for edge in distances:\n", 123 | " if edge[0] != '3':\n", 124 | " # convert to binaries\n", 125 | " node1 = format(int(edge[0]), '02b')\n", 126 | " node2 = format(int(edge[1]), '02b')\n", 127 | " d_bin = format(distances[edge], '02b')\n", 128 | "\n", 129 | " for idx in range(len(node1)): # assume node1 and node2 have the same length\n", 130 | " if node1[idx] == '0':\n", 131 | " qc.x(qr1[idx])\n", 132 | " \n", 133 | " for idx in range(len(node2)):\n", 134 | " if node2[idx] == '0':\n", 135 | " qc.x(qr2[idx])\n", 136 | "\n", 137 | " for idx in range(len(d_bin)):\n", 138 | " if d_bin[idx] == '1':\n", 139 | " qc.mct(qr1[:]+qr2[:], qr_target[idx], qr_anc)\n", 140 | " \n", 141 | " for idx in range(len(node2)): # invert back\n", 142 | " if node2[idx] == '0':\n", 143 | " qc.x(qr2[idx])\n", 144 | "\n", 145 | " for idx in range(len(node1)):\n", 146 | " if node1[idx] == '0':\n", 147 | " qc.x(qr1[idx])\n", 148 | " \n", 149 | " return qc" 150 | ] 151 | }, 152 | { 153 | "cell_type": "code", 154 | "execution_count": 4, 155 | "metadata": {}, 156 | "outputs": [], 157 | "source": [ 158 | "## multi_adder_1\n", 159 | "\n", 160 | "def maj(a, b, k):\n", 161 | " qc.cx(q[k], q[b])\n", 162 | " qc.cx(q[k], q[a])\n", 163 | " qc.ccx(q[a], q[b], q[k])\n", 164 | " \n", 165 | "def unmaj(a, b, k):\n", 166 | " qc.ccx(q[a], q[b], q[k])\n", 167 | " qc.cx(q[k], q[a])\n", 168 | " qc.cx(q[a], q[b])\n", 169 | " \n", 170 | "def multiple_adder(a, b, c_0, z):\n", 171 | " arr_size = len(a)\n", 172 | " maj(c_0, b[0], a[0])\n", 173 | " for i in range(arr_size-1):\n", 174 | " maj(a[i], b[i+1], a[i+1])\n", 175 | " qc.cx(q[a[arr_size-1]], q[z])\n", 176 | " for i in reversed(range(arr_size-1)):\n", 177 | " unmaj(a[i], b[i+1], a[i+1])\n", 178 | " unmaj(c_0, b[0], a[0])" 179 | ] 180 | }, 181 | { 182 | "cell_type": "code", 183 | "execution_count": 5, 184 | "metadata": {}, 185 | "outputs": [], 186 | "source": [ 187 | "## diffusion\n", 188 | "def diffusion():\n", 189 | " qc.h(q[0:6])\n", 190 | " qc.x(q[0:6])\n", 191 | " qc.h(q[5])\n", 192 | " qc.barrier()\n", 193 | " qc.mct(q[0:5], q[5], q[7:10])\n", 194 | " qc.barrier()\n", 195 | " qc.h(q[5])\n", 196 | " qc.x(q[0:6])\n", 197 | " qc.h(q[0:6])" 198 | ] 199 | }, 200 | { 201 | "cell_type": "code", 202 | "execution_count": 6, 203 | "metadata": {}, 204 | "outputs": [ 205 | { 206 | "data": { 207 | "text/plain": [ 208 | "" 209 | ] 210 | }, 211 | "execution_count": 6, 212 | "metadata": {}, 213 | "output_type": "execute_result" 214 | } 215 | ], 216 | "source": [ 217 | "\n", 218 | " qubit_num = 25 # max is 32 if you're using the simulator\n", 219 | "\n", 220 | " # Ancilla indices\n", 221 | " inputs = [0, 1, 2, 3, 4, 5]\n", 222 | " init_ancillae = [6, 7, 8, 9]\n", 223 | " valid = [10]\n", 224 | " temp_dist = [11, 12, 13, 14, 15]\n", 225 | " total_dist = [16, 17, 18, 19, 20]\n", 226 | " gate_ancillae = [21, 22, 23]\n", 227 | " check_dist = [11, 12, 13, 14, 15] # initialize 13 here\n", 228 | " carry_check = [24]\n", 229 | "\n", 230 | " inputs = inputs[0]\n", 231 | " init_ancillae = init_ancillae[0]\n", 232 | " valid = valid[0]\n", 233 | " temp_dist = temp_dist[0]\n", 234 | " total_dist = total_dist[0]\n", 235 | " gate_ancillae = gate_ancillae[0]\n", 236 | " check_dist = check_dist[0]\n", 237 | " carry_check = carry_check[0]\n", 238 | "\n", 239 | " q = QuantumRegister(qubit_num)\n", 240 | " c = ClassicalRegister(6)\n", 241 | " qc = QuantumCircuit(q, c)\n", 242 | "\n", 243 | " qc.h(q[0:6])\n", 244 | " qc.x(q[carry_check])\n", 245 | "\n", 246 | " for i in range(loop):\n", 247 | " # forward oracle\n", 248 | " initialize_oracle_part(4)\n", 249 | " qc.append(dist_single(), q[inputs:inputs+2] + q[temp_dist:temp_dist+5])\n", 250 | " multiple_adder([11, 12, 13, 14], [16, 17, 18, 19], init_ancillae, 20)\n", 251 | " qc.append(dist_single().inverse(), q[inputs:inputs+2] + q[temp_dist:temp_dist+5])\n", 252 | " qc.append(dist(), q[inputs:inputs+4] + q[temp_dist:temp_dist+5] + q[gate_ancillae:gate_ancillae+2])\n", 253 | " multiple_adder([11, 12, 13, 14], [16, 17, 18, 19], init_ancillae, 20)\n", 254 | " qc.append(dist().inverse(), q[inputs:inputs+4] + q[temp_dist:temp_dist+5] + q[gate_ancillae:gate_ancillae+2])\n", 255 | " qc.append(dist(), q[inputs+2:inputs+6] + q[temp_dist:temp_dist+5] + q[gate_ancillae:gate_ancillae+2])\n", 256 | " multiple_adder([11, 12, 13, 14], [16, 17, 18, 19], init_ancillae, 20)\n", 257 | " qc.append(dist().inverse(), q[inputs+2:inputs+6] + q[temp_dist:temp_dist+5] + q[gate_ancillae:gate_ancillae+2])\n", 258 | " qc.x(q[check_dist:check_dist+3]) # init 15\n", 259 | " multiple_adder([11, 12, 13, 14, 15], [16, 17, 18, 19, 20], init_ancillae, carry_check)\n", 260 | "\n", 261 | " # carry_check\n", 262 | " # qc.barrier()\n", 263 | " qc.cz(q[valid], q[carry_check])\n", 264 | " # qc.barrier()\n", 265 | "\n", 266 | " # inverse oracle\n", 267 | " multiple_adder([11, 12, 13, 14, 15], [16, 17, 18, 19, 20], init_ancillae, carry_check)\n", 268 | " qc.x(q[check_dist:check_dist+3]) # init 15\n", 269 | " qc.append(dist().inverse(), q[inputs+2:inputs+6] + q[temp_dist:temp_dist+5] + q[gate_ancillae:gate_ancillae+2])\n", 270 | " multiple_adder([11, 12, 13, 14], [16, 17, 18, 19], init_ancillae, 20)\n", 271 | " qc.append(dist(), q[inputs+2:inputs+6] + q[temp_dist:temp_dist+5] + q[gate_ancillae:gate_ancillae+2])\n", 272 | " qc.append(dist().inverse(), q[inputs:inputs+4] + q[temp_dist:temp_dist+5] + q[gate_ancillae:gate_ancillae+2])\n", 273 | " multiple_adder([11, 12, 13, 14], [16, 17, 18, 19], init_ancillae, 20)\n", 274 | " qc.append(dist(), q[inputs:inputs+4] + q[temp_dist:temp_dist+5] + q[gate_ancillae:gate_ancillae+2])\n", 275 | " qc.append(dist_single().inverse(), q[inputs:inputs+2] + q[temp_dist:temp_dist+5])\n", 276 | " multiple_adder([11, 12, 13, 14], [16, 17, 18, 19], init_ancillae, 20)\n", 277 | " qc.append(dist_single(), q[inputs:inputs+2] + q[temp_dist:temp_dist+5])\n", 278 | " initialize_oracle_part(4)\n", 279 | "\n", 280 | " diffusion()\n", 281 | "\n", 282 | "\n", 283 | "\n", 284 | "qc.measure(q[:6], c)\n", 285 | "# qc.draw()" 286 | ] 287 | }, 288 | { 289 | "cell_type": "code", 290 | "execution_count": 7, 291 | "metadata": { 292 | "scrolled": true 293 | }, 294 | "outputs": [ 295 | { 296 | "name": "stdout", 297 | "output_type": "stream", 298 | "text": [ 299 | "OrderedDict([('u3', 6497), ('cx', 3866), ('measure', 6), ('barrier', 4)])\n" 300 | ] 301 | } 302 | ], 303 | "source": [ 304 | "from qiskit.transpiler import PassManager\n", 305 | "from qiskit.transpiler.passes import Unroller\n", 306 | "\n", 307 | "pass_ = Unroller(['u3', 'cx'])\n", 308 | "pm = PassManager(pass_)\n", 309 | "new_circuit = pm.run(qc)\n", 310 | "print(new_circuit.count_ops())" 311 | ] 312 | }, 313 | { 314 | "cell_type": "code", 315 | "execution_count": null, 316 | "metadata": {}, 317 | "outputs": [], 318 | "source": [ 319 | "backend = Aer.get_backend('qasm_simulator')\n", 320 | "job = execute(qc, backend, shots=1024)\n", 321 | "counts = job.result().get_counts()" 322 | ] 323 | }, 324 | { 325 | "cell_type": "code", 326 | "execution_count": null, 327 | "metadata": { 328 | "scrolled": false 329 | }, 330 | "outputs": [], 331 | "source": [ 332 | "print(sorted(counts.items(), key=lambda x:x[1], reverse=True)[0:20])" 333 | ] 334 | }, 335 | { 336 | "cell_type": "code", 337 | "execution_count": null, 338 | "metadata": {}, 339 | "outputs": [], 340 | "source": [ 341 | "plot_histogram(counts)" 342 | ] 343 | }, 344 | { 345 | "cell_type": "code", 346 | "execution_count": null, 347 | "metadata": {}, 348 | "outputs": [], 349 | "source": [] 350 | } 351 | ], 352 | "metadata": { 353 | "kernelspec": { 354 | "display_name": "Python 3", 355 | "language": "python", 356 | "name": "python3" 357 | }, 358 | "language_info": { 359 | "codemirror_mode": { 360 | "name": "ipython", 361 | "version": 3 362 | }, 363 | "file_extension": ".py", 364 | "mimetype": "text/x-python", 365 | "name": "python", 366 | "nbconvert_exporter": "python", 367 | "pygments_lexer": "ipython3", 368 | "version": "3.7.5" 369 | } 370 | }, 371 | "nbformat": 4, 372 | "nbformat_minor": 2 373 | } 374 | -------------------------------------------------------------------------------- /final_circuit.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit\n", 10 | "from qiskit import IBMQ, Aer, execute\n", 11 | "from qiskit.tools.visualization import plot_histogram" 12 | ] 13 | }, 14 | { 15 | "cell_type": "code", 16 | "execution_count": 2, 17 | "metadata": {}, 18 | "outputs": [], 19 | "source": [ 20 | "## oracle_initialize_part\n", 21 | "\n", 22 | "def OR(qubit_1, qubit_2, k):\n", 23 | " # enter qubit numbers here \n", 24 | " \"\"\" function does the equivalent of a classical OR between qubit numbers a and b and stores the result in qubit number k \"\"\"\n", 25 | "# qc.barrier(q)\n", 26 | " qc.x(q[qubit_1])\n", 27 | " qc.x(q[qubit_2])\n", 28 | "# qc.barrier(q)\n", 29 | " qc.ccx(q[qubit_1], q[qubit_2], q[k])\n", 30 | " qc.x(q[k])\n", 31 | "# qc.barrier(q)\n", 32 | " qc.x(q[qubit_1])\n", 33 | " qc.x(q[qubit_2])\n", 34 | "# qc.barrier(q)\n", 35 | " \n", 36 | "\n", 37 | "def are_not_equal(a_0, b_0, k):\n", 38 | " # enter node numbers here. For example, a is node 0, b is node 1 and c is node 2\n", 39 | " \"\"\" function outputs 1 if nodes a and b are not the same. Node numbering starts from 0\n", 40 | " as in the problem statement. k is the qubit number where the output is XOR-ed. qubit\n", 41 | " numbering also starts from 0 \"\"\"\n", 42 | "# qc.barrier(q)\n", 43 | " qc.cx(q[2*a_0], q[2*b_0])\n", 44 | " qc.cx(q[(2*a_0) + 1], q[(2*b_0) + 1])\n", 45 | " OR(2*b_0, (2*b_0)+1, k)\n", 46 | " qc.cx(q[2*a_0], q[2*b_0])\n", 47 | " qc.cx(q[(2*a_0) + 1], q[(2*b_0) + 1])\n", 48 | "# qc.barrier(q)\n", 49 | "\n", 50 | "def is_not_3(a, k):\n", 51 | " qc.ccx(q[2*a], q[(2*a)+1], q[k])\n", 52 | " qc.x(q[k])\n", 53 | " \n", 54 | "def initialize_oracle_part(n):\n", 55 | " t = 4\n", 56 | "# qc.barrier(q)\n", 57 | " are_not_equal(0, 1, 6) # node a and b are not equal \n", 58 | " are_not_equal(0, 2, 7)\n", 59 | " are_not_equal(1, 2, 8)\n", 60 | " is_not_3(0, 11)\n", 61 | " is_not_3(1, 12)\n", 62 | " is_not_3(2, 13)\n", 63 | "# qc.barrier(q)\n", 64 | " qc.mct([q[6], q[7], q[8], q[11], q[12], q[13]], q[10],[q[9], q[14], q[15], q[16]]) # answer is stored in 10. please keep 9 a clean qubit, it's used as ancilla here \n", 65 | "# qc.barrier(q)\n", 66 | " is_not_3(0, 11)\n", 67 | " is_not_3(1, 12)\n", 68 | " is_not_3(2, 13)\n", 69 | " are_not_equal(0, 1, 6) # node a and b are not equal \n", 70 | " are_not_equal(0, 2, 7)\n", 71 | " are_not_equal(1, 2, 8)" 72 | ] 73 | }, 74 | { 75 | "cell_type": "code", 76 | "execution_count": 3, 77 | "metadata": {}, 78 | "outputs": [], 79 | "source": [ 80 | "## distance_black_box\n", 81 | "\n", 82 | "distances = {\n", 83 | " \"32\": 3,\n", 84 | " \"31\": 2,\n", 85 | " \"30\": 4,\n", 86 | " \"21\": 7,\n", 87 | " \"20\": 6,\n", 88 | " \"10\": 5,\n", 89 | "}\n", 90 | "\n", 91 | "def dist_single():\n", 92 | " qr = QuantumRegister(2)\n", 93 | " qr_target = QuantumRegister(5)\n", 94 | " qc = QuantumCircuit(qr, qr_target, name='dist_single')\n", 95 | " \n", 96 | " for edge in distances:\n", 97 | " if edge[0] == '3':\n", 98 | " node = format(int(edge[1]), '02b')\n", 99 | " d_bin = format(distances[edge], '02b')\n", 100 | " \n", 101 | " for idx in range(len(node)):\n", 102 | " if node[idx] == '0':\n", 103 | " qc.x(qr[idx])\n", 104 | " \n", 105 | " for idx in range(len(d_bin)):\n", 106 | " if d_bin[idx] == '1':\n", 107 | " qc.ccx(qr[0], qr[1], qr_target[idx])\n", 108 | " \n", 109 | " for idx in range(len(node)):\n", 110 | " if node[idx] == '0':\n", 111 | " qc.x(qr[idx])\n", 112 | " \n", 113 | " return qc\n", 114 | "\n", 115 | "def dist():\n", 116 | " qr1 = QuantumRegister(2)\n", 117 | " qr2 = QuantumRegister(2)\n", 118 | " qr_target = QuantumRegister(5)\n", 119 | " qr_anc = QuantumRegister(2)\n", 120 | " qc = QuantumCircuit(qr1, qr2, qr_target, qr_anc, name='dist')\n", 121 | " \n", 122 | " for edge in distances:\n", 123 | " if edge[0] != '3':\n", 124 | " # convert to binaries\n", 125 | " node1 = format(int(edge[0]), '02b')\n", 126 | " node2 = format(int(edge[1]), '02b')\n", 127 | " d_bin = format(distances[edge], '02b')\n", 128 | "\n", 129 | " for idx in range(len(node1)): # assume node1 and node2 have the same length\n", 130 | " if node1[idx] == '0':\n", 131 | " qc.x(qr1[idx])\n", 132 | " \n", 133 | " for idx in range(len(node2)):\n", 134 | " if node2[idx] == '0':\n", 135 | " qc.x(qr2[idx])\n", 136 | "\n", 137 | " for idx in range(len(d_bin)):\n", 138 | " if d_bin[idx] == '1':\n", 139 | " qc.mct(qr1[:]+qr2[:], qr_target[idx], qr_anc)\n", 140 | " \n", 141 | " for idx in range(len(node2)): # invert back\n", 142 | " if node2[idx] == '0':\n", 143 | " qc.x(qr2[idx])\n", 144 | "\n", 145 | " for idx in range(len(node1)):\n", 146 | " if node1[idx] == '0':\n", 147 | " qc.x(qr1[idx])\n", 148 | " \n", 149 | " return qc" 150 | ] 151 | }, 152 | { 153 | "cell_type": "code", 154 | "execution_count": 4, 155 | "metadata": {}, 156 | "outputs": [], 157 | "source": [ 158 | "## multi_adder_1\n", 159 | "\n", 160 | "def maj(a, b, k):\n", 161 | " qc.cx(q[k], q[b])\n", 162 | " qc.cx(q[k], q[a])\n", 163 | " qc.ccx(q[a], q[b], q[k])\n", 164 | " \n", 165 | "def unmaj(a, b, k):\n", 166 | " qc.ccx(q[a], q[b], q[k])\n", 167 | " qc.cx(q[k], q[a])\n", 168 | " qc.cx(q[a], q[b])\n", 169 | " \n", 170 | "def multiple_adder(a, b, c_0, z):\n", 171 | " arr_size = len(a)\n", 172 | " maj(c_0, b[0], a[0])\n", 173 | " for i in range(arr_size-1):\n", 174 | " maj(a[i], b[i+1], a[i+1])\n", 175 | " qc.cx(q[a[arr_size-1]], q[z])\n", 176 | " for i in reversed(range(arr_size-1)):\n", 177 | " unmaj(a[i], b[i+1], a[i+1])\n", 178 | " unmaj(c_0, b[0], a[0])" 179 | ] 180 | }, 181 | { 182 | "cell_type": "code", 183 | "execution_count": 5, 184 | "metadata": {}, 185 | "outputs": [], 186 | "source": [ 187 | "## diffusion\n", 188 | "def diffusion():\n", 189 | " qc.h(q[0:6])\n", 190 | " qc.x(q[0:6])\n", 191 | " qc.h(q[5])\n", 192 | " qc.barrier()\n", 193 | " qc.mct(q[0:5], q[5], q[7:10])\n", 194 | " qc.barrier()\n", 195 | " qc.h(q[5])\n", 196 | " qc.x(q[0:6])\n", 197 | " qc.h(q[0:6])" 198 | ] 199 | }, 200 | { 201 | "cell_type": "code", 202 | "execution_count": 11, 203 | "metadata": {}, 204 | "outputs": [ 205 | { 206 | "data": { 207 | "text/plain": [ 208 | "" 209 | ] 210 | }, 211 | "execution_count": 11, 212 | "metadata": {}, 213 | "output_type": "execute_result" 214 | } 215 | ], 216 | "source": [ 217 | "qubit_num = 25 # max is 32 if you're using the simulator\n", 218 | "\n", 219 | "# Ancilla indices\n", 220 | "inputs = [0, 1, 2, 3, 4, 5]\n", 221 | "init_ancillae = [6, 7, 8, 9]\n", 222 | "valid = [10]\n", 223 | "temp_dist = [11, 12, 13, 14, 15]\n", 224 | "total_dist = [16, 17, 18, 19, 20]\n", 225 | "gate_ancillae = [21, 22, 23]\n", 226 | "check_dist = [11, 12, 13, 14, 15] # initialize 13 here\n", 227 | "carry_check = [24]\n", 228 | "\n", 229 | "inputs = inputs[0]\n", 230 | "init_ancillae = init_ancillae[0]\n", 231 | "valid = valid[0]\n", 232 | "temp_dist = temp_dist[0]\n", 233 | "total_dist = total_dist[0]\n", 234 | "gate_ancillae = gate_ancillae[0]\n", 235 | "check_dist = check_dist[0]\n", 236 | "carry_check = carry_check[0]\n", 237 | "\n", 238 | "q = QuantumRegister(qubit_num)\n", 239 | "c = ClassicalRegister(6)\n", 240 | "qc = QuantumCircuit(q, c)\n", 241 | "\n", 242 | "qc.h(q[0:6])\n", 243 | "qc.x(q[carry_check])\n", 244 | "\n", 245 | "# forward oracle\n", 246 | "initialize_oracle_part(4)\n", 247 | "qc.append(dist_single(), q[inputs:inputs+2] + q[temp_dist:temp_dist+5])\n", 248 | "multiple_adder([11, 12, 13, 14], [16, 17, 18, 19], init_ancillae, 20)\n", 249 | "qc.append(dist_single().inverse(), q[inputs:inputs+2] + q[temp_dist:temp_dist+5])\n", 250 | "qc.append(dist(), q[inputs:inputs+4] + q[temp_dist:temp_dist+5] + q[gate_ancillae:gate_ancillae+2])\n", 251 | "multiple_adder([11, 12, 13, 14], [16, 17, 18, 19], init_ancillae, 20)\n", 252 | "qc.append(dist().inverse(), q[inputs:inputs+4] + q[temp_dist:temp_dist+5] + q[gate_ancillae:gate_ancillae+2])\n", 253 | "qc.append(dist(), q[inputs+2:inputs+6] + q[temp_dist:temp_dist+5] + q[gate_ancillae:gate_ancillae+2])\n", 254 | "multiple_adder([11, 12, 13, 14], [16, 17, 18, 19], init_ancillae, 20)\n", 255 | "qc.append(dist().inverse(), q[inputs+2:inputs+6] + q[temp_dist:temp_dist+5] + q[gate_ancillae:gate_ancillae+2])\n", 256 | "qc.x(q[check_dist:check_dist+3]) # init 15\n", 257 | "multiple_adder([11, 12, 13, 14, 15], [16, 17, 18, 19, 20], init_ancillae, carry_check)\n", 258 | "\n", 259 | "# carry_check\n", 260 | "# qc.barrier()\n", 261 | "qc.cz(q[valid], q[carry_check])\n", 262 | "# qc.barrier()\n", 263 | "\n", 264 | "# inverse oracle\n", 265 | "multiple_adder([11, 12, 13, 14, 15], [16, 17, 18, 19, 20], init_ancillae, carry_check)\n", 266 | "qc.x(q[check_dist:check_dist+3]) # init 15\n", 267 | "qc.append(dist().inverse(), q[inputs+2:inputs+6] + q[temp_dist:temp_dist+5] + q[gate_ancillae:gate_ancillae+2])\n", 268 | "multiple_adder([11, 12, 13, 14], [16, 17, 18, 19], init_ancillae, 20)\n", 269 | "qc.append(dist(), q[inputs+2:inputs+6] + q[temp_dist:temp_dist+5] + q[gate_ancillae:gate_ancillae+2])\n", 270 | "qc.append(dist().inverse(), q[inputs:inputs+4] + q[temp_dist:temp_dist+5] + q[gate_ancillae:gate_ancillae+2])\n", 271 | "multiple_adder([11, 12, 13, 14], [16, 17, 18, 19], init_ancillae, 20)\n", 272 | "qc.append(dist(), q[inputs:inputs+4] + q[temp_dist:temp_dist+5] + q[gate_ancillae:gate_ancillae+2])\n", 273 | "qc.append(dist_single().inverse(), q[inputs:inputs+2] + q[temp_dist:temp_dist+5])\n", 274 | "multiple_adder([11, 12, 13, 14], [16, 17, 18, 19], init_ancillae, 20)\n", 275 | "qc.append(dist_single(), q[inputs:inputs+2] + q[temp_dist:temp_dist+5])\n", 276 | "initialize_oracle_part(4)\n", 277 | "\n", 278 | "diffusion()\n", 279 | "\n", 280 | "qc.measure(q[:6], c)\n", 281 | "# qc.draw()" 282 | ] 283 | }, 284 | { 285 | "cell_type": "code", 286 | "execution_count": 12, 287 | "metadata": { 288 | "scrolled": true 289 | }, 290 | "outputs": [ 291 | { 292 | "name": "stdout", 293 | "output_type": "stream", 294 | "text": [ 295 | "OrderedDict([('u3', 3252), ('cx', 1933), ('measure', 6), ('barrier', 2)])\n" 296 | ] 297 | } 298 | ], 299 | "source": [ 300 | "from qiskit.transpiler import PassManager\n", 301 | "from qiskit.transpiler.passes import Unroller\n", 302 | "\n", 303 | "pass_ = Unroller(['u3', 'cx'])\n", 304 | "pm = PassManager(pass_)\n", 305 | "new_circuit = pm.run(qc)\n", 306 | "print(new_circuit.count_ops())" 307 | ] 308 | }, 309 | { 310 | "cell_type": "code", 311 | "execution_count": 13, 312 | "metadata": {}, 313 | "outputs": [], 314 | "source": [ 315 | "backend = Aer.get_backend('qasm_simulator')\n", 316 | "job = execute(qc, backend, shots=1024)\n", 317 | "counts = job.result().get_counts()" 318 | ] 319 | }, 320 | { 321 | "cell_type": "code", 322 | "execution_count": 14, 323 | "metadata": { 324 | "scrolled": false 325 | }, 326 | "outputs": [ 327 | { 328 | "name": "stdout", 329 | "output_type": "stream", 330 | "text": [ 331 | "[('011000', 54), ('100001', 38), ('001001', 35), ('111101', 33), ('001011', 31), ('010010', 29), ('000110', 28), ('111001', 27), ('000100', 27), ('100110', 25), ('101001', 24), ('001101', 23), ('101101', 23), ('000001', 22), ('011111', 21), ('011101', 21), ('100111', 20), ('001010', 20), ('100010', 20), ('000101', 20)]\n" 332 | ] 333 | } 334 | ], 335 | "source": [ 336 | "print(sorted(counts.items(), key=lambda x:x[1], reverse=True)[0:20])" 337 | ] 338 | }, 339 | { 340 | "cell_type": "code", 341 | "execution_count": 15, 342 | "metadata": {}, 343 | "outputs": [ 344 | { 345 | "data": { 346 | "image/png": "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\n", 347 | "text/plain": [ 348 | "
" 349 | ] 350 | }, 351 | "execution_count": 15, 352 | "metadata": {}, 353 | "output_type": "execute_result" 354 | } 355 | ], 356 | "source": [ 357 | "plot_histogram(counts)" 358 | ] 359 | }, 360 | { 361 | "cell_type": "code", 362 | "execution_count": null, 363 | "metadata": {}, 364 | "outputs": [], 365 | "source": [] 366 | } 367 | ], 368 | "metadata": { 369 | "kernelspec": { 370 | "display_name": "Python 3", 371 | "language": "python", 372 | "name": "python3" 373 | }, 374 | "language_info": { 375 | "codemirror_mode": { 376 | "name": "ipython", 377 | "version": 3 378 | }, 379 | "file_extension": ".py", 380 | "mimetype": "text/x-python", 381 | "name": "python", 382 | "nbconvert_exporter": "python", 383 | "pygments_lexer": "ipython3", 384 | "version": "3.7.5" 385 | } 386 | }, 387 | "nbformat": 4, 388 | "nbformat_minor": 2 389 | } 390 | -------------------------------------------------------------------------------- /gate_extensions/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | from .mct import apply_mct -------------------------------------------------------------------------------- /gate_extensions/mct.py: -------------------------------------------------------------------------------- 1 | import qiskit 2 | from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister 3 | from qiskit import Aer 4 | from qiskit.circuit import Qubit 5 | 6 | import numpy as np 7 | from math import floor, ceil 8 | 9 | def RTL(qc, a, b, c): 10 | ## fig 3 dashed 11 | qc.rccx(a, b, c) 12 | 13 | def RTL_inv(qc, a, b, c): 14 | RTL(qc, a, b, c) 15 | 16 | def RTS(qc, a, b, c): 17 | ## fig 3 gates 2-6 18 | qc.h(c) 19 | qc.t(c) 20 | qc.cx(b, c) 21 | qc.tdg(c) 22 | qc.cx(a, c) 23 | 24 | def RTS_inv(qc, a, b, c): 25 | qc.cx(a, c) 26 | qc.t(c) 27 | qc.cx(b, c) 28 | qc.tdg(c) 29 | qc.h(c) 30 | 31 | def SRTS(qc, a, b, c): 32 | ## circuit 3 dashed 33 | qc.h(c) 34 | qc.cx(c, b) 35 | qc.tdg(b) 36 | qc.cx(a, b) 37 | qc.t(b) 38 | qc.cx(c, b) 39 | qc.tdg(b) 40 | qc.cx(a, b) 41 | qc.t(b) 42 | 43 | def SRTS_inv(qc, a, b, c): 44 | qc.tdg(b) 45 | qc.cx(a, b) 46 | qc.t(b) 47 | qc.cx(c, b) 48 | qc.tdg(b) 49 | qc.cx(a, b) 50 | qc.t(b) 51 | qc.cx(c, b) 52 | qc.h(c) 53 | 54 | def RT4L(qc, a, b, c, d): 55 | ## fig 4 56 | qc.rcccx(a, b, c, d) 57 | 58 | def RT4L_inv(qc, a, b, c, d): 59 | qc.h(d) 60 | qc.t(d) 61 | qc.cx(c, d) 62 | qc.tdg(d) 63 | qc.h(d) 64 | qc.t(d) 65 | qc.cx(b, d) 66 | qc.tdg(d) 67 | qc.cx(a, d) 68 | qc.t(d) 69 | qc.cx(b, d) 70 | qc.tdg(d) 71 | qc.cx(a, d) 72 | qc.h(d) 73 | qc.t(d) 74 | qc.cx(c, d) 75 | qc.tdg(d) 76 | qc.h(d) 77 | 78 | def RT4S(qc, a, b, c, d): 79 | ## fig 4 dashed 80 | qc.h(d) 81 | qc.t(d) 82 | qc.cx(c, d) 83 | qc.tdg(d) 84 | qc.h(d) 85 | qc.cx(a, d) 86 | qc.t(d) 87 | qc.cx(b, d) 88 | qc.tdg(d) 89 | qc.cx(a, d) 90 | 91 | def RT4S_inv(qc, a, b, c, d): 92 | qc.cx(a, d) 93 | qc.t(d) 94 | qc.cx(b, d) 95 | qc.tdg(d) 96 | qc.cx(a, d) 97 | qc.h(d) 98 | qc.t(d) 99 | qc.cx(c, d) 100 | qc.tdg(d) 101 | qc.h(d) 102 | 103 | def apply_mct_clean(self, controls, target, ancilla_register): 104 | if len(controls) < 3: 105 | raise ValueError("there's something wrong") 106 | 107 | n = len(controls) 108 | ancilla = ancilla_register[:ceil((n-2)/2)] 109 | 110 | if n == 3: 111 | # TODO: Check for ancilla length 112 | self.rccx(controls[0], controls[1], ancilla[0]) 113 | self.ccx(controls[2], ancilla[0], target) 114 | self.rccx(controls[0], controls[1], ancilla[0]) 115 | return 116 | 117 | if n == 4: 118 | # TODO: Check for ancilla length 119 | self.rcccx(controls[0], controls[1], controls[2], ancilla[0]) 120 | self.ccx(controls[3], ancilla[0], target) 121 | self.rcccx(controls[0], controls[1], controls[2], ancilla[0]) 122 | return 123 | 124 | ## when controls >= 5 125 | 126 | if n % 2 == 0: 127 | self.rcccx(controls[0], controls[1], controls[2], ancilla[0]) 128 | self.barrier() 129 | anc_idx = 1 130 | 131 | for i in range(3, n-1, 2): 132 | # print('i = /{}'.format(i)) 133 | self.rcccx(controls[i], controls[i+1], ancilla[anc_idx-1], ancilla[anc_idx]) 134 | self.barrier() 135 | anc_idx += 1 136 | if (n-3)%2 == 1: 137 | self.ccx(controls[-1], ancilla[-1], target) 138 | self.barrier() 139 | else: 140 | self.rccx(controls[-2], ancilla[-2], ancilla[-1]) 141 | self.barrier() 142 | self.ccx(controls[-1], ancilla[-1], target) 143 | self.barrier() 144 | self.rccx(controls[-2], ancilla[-2], ancilla[-1]) 145 | self.barrier() 146 | for i in reversed(range(3, n-1, 2)): 147 | anc_idx -= 1 148 | self.rcccx(controls[i], controls[i+1], ancilla[anc_idx-1], ancilla[anc_idx]) 149 | self.barrier() 150 | 151 | self.rcccx(controls[0], controls[1], controls[2], ancilla[0]) 152 | else: 153 | self.rcccx(controls[0], controls[1], controls[2], ancilla[0]) 154 | self.barrier() 155 | anc_idx = 1 156 | 157 | for i in range(3, n-3, 2): 158 | # print('i = /{}'.format(i)) 159 | self.rcccx(controls[i], controls[i+1], ancilla[anc_idx-1], ancilla[anc_idx]) 160 | self.barrier() 161 | anc_idx += 1 162 | if (n-3)%2 == 1: 163 | self.ccx(controls[-1], ancilla[-1], target) 164 | self.barrier() 165 | else: 166 | self.rccx(controls[-2], ancilla[-2], ancilla[-1]) 167 | self.barrier() 168 | self.ccx(controls[-1], ancilla[-1], target) 169 | self.barrier() 170 | self.rccx(controls[-2], ancilla[-2], ancilla[-1]) 171 | self.barrier() 172 | for i in reversed(range(3, n-3, 2)): 173 | anc_idx -= 1 174 | self.rcccx(controls[i], controls[i+1], ancilla[anc_idx-1], ancilla[anc_idx]) 175 | self.barrier() 176 | 177 | self.rcccx(controls[0], controls[1], controls[2], ancilla[0]) 178 | 179 | def apply_mct_dirty(self, controls, target, ancilla): 180 | # TODO: check controls to be list of bits or register 181 | if len(controls) == 1: 182 | self.cx(controls[0], target) 183 | return 184 | if len(controls) == 2: 185 | self.ccx(controls[0], controls[1], target) 186 | return 187 | 188 | if len(controls) == 3: 189 | SRTS(self, controls[2], ancilla[0], target) 190 | RTL(self, controls[0], controls[1], ancilla[0]) 191 | SRTS_inv(self, controls[2], ancilla[0], target) 192 | RTL_inv(self, controls[0], controls[1], ancilla[0]) 193 | return 194 | 195 | n = len(controls) 196 | anc = ancilla[:ceil((n-2)/2)] 197 | 198 | 199 | SRTS(self, controls[-1], anc[-1], target) 200 | self.barrier() 201 | 202 | if (n-4)%2 == 0: 203 | a_idx = 1 204 | for i in reversed(range(floor((n-4)/2))): 205 | RT4S(self, anc[a_idx - 1 + i], controls[2*i+3], controls[2*i+4], anc[a_idx + i]) 206 | self.barrier() 207 | else: 208 | a_idx = 2 209 | for i in reversed(range(floor((n-4)/2))): 210 | RT4S(self, anc[a_idx - 1 + i], controls[2*i+4], controls[2*i+5], anc[a_idx + i]) 211 | self.barrier() 212 | RTS(self, anc[0], controls[3], anc[1]) 213 | self.barrier() 214 | 215 | RT4L(self, controls[0], controls[1], controls[2], anc[0]) 216 | self.barrier() 217 | 218 | if (n-4)%2 == 0: 219 | a_idx = 1 220 | for i in (range(floor((n-4)/2))): 221 | RT4S_inv(self, anc[a_idx - 1 + i], controls[2*i+3], controls[2*i+4], anc[a_idx + i]) 222 | self.barrier() 223 | else: 224 | a_idx = 2 225 | RTS_inv(self, anc[0], controls[3], anc[1]) 226 | self.barrier() 227 | for i in (range(floor((n-4)/2))): 228 | RT4S_inv(self, anc[a_idx - 1 + i], controls[2*i+4], controls[2*i+5], anc[a_idx + i]) 229 | self.barrier() 230 | 231 | SRTS_inv(self, controls[-1], anc[-1], target) 232 | self.barrier() 233 | 234 | ## SAME AS ABOVE 235 | if (n-4)%2 == 0: 236 | a_idx = 1 237 | for i in reversed(range(floor((n-4)/2))): 238 | RT4S(self, anc[a_idx - 1 + i], controls[2*i+3], controls[2*i+4], anc[a_idx + i]) 239 | self.barrier() 240 | else: 241 | a_idx = 2 242 | for i in reversed(range(floor((n-4)/2))): 243 | RT4S(self, anc[a_idx - 1 + i], controls[2*i+4], controls[2*i+5], anc[a_idx + i]) 244 | self.barrier() 245 | RTS(self, anc[0], controls[3], anc[1]) 246 | self.barrier() 247 | 248 | RT4L_inv(self, controls[0], controls[1], controls[2], anc[0]) 249 | self.barrier() 250 | 251 | if (n-4)%2 == 0: 252 | a_idx = 1 253 | for i in (range(floor((n-4)/2))): 254 | RT4S_inv(self, anc[a_idx - 1 + i], controls[2*i+3], controls[2*i+4], anc[a_idx + i]) 255 | self.barrier() 256 | else: 257 | a_idx = 2 258 | RTS_inv(self, anc[0], controls[3], anc[1]) 259 | self.barrier() 260 | for i in (range(floor((n-4)/2))): 261 | RT4S_inv(self, anc[a_idx - 1 + i], controls[2*i+4], controls[2*i+5], anc[a_idx + i]) 262 | self.barrier() 263 | 264 | def apply_mct(circuit, controls, target, anc, mode='clean-ancilla'): 265 | if len(controls) == 1: 266 | circuit.cx(controls[0], target) 267 | elif len(controls) == 2: 268 | circuit.ccx(controls[0], controls[1], target) 269 | else: 270 | if mode == 'clean-ancilla': 271 | apply_mct_clean(circuit, controls, target, anc) 272 | if mode == 'dirty-ancilla': 273 | apply_mct_dirty(circuit, controls, target, anc) 274 | 275 | def _mct(self, controls, target, ancilla, mode): 276 | if controls is None or len(controls) < 0: 277 | raise ValueError('you should pass controls as list or registers') 278 | if target is None or (not isinstance(target, Qubit) and len(target) != 1): 279 | raise ValueError('target length is not 1') 280 | if ancilla is None or len(ancilla) < ceil((len(controls)-2)/2): 281 | raise ValueError('for {} controls, need at least {} ancilla'.format(len(controls), ceil((len(controls)-2)/2))) 282 | if mode is None or (mode != 'dirty-ancilla' and mode != 'clean-ancilla'): 283 | raise ValueError('unknown mode') 284 | apply_mct(self, controls, target, ancilla, mode) 285 | 286 | QuantumCircuit.mct = _mct 287 | -------------------------------------------------------------------------------- /how-to-use-custom-mct.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import qiskit\n", 10 | "from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister\n", 11 | "from qiskit import Aer\n", 12 | "\n", 13 | "import numpy as np\n", 14 | "from math import floor, ceil\n", 15 | "\n", 16 | "%matplotlib inline" 17 | ] 18 | }, 19 | { 20 | "cell_type": "code", 21 | "execution_count": 2, 22 | "metadata": {}, 23 | "outputs": [], 24 | "source": [ 25 | "import gate_extensions" 26 | ] 27 | }, 28 | { 29 | "cell_type": "code", 30 | "execution_count": 4, 31 | "metadata": {}, 32 | "outputs": [ 33 | { 34 | "name": "stdout", 35 | "output_type": "stream", 36 | "text": [ 37 | "5-bit controls\n", 38 | "31 got 1\n", 39 | "6-bit controls\n", 40 | "63 got 1\n" 41 | ] 42 | } 43 | ], 44 | "source": [ 45 | "for n in range(5, 7):\n", 46 | " print('{}-bit controls'.format(n))\n", 47 | " for inp in range(2**n):\n", 48 | " qr = QuantumRegister(n, 'qr')\n", 49 | " anc = QuantumRegister(max(ceil((n-2)/2), 1), 'anc')\n", 50 | " target = QuantumRegister(1)\n", 51 | " cr = ClassicalRegister(1, 'cr')\n", 52 | " qc = QuantumCircuit(qr, anc, target, cr)\n", 53 | " \n", 54 | " for i in range(n):\n", 55 | " if (inp & (1< 0:\n", 56 | " qc.x(qr[i])\n", 57 | " \n", 58 | " qc.mct(qr, target, anc, mode='clean-ancilla')\n", 59 | " qc.barrier()\n", 60 | " qc.measure(target, cr[0])\n", 61 | " \n", 62 | " backend = Aer.get_backend('qasm_simulator')\n", 63 | " job = qiskit.execute(qc, backend, shots=10)\n", 64 | " result = job.result()\n", 65 | " counts = result.get_counts()\n", 66 | "# print(inp)\n", 67 | " if '1' in counts:\n", 68 | " print('{} got 1'.format(inp))" 69 | ] 70 | }, 71 | { 72 | "cell_type": "code", 73 | "execution_count": null, 74 | "metadata": {}, 75 | "outputs": [], 76 | "source": [] 77 | } 78 | ], 79 | "metadata": { 80 | "kernelspec": { 81 | "display_name": "Python 3", 82 | "language": "python", 83 | "name": "python3" 84 | }, 85 | "language_info": { 86 | "codemirror_mode": { 87 | "name": "ipython", 88 | "version": 3 89 | }, 90 | "file_extension": ".py", 91 | "mimetype": "text/x-python", 92 | "name": "python", 93 | "nbconvert_exporter": "python", 94 | "pygments_lexer": "ipython3", 95 | "version": "3.7.3" 96 | } 97 | }, 98 | "nbformat": 4, 99 | "nbformat_minor": 2 100 | } 101 | -------------------------------------------------------------------------------- /multi_adder_1.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 43, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "#initialization\n", 10 | "import matplotlib.pyplot as plt\n", 11 | "%matplotlib inline\n", 12 | "import numpy as np\n", 13 | "\n", 14 | "# importing Qiskit\n", 15 | "from qiskit import IBMQ, BasicAer, Aer\n", 16 | "from qiskit.providers.ibmq import least_busy\n", 17 | "from qiskit import QuantumCircuit, ClassicalRegister, QuantumRegister, execute\n", 18 | "\n", 19 | "# import basic plot tools\n", 20 | "from qiskit.tools.visualization import plot_histogram" 21 | ] 22 | }, 23 | { 24 | "cell_type": "code", 25 | "execution_count": 44, 26 | "metadata": {}, 27 | "outputs": [], 28 | "source": [ 29 | "provider = IBMQ.load_account()" 30 | ] 31 | }, 32 | { 33 | "cell_type": "code", 34 | "execution_count": 61, 35 | "metadata": {}, 36 | "outputs": [], 37 | "source": [ 38 | "\n", 39 | "def maj(a, b, k):\n", 40 | " qc.cx(q[k], q[b])\n", 41 | " qc.cx(q[k], q[a])\n", 42 | " qc.ccx(q[a], q[b], q[k])\n", 43 | " \n", 44 | "def unmaj(a, b, k):\n", 45 | " qc.ccx(q[a], q[b], q[k])\n", 46 | " qc.cx(q[k], q[a])\n", 47 | " qc.cx(q[a], q[b])\n", 48 | " \n", 49 | "def multiple_adder(a, b, c_0, z):\n", 50 | " arr_size = len(a)\n", 51 | " maj(c_0, b[0], a[0])\n", 52 | " for i in range(arr_size-1):\n", 53 | " maj(a[i], b[i+1], a[i+1])\n", 54 | " qc.cx(q[a[arr_size-1]], q[z])\n", 55 | " for i in reversed(range(arr_size-1)):\n", 56 | " unmaj(a[i], b[i+1], a[i+1])\n", 57 | " unmaj(c_0, b[0], a[0])\n", 58 | " " 59 | ] 60 | }, 61 | { 62 | "cell_type": "code", 63 | "execution_count": 63, 64 | "metadata": {}, 65 | "outputs": [ 66 | { 67 | "name": "stdout", 68 | "output_type": "stream", 69 | "text": [ 70 | "{'0001110011': 1024}\n" 71 | ] 72 | }, 73 | { 74 | "data": { 75 | "text/html": [ 76 | "
           ┌───┐ ░                          ┌───┐┌───┐                         »\n",
 77 |        " q26_0: |0>┤ X ├─░───■───────────────────■──┤ X ├┤ X ├──■──────────────────────»\n",
 78 |        "           ├───┤ ░   │                   │  └─┬─┘└─┬─┘┌─┴─┐┌───┐               »\n",
 79 |        " q26_1: |0>┤ X ├─░───┼────■──────────────┼────┼────■──┤ X ├┤ X ├──■────────────»\n",
 80 |        "           └───┘ ░   │    │              │    │       └─┬─┘└─┬─┘┌─┴─┐┌───┐     »\n",
 81 |        " q26_2: |0>──────░───┼────┼────■─────────┼────┼─────────┼────■──┤ X ├┤ X ├──■──»\n",
 82 |        "                 ░   │    │    │         │    │         │       └─┬─┘└─┬─┘┌─┴─┐»\n",
 83 |        " q26_3: |0>──────░───┼────┼────┼────■────┼────┼─────────┼─────────┼────■──┤ X ├»\n",
 84 |        "                 ░ ┌─┴─┐  │    │    │    │    │         │         │       └─┬─┘»\n",
 85 |        " q26_4: |0>──────░─┤ X ├──┼────┼────┼────┼────■─────────┼─────────┼─────────┼──»\n",
 86 |        "                 ░ └───┘┌─┴─┐  │    │    │    │         │         │         │  »\n",
 87 |        " q26_5: |0>──────░──────┤ X ├──┼────┼────┼────┼─────────■─────────┼─────────┼──»\n",
 88 |        "           ┌───┐ ░      └───┘┌─┴─┐  │    │    │                   │         │  »\n",
 89 |        " q26_6: |0>┤ X ├─░───────────┤ X ├──┼────┼────┼───────────────────■─────────┼──»\n",
 90 |        "           └───┘ ░           └───┘┌─┴─┐  │    │                             │  »\n",
 91 |        " q26_7: |0>──────░────────────────┤ X ├──┼────┼─────────────────────────────■──»\n",
 92 |        "                 ░                └───┘┌─┴─┐  │                                »\n",
 93 |        " q26_8: |0>──────░─────────────────────┤ X ├──■────────────────────────────────»\n",
 94 |        "                 ░                     └───┘                                   »\n",
 95 |        " q26_9: |0>──────░─────────────────────────────────────────────────────────────»\n",
 96 |        "                 ░                                                             »\n",
 97 |        "q26_10: |0>──────░─────────────────────────────────────────────────────────────»\n",
 98 |        "                 ░                                                             »\n",
 99 |        "q26_11: |0>──────░─────────────────────────────────────────────────────────────»\n",
100 |        "                 ░                                                             »\n",
101 |        "q26_12: |0>──────░─────────────────────────────────────────────────────────────»\n",
102 |        "                 ░                                                             »\n",
103 |        "q26_13: |0>──────░─────────────────────────────────────────────────────────────»\n",
104 |        "                 ░                                                             »\n",
105 |        "q26_14: |0>──────░─────────────────────────────────────────────────────────────»\n",
106 |        "                 ░                                                             »\n",
107 |        "q26_15: |0>──────░─────────────────────────────────────────────────────────────»\n",
108 |        "                 ░                                                             »\n",
109 |        "q26_16: |0>──────░─────────────────────────────────────────────────────────────»\n",
110 |        "                 ░                                                             »\n",
111 |        "q26_17: |0>──────░─────────────────────────────────────────────────────────────»\n",
112 |        "                 ░                                                             »\n",
113 |        "q26_18: |0>──────░─────────────────────────────────────────────────────────────»\n",
114 |        "                 ░                                                             »\n",
115 |        "q26_19: |0>──────░─────────────────────────────────────────────────────────────»\n",
116 |        "                 ░                                                             »\n",
117 |        "  c26_0: 0 ════════════════════════════════════════════════════════════════════»\n",
118 |        "                                                                               »\n",
119 |        "  c26_1: 0 ════════════════════════════════════════════════════════════════════»\n",
120 |        "                                                                               »\n",
121 |        "  c26_2: 0 ════════════════════════════════════════════════════════════════════»\n",
122 |        "                                                                               »\n",
123 |        "  c26_3: 0 ════════════════════════════════════════════════════════════════════»\n",
124 |        "                                                                               »\n",
125 |        "  c26_4: 0 ════════════════════════════════════════════════════════════════════»\n",
126 |        "                                                                               »\n",
127 |        "  c26_5: 0 ════════════════════════════════════════════════════════════════════»\n",
128 |        "                                                                               »\n",
129 |        "  c26_6: 0 ════════════════════════════════════════════════════════════════════»\n",
130 |        "                                                                               »\n",
131 |        "  c26_7: 0 ════════════════════════════════════════════════════════════════════»\n",
132 |        "                                                                               »\n",
133 |        "  c26_8: 0 ════════════════════════════════════════════════════════════════════»\n",
134 |        "                                                                               »\n",
135 |        "  c26_9: 0 ════════════════════════════════════════════════════════════════════»\n",
136 |        "                                                                               »\n",
137 |        "«                                                      ┌───┐        ┌───┐   »\n",
138 |        "« q26_0: ───────────────────────────────────────────■──┤ X ├──■─────┤ X ├───»\n",
139 |        "«                                    ┌───┐        ┌─┴─┐└─┬─┘  │  ┌─┐└─┬─┘   »\n",
140 |        "« q26_1: ─────────────────────────■──┤ X ├──■─────┤ X ├──■────┼──┤M├──┼─────»\n",
141 |        "«                  ┌───┐        ┌─┴─┐└─┬─┘  │  ┌─┐└─┬─┘       │  └╥┘  │     »\n",
142 |        "« q26_2: ───────■──┤ X ├──■─────┤ X ├──■────┼──┤M├──┼─────────┼───╫───┼─────»\n",
143 |        "«             ┌─┴─┐└─┬─┘  │  ┌─┐└─┬─┘       │  └╥┘  │         │   ║   │     »\n",
144 |        "« q26_3: ──■──┤ X ├──■────┼──┤M├──┼─────────┼───╫───┼─────────┼───╫───┼─────»\n",
145 |        "«          │  └─┬─┘       │  └╥┘  │         │   ║   │         │   ║   │     »\n",
146 |        "« q26_4: ──┼────┼─────────┼───╫───┼─────────┼───╫───┼─────────┼───╫───■─────»\n",
147 |        "«          │    │         │   ║   │         │   ║   │       ┌─┴─┐ ║   │  ┌─┐»\n",
148 |        "« q26_5: ──┼────┼─────────┼───╫───┼─────────┼───╫───■───────┤ X ├─╫───┼──┤M├»\n",
149 |        "«          │    │         │   ║   │       ┌─┴─┐ ║  ┌─┐      └───┘ ║   │  └╥┘»\n",
150 |        "« q26_6: ──┼────┼─────────┼───╫───■───────┤ X ├─╫──┤M├────────────╫───┼───╫─»\n",
151 |        "«          │    │       ┌─┴─┐ ║  ┌─┐      └───┘ ║  └╥┘            ║   │   ║ »\n",
152 |        "« q26_7: ──┼────■───────┤ X ├─╫──┤M├────────────╫───╫─────────────╫───┼───╫─»\n",
153 |        "«          │            └───┘ ║  └╥┘            ║   ║             ║   │   ║ »\n",
154 |        "« q26_8: ──┼──────────────────╫───╫─────────────╫───╫─────────────╫───■───╫─»\n",
155 |        "«        ┌─┴─┐ ┌─┐            ║   ║             ║   ║             ║       ║ »\n",
156 |        "« q26_9: ┤ X ├─┤M├────────────╫───╫─────────────╫───╫─────────────╫───────╫─»\n",
157 |        "«        └───┘ └╥┘            ║   ║             ║   ║             ║       ║ »\n",
158 |        "«q26_10: ───────╫─────────────╫───╫─────────────╫───╫─────────────╫───────╫─»\n",
159 |        "«               ║             ║   ║             ║   ║             ║       ║ »\n",
160 |        "«q26_11: ───────╫─────────────╫───╫─────────────╫───╫─────────────╫───────╫─»\n",
161 |        "«               ║             ║   ║             ║   ║             ║       ║ »\n",
162 |        "«q26_12: ───────╫─────────────╫───╫─────────────╫───╫─────────────╫───────╫─»\n",
163 |        "«               ║             ║   ║             ║   ║             ║       ║ »\n",
164 |        "«q26_13: ───────╫─────────────╫───╫─────────────╫───╫─────────────╫───────╫─»\n",
165 |        "«               ║             ║   ║             ║   ║             ║       ║ »\n",
166 |        "«q26_14: ───────╫─────────────╫───╫─────────────╫───╫─────────────╫───────╫─»\n",
167 |        "«               ║             ║   ║             ║   ║             ║       ║ »\n",
168 |        "«q26_15: ───────╫─────────────╫───╫─────────────╫───╫─────────────╫───────╫─»\n",
169 |        "«               ║             ║   ║             ║   ║             ║       ║ »\n",
170 |        "«q26_16: ───────╫─────────────╫───╫─────────────╫───╫─────────────╫───────╫─»\n",
171 |        "«               ║             ║   ║             ║   ║             ║       ║ »\n",
172 |        "«q26_17: ───────╫─────────────╫───╫─────────────╫───╫─────────────╫───────╫─»\n",
173 |        "«               ║             ║   ║             ║   ║             ║       ║ »\n",
174 |        "«q26_18: ───────╫─────────────╫───╫─────────────╫───╫─────────────╫───────╫─»\n",
175 |        "«               ║             ║   ║             ║   ║             ║       ║ »\n",
176 |        "«q26_19: ───────╫─────────────╫───╫─────────────╫───╫─────────────╫───────╫─»\n",
177 |        "«               ║             ║   ║             ║   ║             ║       ║ »\n",
178 |        "« c26_0: ═══════╬═════════════╬═══╬═════════════╬═══╬═════════════╬═══════╬═»\n",
179 |        "«               ║             ║   ║             ║   ║             ║       ║ »\n",
180 |        "« c26_1: ═══════╬═════════════╬═══╬═════════════╬═══╬═════════════╩═══════╬═»\n",
181 |        "«               ║             ║   ║             ║   ║                     ║ »\n",
182 |        "« c26_2: ═══════╬═════════════╬═══╬═════════════╩═══╬═════════════════════╬═»\n",
183 |        "«               ║             ║   ║                 ║                     ║ »\n",
184 |        "« c26_3: ═══════╬═════════════╩═══╬═════════════════╬═════════════════════╬═»\n",
185 |        "«               ║                 ║                 ║                     ║ »\n",
186 |        "« c26_4: ═══════╬═════════════════╬═════════════════╬═════════════════════╬═»\n",
187 |        "«               ║                 ║                 ║                     ║ »\n",
188 |        "« c26_5: ═══════╬═════════════════╬═════════════════╬═════════════════════╩═»\n",
189 |        "«               ║                 ║                 ║                       »\n",
190 |        "« c26_6: ═══════╬═════════════════╬═════════════════╩═══════════════════════»\n",
191 |        "«               ║                 ║                                         »\n",
192 |        "« c26_7: ═══════╬═════════════════╩═════════════════════════════════════════»\n",
193 |        "«               ║                                                           »\n",
194 |        "« c26_8: ═══════╬═══════════════════════════════════════════════════════════»\n",
195 |        "«               ║                                                           »\n",
196 |        "« c26_9: ═══════╩═══════════════════════════════════════════════════════════»\n",
197 |        "«                                                                           »\n",
198 |        "«                  ┌─┐      \n",
199 |        "« q26_0: ──■───────┤M├──────\n",
200 |        "«          │       └╥┘      \n",
201 |        "« q26_1: ──┼────────╫───────\n",
202 |        "«          │        ║       \n",
203 |        "« q26_2: ──┼────────╫───────\n",
204 |        "«          │        ║       \n",
205 |        "« q26_3: ──┼────────╫───────\n",
206 |        "«          │  ┌───┐ ║ ┌─┐   \n",
207 |        "« q26_4: ──┼──┤ X ├─╫─┤M├───\n",
208 |        "«          │  └─┬─┘ ║ └╥┘   \n",
209 |        "« q26_5: ──┼────┼───╫──╫────\n",
210 |        "«          │    │   ║  ║    \n",
211 |        "« q26_6: ──┼────┼───╫──╫────\n",
212 |        "«          │    │   ║  ║    \n",
213 |        "« q26_7: ──┼────┼───╫──╫────\n",
214 |        "«        ┌─┴─┐  │   ║  ║ ┌─┐\n",
215 |        "« q26_8: ┤ X ├──■───╫──╫─┤M├\n",
216 |        "«        └───┘      ║  ║ └╥┘\n",
217 |        "« q26_9: ───────────╫──╫──╫─\n",
218 |        "«                   ║  ║  ║ \n",
219 |        "«q26_10: ───────────╫──╫──╫─\n",
220 |        "«                   ║  ║  ║ \n",
221 |        "«q26_11: ───────────╫──╫──╫─\n",
222 |        "«                   ║  ║  ║ \n",
223 |        "«q26_12: ───────────╫──╫──╫─\n",
224 |        "«                   ║  ║  ║ \n",
225 |        "«q26_13: ───────────╫──╫──╫─\n",
226 |        "«                   ║  ║  ║ \n",
227 |        "«q26_14: ───────────╫──╫──╫─\n",
228 |        "«                   ║  ║  ║ \n",
229 |        "«q26_15: ───────────╫──╫──╫─\n",
230 |        "«                   ║  ║  ║ \n",
231 |        "«q26_16: ───────────╫──╫──╫─\n",
232 |        "«                   ║  ║  ║ \n",
233 |        "«q26_17: ───────────╫──╫──╫─\n",
234 |        "«                   ║  ║  ║ \n",
235 |        "«q26_18: ───────────╫──╫──╫─\n",
236 |        "«                   ║  ║  ║ \n",
237 |        "«q26_19: ───────────╫──╫──╫─\n",
238 |        "«                   ║  ║  ║ \n",
239 |        "« c26_0: ═══════════╩══╬══╬═\n",
240 |        "«                      ║  ║ \n",
241 |        "« c26_1: ══════════════╬══╬═\n",
242 |        "«                      ║  ║ \n",
243 |        "« c26_2: ══════════════╬══╬═\n",
244 |        "«                      ║  ║ \n",
245 |        "« c26_3: ══════════════╬══╬═\n",
246 |        "«                      ║  ║ \n",
247 |        "« c26_4: ══════════════╩══╬═\n",
248 |        "«                         ║ \n",
249 |        "« c26_5: ═════════════════╬═\n",
250 |        "«                         ║ \n",
251 |        "« c26_6: ═════════════════╬═\n",
252 |        "«                         ║ \n",
253 |        "« c26_7: ═════════════════╬═\n",
254 |        "«                         ║ \n",
255 |        "« c26_8: ═════════════════╩═\n",
256 |        "«                           \n",
257 |        "« c26_9: ═══════════════════\n",
258 |        "«                           
" 259 | ], 260 | "text/plain": [ 261 | "" 262 | ] 263 | }, 264 | "execution_count": 63, 265 | "metadata": {}, 266 | "output_type": "execute_result" 267 | } 268 | ], 269 | "source": [ 270 | "qubit_num = 20 # max is 32 if you're using the simulator \n", 271 | "q = QuantumRegister(qubit_num)\n", 272 | "c = ClassicalRegister(10)\n", 273 | "qc = QuantumCircuit(q, c)\n", 274 | "\n", 275 | "qc.x(q[0:2])\n", 276 | "qc.x(q[6])\n", 277 | "\n", 278 | "\n", 279 | "qc.barrier(q)\n", 280 | "\n", 281 | "# initialize_oracle_part(4)\n", 282 | "multiple_adder([0,1,2,3], [4,5,6,7], 8, 9)\n", 283 | "\n", 284 | "for i in range(10):\n", 285 | " qc.measure(q[i], c[i])\n", 286 | "\n", 287 | "r = execute(qc, Aer.get_backend('qasm_simulator')).result()\n", 288 | "rc = r.get_counts()\n", 289 | "print(rc)\n", 290 | "plot_histogram(rc)\n", 291 | "\n", 292 | "qc.draw()" 293 | ] 294 | }, 295 | { 296 | "cell_type": "code", 297 | "execution_count": null, 298 | "metadata": {}, 299 | "outputs": [], 300 | "source": [] 301 | }, 302 | { 303 | "cell_type": "code", 304 | "execution_count": null, 305 | "metadata": {}, 306 | "outputs": [], 307 | "source": [] 308 | } 309 | ], 310 | "metadata": { 311 | "kernelspec": { 312 | "display_name": "Python 3", 313 | "language": "python", 314 | "name": "python3" 315 | }, 316 | "language_info": { 317 | "codemirror_mode": { 318 | "name": "ipython", 319 | "version": 3 320 | }, 321 | "file_extension": ".py", 322 | "mimetype": "text/x-python", 323 | "name": "python", 324 | "nbconvert_exporter": "python", 325 | "pygments_lexer": "ipython3", 326 | "version": "3.7.3" 327 | } 328 | }, 329 | "nbformat": 4, 330 | "nbformat_minor": 2 331 | } 332 | -------------------------------------------------------------------------------- /multiple-controlled-toffoli-gate-testing.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 57, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import qiskit\n", 10 | "from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister\n", 11 | "from qiskit import Aer\n", 12 | "\n", 13 | "import numpy as np\n", 14 | "from math import floor, ceil\n", 15 | "\n", 16 | "%matplotlib inline" 17 | ] 18 | }, 19 | { 20 | "cell_type": "code", 21 | "execution_count": 2, 22 | "metadata": {}, 23 | "outputs": [], 24 | "source": [ 25 | "def RTL(qc, a, b, c):\n", 26 | " ## fig 3 dashed\n", 27 | " qc.rccx(a, b, c)\n", 28 | " \n", 29 | "def RTL_inv(qc, a, b, c):\n", 30 | " RTL(qc, a, b, c)" 31 | ] 32 | }, 33 | { 34 | "cell_type": "code", 35 | "execution_count": 3, 36 | "metadata": {}, 37 | "outputs": [], 38 | "source": [ 39 | "def RTS(qc, a, b, c):\n", 40 | " ## fig 3 gates 2-6\n", 41 | " qc.h(c)\n", 42 | " qc.t(c)\n", 43 | " qc.cx(b, c)\n", 44 | " qc.tdg(c)\n", 45 | " qc.cx(a, c)\n", 46 | " \n", 47 | "def RTS_inv(qc, a, b, c):\n", 48 | " qc.cx(a, c)\n", 49 | " qc.t(c)\n", 50 | " qc.cx(b, c)\n", 51 | " qc.tdg(c)\n", 52 | " qc.h(c)" 53 | ] 54 | }, 55 | { 56 | "cell_type": "code", 57 | "execution_count": 70, 58 | "metadata": {}, 59 | "outputs": [], 60 | "source": [ 61 | "def SRTS(qc, a, b, c):\n", 62 | " ## circuit 3 dashed\n", 63 | " qc.h(c)\n", 64 | " qc.cx(c, b)\n", 65 | " qc.tdg(b)\n", 66 | " qc.cx(a, b)\n", 67 | " qc.t(b)\n", 68 | " qc.cx(c, b)\n", 69 | " qc.tdg(b)\n", 70 | " qc.cx(a, b)\n", 71 | " qc.t(b)\n", 72 | " \n", 73 | "def SRTS_inv(qc, a, b, c):\n", 74 | " qc.tdg(b)\n", 75 | " qc.cx(a, b)\n", 76 | " qc.t(b)\n", 77 | " qc.cx(c, b)\n", 78 | " qc.tdg(b)\n", 79 | " qc.cx(a, b)\n", 80 | " qc.t(b)\n", 81 | " qc.cx(c, b)\n", 82 | " qc.h(c)" 83 | ] 84 | }, 85 | { 86 | "cell_type": "code", 87 | "execution_count": 71, 88 | "metadata": {}, 89 | "outputs": [], 90 | "source": [ 91 | "def RT4L(qc, a, b, c, d):\n", 92 | " ## fig 4\n", 93 | " qc.rcccx(a, b, c, d)\n", 94 | " \n", 95 | "def RT4L_inv(qc, a, b, c, d):\n", 96 | " qc.h(d)\n", 97 | " qc.t(d)\n", 98 | " qc.cx(c, d)\n", 99 | " qc.tdg(d)\n", 100 | " qc.h(d)\n", 101 | " qc.t(d)\n", 102 | " qc.cx(b, d)\n", 103 | " qc.tdg(d)\n", 104 | " qc.cx(a, d)\n", 105 | " qc.t(d)\n", 106 | " qc.cx(b, d)\n", 107 | " qc.tdg(d)\n", 108 | " qc.cx(a, d)\n", 109 | " qc.h(d)\n", 110 | " qc.t(d)\n", 111 | " qc.cx(c, d)\n", 112 | " qc.tdg(d)\n", 113 | " qc.h(d)" 114 | ] 115 | }, 116 | { 117 | "cell_type": "code", 118 | "execution_count": 72, 119 | "metadata": {}, 120 | "outputs": [], 121 | "source": [ 122 | "def RT4S(qc, a, b, c, d):\n", 123 | " ## fig 4 dashed\n", 124 | " qc.h(d)\n", 125 | " qc.t(d)\n", 126 | " qc.cx(c, d)\n", 127 | " qc.tdg(d)\n", 128 | " qc.h(d)\n", 129 | " qc.cx(a, d)\n", 130 | " qc.t(d)\n", 131 | " qc.cx(b, d)\n", 132 | " qc.tdg(d)\n", 133 | " qc.cx(a, d)\n", 134 | " \n", 135 | "def RT4S_inv(qc, a, b, c, d):\n", 136 | " qc.cx(a, d)\n", 137 | " qc.t(d)\n", 138 | " qc.cx(b, d)\n", 139 | " qc.tdg(d)\n", 140 | " qc.cx(a, d)\n", 141 | " qc.h(d)\n", 142 | " qc.t(d)\n", 143 | " qc.cx(c, d)\n", 144 | " qc.tdg(d)\n", 145 | " qc.h(d)" 146 | ] 147 | }, 148 | { 149 | "cell_type": "code", 150 | "execution_count": 184, 151 | "metadata": {}, 152 | "outputs": [], 153 | "source": [ 154 | "def apply_mct_clean(self, controls, target, ancilla_register):\n", 155 | " if len(controls) < 3:\n", 156 | " raise ValueError(\"there's something wrong\")\n", 157 | " \n", 158 | " n = len(controls)\n", 159 | " ancilla = ancilla_register[:ceil((n-2)/2)]\n", 160 | " \n", 161 | " if n == 3:\n", 162 | " # TODO: Check for ancilla length\n", 163 | " self.rccx(controls[0], controls[1], ancilla[0])\n", 164 | " self.ccx(controls[2], ancilla[0], target)\n", 165 | " self.rccx(controls[0], controls[1], ancilla[0])\n", 166 | " return\n", 167 | " \n", 168 | " if n == 4:\n", 169 | " # TODO: Check for ancilla length\n", 170 | " self.rcccx(controls[0], controls[1], controls[2], ancilla[0])\n", 171 | " self.ccx(controls[3], ancilla[0], target)\n", 172 | " self.rcccx(controls[0], controls[1], controls[2], ancilla[0])\n", 173 | " return\n", 174 | " \n", 175 | " ## when controls >= 5\n", 176 | " \n", 177 | " if n % 2 == 0:\n", 178 | " self.rcccx(controls[0], controls[1], controls[2], ancilla[0])\n", 179 | " self.barrier()\n", 180 | " anc_idx = 1\n", 181 | "\n", 182 | " for i in range(3, n-1, 2):\n", 183 | " # print('i = /{}'.format(i))\n", 184 | " self.rcccx(controls[i], controls[i+1], ancilla[anc_idx-1], ancilla[anc_idx])\n", 185 | " self.barrier()\n", 186 | " anc_idx += 1\n", 187 | " if (n-3)%2 == 1:\n", 188 | " self.ccx(controls[-1], ancilla[-1], target)\n", 189 | " self.barrier()\n", 190 | " else:\n", 191 | " self.rccx(controls[-2], ancilla[-2], ancilla[-1])\n", 192 | " self.barrier()\n", 193 | " self.ccx(controls[-1], ancilla[-1], target)\n", 194 | " self.barrier()\n", 195 | " self.rccx(controls[-2], ancilla[-2], ancilla[-1])\n", 196 | " self.barrier()\n", 197 | " for i in reversed(range(3, n-1, 2)):\n", 198 | " anc_idx -= 1\n", 199 | " self.rcccx(controls[i], controls[i+1], ancilla[anc_idx-1], ancilla[anc_idx])\n", 200 | " self.barrier()\n", 201 | "\n", 202 | " self.rcccx(controls[0], controls[1], controls[2], ancilla[0])\n", 203 | " else:\n", 204 | " self.rcccx(controls[0], controls[1], controls[2], ancilla[0])\n", 205 | " self.barrier()\n", 206 | " anc_idx = 1\n", 207 | "\n", 208 | " for i in range(3, n-3, 2):\n", 209 | " # print('i = /{}'.format(i))\n", 210 | " self.rcccx(controls[i], controls[i+1], ancilla[anc_idx-1], ancilla[anc_idx])\n", 211 | " self.barrier()\n", 212 | " anc_idx += 1\n", 213 | " if (n-3)%2 == 1:\n", 214 | " self.ccx(controls[-1], ancilla[-1], target)\n", 215 | " self.barrier()\n", 216 | " else:\n", 217 | " self.rccx(controls[-2], ancilla[-2], ancilla[-1])\n", 218 | " self.barrier()\n", 219 | " self.ccx(controls[-1], ancilla[-1], target)\n", 220 | " self.barrier()\n", 221 | " self.rccx(controls[-2], ancilla[-2], ancilla[-1])\n", 222 | " self.barrier()\n", 223 | " for i in reversed(range(3, n-3, 2)):\n", 224 | " anc_idx -= 1\n", 225 | " self.rcccx(controls[i], controls[i+1], ancilla[anc_idx-1], ancilla[anc_idx])\n", 226 | " self.barrier()\n", 227 | "\n", 228 | " self.rcccx(controls[0], controls[1], controls[2], ancilla[0])\n", 229 | " \n", 230 | "qr = QuantumRegister(5, 'qr')\n", 231 | "anc = QuantumRegister(2, 'anc')\n", 232 | "target = QuantumRegister(1, 'target')\n", 233 | "\n", 234 | "qc = QuantumCircuit(qr, anc, target)\n", 235 | "apply_mct_clean(qc, qr, target, anc)\n", 236 | "\n", 237 | "# backend = Aer.get_backend('unitary_simulator')\n", 238 | "# job = qiskit.execute(qc, backend)\n", 239 | "# result = job.result()\n", 240 | "# print(result.get_unitary(qc, decimals=3))\n", 241 | "\n", 242 | "# qc.draw(output='mpl')" 243 | ] 244 | }, 245 | { 246 | "cell_type": "code", 247 | "execution_count": 185, 248 | "metadata": {}, 249 | "outputs": [], 250 | "source": [ 251 | "def apply_mct_dirty(self, controls, target, ancilla):\n", 252 | " # TODO: check controls to be list of bits or register\n", 253 | " if len(controls) == 1:\n", 254 | " self.cx(controls[0], target)\n", 255 | " return\n", 256 | " if len(controls) == 2:\n", 257 | " self.ccx(controls[0], controls[1], target)\n", 258 | " return\n", 259 | " \n", 260 | " if len(controls) == 3:\n", 261 | " SRTS(self, controls[2], ancilla[0], target)\n", 262 | " RTL(self, controls[0], controls[1], ancilla[0])\n", 263 | " SRTS_inv(self, controls[2], ancilla[0], target)\n", 264 | " RTL_inv(self, controls[0], controls[1], ancilla[0])\n", 265 | " return\n", 266 | " \n", 267 | " n = len(controls)\n", 268 | " anc = ancilla[:ceil((n-2)/2)]\n", 269 | " \n", 270 | " \n", 271 | " SRTS(self, controls[-1], anc[-1], target)\n", 272 | " qc.barrier()\n", 273 | " \n", 274 | " if (n-4)%2 == 0:\n", 275 | " a_idx = 1\n", 276 | " for i in reversed(range(floor((n-4)/2))):\n", 277 | " RT4S(self, anc[a_idx - 1 + i], controls[2*i+3], controls[2*i+4], anc[a_idx + i])\n", 278 | " qc.barrier()\n", 279 | " else:\n", 280 | " a_idx = 2\n", 281 | " for i in reversed(range(floor((n-4)/2))):\n", 282 | " RT4S(self, anc[a_idx - 1 + i], controls[2*i+4], controls[2*i+5], anc[a_idx + i])\n", 283 | " qc.barrier()\n", 284 | " RTS(self, anc[0], controls[3], anc[1])\n", 285 | " qc.barrier()\n", 286 | " \n", 287 | " RT4L(self, controls[0], controls[1], controls[2], anc[0])\n", 288 | " qc.barrier()\n", 289 | " \n", 290 | " if (n-4)%2 == 0:\n", 291 | " a_idx = 1\n", 292 | " for i in (range(floor((n-4)/2))):\n", 293 | " RT4S_inv(self, anc[a_idx - 1 + i], controls[2*i+3], controls[2*i+4], anc[a_idx + i])\n", 294 | " qc.barrier()\n", 295 | " else:\n", 296 | " a_idx = 2\n", 297 | " RTS_inv(self, anc[0], controls[3], anc[1])\n", 298 | " qc.barrier()\n", 299 | " for i in (range(floor((n-4)/2))):\n", 300 | " RT4S_inv(self, anc[a_idx - 1 + i], controls[2*i+4], controls[2*i+5], anc[a_idx + i])\n", 301 | " qc.barrier()\n", 302 | " \n", 303 | " SRTS_inv(self, controls[-1], anc[-1], target)\n", 304 | " qc.barrier()\n", 305 | " \n", 306 | " ## SAME AS ABOVE\n", 307 | " if (n-4)%2 == 0:\n", 308 | " a_idx = 1\n", 309 | " for i in reversed(range(floor((n-4)/2))):\n", 310 | " RT4S(self, anc[a_idx - 1 + i], controls[2*i+3], controls[2*i+4], anc[a_idx + i])\n", 311 | " qc.barrier()\n", 312 | " else:\n", 313 | " a_idx = 2\n", 314 | " for i in reversed(range(floor((n-4)/2))):\n", 315 | " RT4S(self, anc[a_idx - 1 + i], controls[2*i+4], controls[2*i+5], anc[a_idx + i])\n", 316 | " qc.barrier()\n", 317 | " RTS(self, anc[0], controls[3], anc[1])\n", 318 | " qc.barrier()\n", 319 | " \n", 320 | " RT4L_inv(self, controls[0], controls[1], controls[2], anc[0])\n", 321 | " qc.barrier()\n", 322 | " \n", 323 | " if (n-4)%2 == 0:\n", 324 | " a_idx = 1\n", 325 | " for i in (range(floor((n-4)/2))):\n", 326 | " RT4S_inv(self, anc[a_idx - 1 + i], controls[2*i+3], controls[2*i+4], anc[a_idx + i])\n", 327 | " qc.barrier()\n", 328 | " else:\n", 329 | " a_idx = 2\n", 330 | " RTS_inv(self, anc[0], controls[3], anc[1])\n", 331 | " qc.barrier()\n", 332 | " for i in (range(floor((n-4)/2))):\n", 333 | " RT4S_inv(self, anc[a_idx - 1 + i], controls[2*i+4], controls[2*i+5], anc[a_idx + i])\n", 334 | " qc.barrier()" 335 | ] 336 | }, 337 | { 338 | "cell_type": "code", 339 | "execution_count": 186, 340 | "metadata": {}, 341 | "outputs": [], 342 | "source": [ 343 | "qr = QuantumRegister(3, 'qr')\n", 344 | "anc = QuantumRegister(3, 'anc')\n", 345 | "target = QuantumRegister(1, 'target')\n", 346 | "\n", 347 | "qc = QuantumCircuit(qr, anc, target)\n", 348 | "apply_mct_dirty(qc, qr, target, anc)\n", 349 | "\n", 350 | "# backend = Aer.get_backend('unitary_simulator')\n", 351 | "# job = qiskit.execute(qc, backend)\n", 352 | "# result = job.result()\n", 353 | "# print(result.get_unitary(qc, decimals=3))\n", 354 | "\n", 355 | "# qc.draw(output='mpl')" 356 | ] 357 | }, 358 | { 359 | "cell_type": "code", 360 | "execution_count": null, 361 | "metadata": {}, 362 | "outputs": [], 363 | "source": [] 364 | }, 365 | { 366 | "cell_type": "code", 367 | "execution_count": 187, 368 | "metadata": { 369 | "scrolled": false 370 | }, 371 | "outputs": [ 372 | { 373 | "name": "stdout", 374 | "output_type": "stream", 375 | "text": [ 376 | "5-bit controls\n", 377 | "31 got 1\n", 378 | "6-bit controls\n", 379 | "63 got 1\n", 380 | "7-bit controls\n", 381 | "127 got 1\n", 382 | "8-bit controls\n", 383 | "255 got 1\n", 384 | "9-bit controls\n", 385 | "511 got 1\n" 386 | ] 387 | } 388 | ], 389 | "source": [ 390 | "for n in range(5, 10):\n", 391 | " print('{}-bit controls'.format(n))\n", 392 | " for inp in range(2**n):\n", 393 | " qr = QuantumRegister(n, 'qr')\n", 394 | " anc = QuantumRegister(max(ceil((n-2)/2), 1), 'anc')\n", 395 | " target = QuantumRegister(1)\n", 396 | " cr = ClassicalRegister(1, 'cr')\n", 397 | " qc = QuantumCircuit(qr, anc, target, cr)\n", 398 | " \n", 399 | " for i in range(n):\n", 400 | " if (inp & (1< 0:\n", 401 | " qc.x(qr[i])\n", 402 | " \n", 403 | "# apply_mct_dirty(qc, qr, target, anc)\n", 404 | " apply_mct_clean(qc, qr, target, anc)\n", 405 | " qc.barrier()\n", 406 | " qc.measure(target, cr[0])\n", 407 | " \n", 408 | " backend = Aer.get_backend('qasm_simulator')\n", 409 | " job = qiskit.execute(qc, backend, shots=10)\n", 410 | " result = job.result()\n", 411 | " counts = result.get_counts()\n", 412 | "# print(inp)\n", 413 | " if '1' in counts:\n", 414 | " print('{} got 1'.format(inp))" 415 | ] 416 | }, 417 | { 418 | "cell_type": "code", 419 | "execution_count": null, 420 | "metadata": {}, 421 | "outputs": [], 422 | "source": [ 423 | "def apply_mct(circuit, controls, target, anc, mode='clean-ancilla'):\n", 424 | " if len(controls) == 1:\n", 425 | " circuit.cx(controls[0], target)\n", 426 | " else\n", 427 | " if mode == 'clean-ancilla':\n", 428 | " " 429 | ] 430 | }, 431 | { 432 | "cell_type": "code", 433 | "execution_count": null, 434 | "metadata": {}, 435 | "outputs": [], 436 | "source": [] 437 | }, 438 | { 439 | "cell_type": "code", 440 | "execution_count": null, 441 | "metadata": {}, 442 | "outputs": [], 443 | "source": [] 444 | } 445 | ], 446 | "metadata": { 447 | "kernelspec": { 448 | "display_name": "Python 3", 449 | "language": "python", 450 | "name": "python3" 451 | }, 452 | "language_info": { 453 | "codemirror_mode": { 454 | "name": "ipython", 455 | "version": 3 456 | }, 457 | "file_extension": ".py", 458 | "mimetype": "text/x-python", 459 | "name": "python", 460 | "nbconvert_exporter": "python", 461 | "pygments_lexer": "ipython3", 462 | "version": "3.7.5" 463 | } 464 | }, 465 | "nbformat": 4, 466 | "nbformat_minor": 2 467 | } 468 | --------------------------------------------------------------------------------