├── .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": "iVBORw0KGgoAAAANSUhEUgAAAdAAAAFWCAYAAADZtMzFAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4zLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvnQurowAAHOFJREFUeJzt3XuYXXV97/H31yCSHCCQODSZ1LQZLzhFOoRELQgYkHgq9vgoWoHWIlrlgIJaxIrn2Cq26vPkcJFq1UIviHqAQuvx0nCAkFQQEMgFG4yNhmJyJBclCUojIQG+54+1B3cme2b2/jGXPdnv1/PsZ/b6rd9a+7v+IB/W7feLzESSJLXmOeNdgCRJE5EBKklSAQNUkqQCBqgkSQUMUEmSChigkiQVMEAlSSpggEqSVMAAlSSpwH7jXcB4mj59es6ePXu8y5AktZH777//kczsGq5fRwfo7NmzWbp06XiXIUlqI9OmTVvfTD8v4UqSVMAAlSSpgAEqSVIBA1SSpAIGqCRJBQxQSZIKGKCSJBUwQCVJKmCASpJUwACVJKmAASpJUgEDVJKkAgaoJEkFDFBJkgoYoJIkFTBAJUkqYIBKklTAAJUkqYABKklSAQNUkqQCBqgkSQUMUEmSChigkiQVMEClfdB5553HS17yEo499tiG6zOTiy66iHnz5nHcccfxve9975l11157LfPnz2f+/Plce+21z7Tff//9vOpVr2LevHlcdNFFZOaoH4fUzgxQaR/0B3/wB9xwww2Drl+yZAkPPvggy5cv5/LLL+eDH/wgANu3b2fRokXceuutLFmyhEWLFvHoo48CcOGFF3L55ZezfPlyHnzwQZYsWTImxyK1KwNU2gcde+yxHHrooYOuX7x4MaeffjoRwctf/nJ+8YtfsHnzZpYuXcqCBQs49NBDOeSQQ1iwYAG33XYbmzdv5rHHHuMVr3gFEcHpp5/O4sWLx/CIpPZjgEodaNOmTcyaNeuZ5e7ubjZt2sTGjRv3at+4cSObNm2iu7t7r/5SJzNApQ7U6P5lRLTcLnUyA1TqQN3d3Tz88MPPLG/cuJEZM2Ywa9asvdpnzpz5zJnowP5SJzNApQ70ute9juuuu47M5L777uPggw9mxowZnHTSSSxbtoxHH32URx99lGXLlnHSSScxY8YMDjzwQO677z4yk+uuu45TTjllvA9DGlf7jXcBkkbeu971Lu688062bt3KEUccwUUXXcSTTz4JwDve8Q4WLlzIrbfeyrx585g8eTKf+9znADj00EO58MILec1rXgPAhz70oWceRrrkkkt473vfy86dOzn55JM5+eSTx+fgpDYRnfwu19y5c3Pp0qXjXYYkqY1MmzZtRWbOH66fl3AlSSpggEqSVMAAlSSpgAEqSVIBA1SSpAIGqCRJBQxQSZIKGKCSJBUY0wCNiBMi4hsR8XBEZESc1cQ2R0bEtyPi8dp2fx4DRrGOiDdHxJqIeKL2902jdhCSJDH2Z6AHAg8A7wceH65zRBwM3ApsAV4OvA/4EHBBXZ9jgOuBrwJH1f7eEBGvHOniJUnqN6Zj4WbmYmAxQERc3cQmfwhMAd6emY8DD0REL3BBRFyW1TiEHwCWZeYna9t8MiJOrLWfMdLHIEkStP9g8scAd9TCs9/NwF8Avwk8VOvz2QHb3Qyc12iHEXE2cDbAzJkzWblyJVBN7zRlyhTWrVsHwNSpU+np6WHVqlUATJo0ib6+PtauXcuOHTsA6O3tZdu2bVyx5GUjcKiSpGfjw7+3jvXr1wPQ1dVFV1cXa9asAWDy5Mn09vayevVqdu/eDUBfXx8bNmxg+/btAPT09LBr166mf6/dA3QG8JMBbVvq1j1U+7ulQZ+GkxVm5pXAlVANJn/00UfvsX645cMPP3yP5VmzZg15AJKksTF9+nSmT5++R9vAf8OPPPLIPZbnzJnDnDlzin5vIjyFO3C6mGjQ3qhP504zI0kade0eoJvZ+0zysNrfLcP0GXhWKknSiGn3AL0bOD4iDqhrWwhsBH5c12fhgO0WAneNenWSpI411u+BHhgRR0XEUbXfnl1bnl1b/+mIuK1uk/8N/BK4OiJeFhGnAhcB/U/gAlwBnBQRH4mIl0bER4ATgc+M2YFJkjrOWJ+BzgdW1T6TgYtr3z9RWz8TeGF/58z8OdXZZDewHPhr4FLgsro+dwGnA28H/g04EzgtM+8Z5WORJHWwsX4P9F/51UNAjdaf1aBtNXDCMPu9EbjxWZYnSVLT2v0eqCRJbckAlSSpgAEqSVIBA1SSpAIGqCRJBQxQSZIKGKCSJBUwQCVJKmCASpJUwACVJKmAASpJUgEDVJKkAgaoJEkFDFBJkgoYoJIkFTBAJUkqYIBKklTAAJUkqYABKklSAQNUkqQCBqgkSQUMUEmSChigkiQVMEAlSSpggEqSVMAAlSSpgAEqSVIBA1SSpAIGqCRJBQxQSZIKGKCSJBUwQCVJKmCASpJUwACVJKmAASpJUgEDVJKkAgaoJEkFDFBJkgoYoJIkFTBAJUkqYIBKklTAAJUkqYABKklSAQNUkqQCLQVoRLw1Il5bt/znEfGTiLg5ImaOfHmSJLWnVs9AP97/JSKOBv4H8FfAc4FLm9lBRLwnIh6KiJ0RsSIijh+i79URkQ0+O+r6LBikz0tbPDZJkpq2X4v9fwNYW/v+JuD/ZOaiiLgFuHm4jSPiNOAK4D3Ad2p/b4qI38rMDQ02eT9w0YC2O4HbG/Q9AthWt/yz4eqRJKlUq2egO4GDat9fAyypff95XftQLgCuzsyrMvMHmXk+sAk4t1HnzPx5Zm7u/wAvBHqAqxp0/2l938x8qoXjkiSpJa0G6B3ApRHxZ8B8YHGt/SXA/xtqw4jYH5gH3DJg1S3AsU3+/ruB72fmXQ3WLY+ITRFxW0Sc2OT+JEkq0uol3POALwBvAc7JzI219tcx/CXc5wOTgC0D2rcAJw/3wxExFfh9qvuu9frPYO8D9gf+CLgtIhZk5l6XeiPibOBsgJkzZ7Jy5UoAuru7mTJlCuvWrQNg6tSp9PT0sGrVKgAmTZpEX18fa9euZceO6hZsb28v27ZtAw4drnxJ0ijbunUr69evB6Crq4uuri7WrFkDwOTJk+nt7WX16tXs3r0bgL6+PjZs2MD27dsB6OnpYdeuXU3/XmTmCB/CID8U0Q08DJyQmXfUtX8MOCMzh3zoJyLeS/WgUndmbhum72Lgycx8w1D95s6dm0uXLm32EAb1p18yQCVpvC16+/YR2c+0adNWZOb84fq1/B5oRBwQEW+JiA9HxCG1thdGxLRhNn0EeAqYMaD9MPY+K23k3cA/DReeNfcAL26inyRJRVp9D/RFwL8DXwQ+CfSH5rnAoqG2zcxdwApg4YBVC4FG9zTrf/eVQB+NHx5q5CiqS7uSJI2KVu+BfobqoZ9zgUfr2r8B/EMT218GfDki7qV6HeUcoJsqkImIawAy88wB270b+BHw7YE7jIgPAD8Gvk91D/RtwBuBNzd5TJIktazVAD0W+J3MfCoi6ts3UAXhkDLz+oiYDnwUmAk8AJySmetrXWYP3CYiDgJOBz6RjW/Y7g9cAswCHqcK0tdn5uIGfSVJGhGtBihUow4NNJvqXdBhZebngc8Psm5Bg7bHgAOH2N8ihrl8LEnSSGv1IaJbqAZD6JcRcTBwMfAvI1aVJEltrtUz0AuAZRGxFjgAuB54EdVTtG8d4dokSWpbLQVoZm6MiKOAM4Cjqc5grwS+mpmPj0J9kiS1pZbvgdaC8u9rH0mSOtKwARoRpwLfzMzdte+Dysx/HrHKJElqY82cgd5INXrQT2vfB5NUY91KkrTPGzZAM/M5jb5LktTJWh3K74SI2Ct0I2JSRJwwcmVJktTeWj2jXMavxr+td0htnSRJHaHVAA2qe50DTQd2PPtyJEmaGJp6jSUivlH7msBXIuKJutWTgJcxzIwqkiTtS5p9D3Rr7W8A26kGbe+3C/gOzU81JknShNdUgGbmOwAi4sfAJZnp5VpJUkdrdSi/i0erEEmSJpJmRiL6N+DVmbk9IlbT+CEiADLzt0eyOEmS2lUzZ6D/BPQ/NDTUSESSJHWMZkYiurjRd0mSOplD80mSVKCZe6BD3ves5z1QSVKnaHY2FkmSVKele6CSJKniPVBJkgr4HqgkSQV8D1SSpAK+BypJUoGWxsLtFxEvBHpriz/IzAdHriRJktpfSwEaEdOBvwPeADz9q+b4FvDOzNw66MaSJO1DWn0K92+BFwHHAwfUPicAc3A+UElSB2n1Eu5/BV6TmXfXtd0ZEf8dWDJyZUmS1N5aPQP9GdBoMu1fAl6+lSR1jFYD9BPAZyJiVn9D7fultXWSJHWEksHk5wA/joiHa8uzgJ3AYVT3SCVJ2uc5mLwkSQUcTF6SpAIOJi9JUoGWAjQi9o+IiyPihxGxMyKeqv+MVpGSJLWbVs9A/wJ4O9VTt08DHwL+muoVlveMbGmSJLWvVgP0rcA5mfk3wFPA1zPzfcDHgIUjXZwkSe2q1QD9NWBN7ft/AofUvv9f4LUjVZQkSe2u1QDdAHTXvq+jGtoP4Bjg8ZEqSpKkdtdqgH4NeE3t+xXAxRHxEHA1DqIgSeogLQ0mn5kfqft+Y0T8BDgW+GFmfmuki5MkqV0VTajdLzO/C3x3hGqRJGnCaHkghYg4OiKuiYjltc+XI+Lo0ShOkqR21epACn8I3AfMBBbXPr8G3BsRbxv58iRJak+tXsL9JPBnmfmp+saI+Ajwl8BXRqowSZLaWauXcLuAf2zQfgPVdGbDioj3RMRDtaEAV0TE8UP0XRAR2eDz0gH93hwRayLiidrfN7V0VJIktajVAF0GLGjQvgD49nAbR8RpVK+/fAqYC9wF3BQRs4fZ9Aiqy8b9nx/V7fMY4Hrgq8BRtb83RMQrh6tHkqRSzUyofWrd4k3ApyNiPr96+vZ3gFOBjzfxexcAV2fmVbXl8yPid4FzgY8Mvhk/zcxHBln3AWBZZn6ytvzJiDix1n5GEzVJktSy0gm1z6596n0W+PxgO4mI/YF5wCUDVt1C9S7pUJZHxPOohhH8y8xcVrfumNpv17sZOG+QOp6pfebMmaxcuRKA7u5upkyZwrp16wCYOnUqPT09rFq1CoBJkybR19fH2rVr2bFjBwC9vb1s27YNOHSY8iVJo23r1q2sX78egK6uLrq6ulizphp9dvLkyfT29rJ69Wp2794NQF9fHxs2bGD79u0A9PT0sGvXrqZ/r5kJtUdqztDnA5OALQPatwAnD7LNJqqz0/uA/YE/Am6LiAWZeXutz4xB9jmj0Q4z80rgSoC5c+fm0Ufv+QbOcMuHH374HsuzZs0apHRJ0liaPn0606dP36Nt4L/hRx555B7Lc+bMYc6cOUW/96wGUiiUA5ajQVvVMXMtsLau6e6I+E3gQuD2+q7N7lOSpJFQMpDC6yPi9oh4JCJ+FhHfjohTmtj0Eaop0AaeGR7G3meQQ7kHeHHd8uYR2KckSS1pdSCFd1ENKP8g8GHgIuAh4GsR8c6hts3MXcAK9p43dCHV07jNOorq0m6/u0dgn5IktaTVS7gfBi7IzM/Vtf1dRKygCtO/H2b7y4AvR8S9wJ3AOVTTo30RICKuAcjMM2vLHwB+DHyf6h7o24A3Am+u2+cVwO21wRy+BrwJOBE4rsVjkySpaa0G6GyqybMHuom9n67dS2ZeHxHTgY9Svc/5AHBKZq6v23+9/Wv7nUU13+j3gddn5uK6fd4VEadTjYR0MdXZ8WmZeU8rByZJUitaDdANVJdH1w1ofy2wfu/ue8vMzzPI6y6ZuWDA8iJgURP7vJHGr9tIkjQqWg3QS4DP1mZfuYvqSdfjqF4vOX+Ea5MkqW21OqH230TET4EPUo0+BPAD4K2Z+fWRLk6SpHbVdIBGxH5Ul2pvz8yvjV5JkiS1v6ZfY8nMJ4F/Bg4avXIkSZoYWh1I4XvAi0ajEEmSJpJWA/TjwKUR8caIeEFETKv/jEJ9kiS1pVafwv2X2t9/Zs+xZvvHnp00EkVJktTuWg3QE0elCkmSJpimAjQipgD/i2oYvecCS4D3DTHJtSRJ+7Rm74FeDJxFdQn3WqrRiL4wSjVJktT2mr2Eeyrwx5l5HUBEfBW4MyImZeZTo1adJEltqtkz0BcAd/QvZOa9wJNUM6lIktRxmg3QScCuAW1P0vpDSJIk7ROaDcAAvhIRT9S1HQBcFRG/7G/IzDeMZHGSJLWrZgP0Sw3avjKShUiSNJE0FaCZ+Y7RLkSSpImk1aH8JEkSBqgkSUUMUEmSChigkiQVMEAlSSpggEqSVMAAlSSpgAEqSVIBA1SSpAIGqCRJBQxQSZIKGKCSJBUwQCVJKmCASpJUwACVJKmAASpJUgEDVJKkAgaoJEkFDFBJkgoYoJIkFTBAJUkqYIBKklTAAJUkqYABKklSAQNUkqQCBqgkSQUMUEmSChigkiQVMEAlSSow5gEaEe+JiIciYmdErIiI44foe2pE3BIRP4uIxyLinoh4w4A+Z0VENvgcMPpHI0nqVGMaoBFxGnAF8ClgLnAXcFNEzB5kk1cDS4HX1/ovBr7WIHR/Ccys/2TmzpE/AkmSKvuN8e9dAFydmVfVls+PiN8FzgU+MrBzZr5/QNPFEfF64I3AHXt2zc2jUbAkSY2M2RloROwPzANuGbDqFuDYFnZ1ELB9QNvkiFgfET+JiG9FxNxnUaokScMayzPQ5wOTgC0D2rcAJzezg4h4L/DrwJfrmtcC7wS+RxWu7wfujIi+zPxRg32cDZwNMHPmTFauXAlAd3c3U6ZMYd26dQBMnTqVnp4eVq1aBcCkSZPo6+tj7dq17NixA4De3l62bdsGHNpM+ZKkUbR161bWr18PQFdXF11dXaxZswaAyZMn09vby+rVq9m9ezcAfX19bNiwge3bq3Oynp4edu3a1fTvRWaO8CEM8kMR3cDDwAmZeUdd+8eAMzLzpcNs/2aq4Dw9M78xRL9JwP3Assx831D7nDt3bi5durSFo2jsT79kgErSeFv09oEXJ8tMmzZtRWbOH67fWD5E9AjwFDBjQPth7H1Wuoe68DxzqPAEyMyngOXAi8tLlSRpaGMWoJm5C1gBLBywaiHV07gNRcRbga8AZ2XmjcP9TkQE8NvApvJqJUka2lg/hXsZ8OWIuBe4EzgH6Aa+CBAR1wBk5pm15dOpzjwvBG6PiP6z112Zua3W52PAd4EfAQcD76MK0HPH6JgkSR1oTAM0M6+PiOnAR6ne13wAOCUz19e6DHwf9ByqGj9T+/T7NrCg9v0Q4EqqS8M/B1ZR3We9dzSOQZIkGPszUDLz88DnB1m3YKjlQbb5E+BPRqI2SZKa5Vi4kiQVMEAlSSpggEqSVMAAlSSpgAEqSVIBA1SSpAIGqCRJBQxQSZIKGKCSJBUwQCVJKmCASpJUwACVJKmAASpJUgEDVJKkAgaoJEkFDFBJkgoYoJIkFTBAJUkqYIBKklTAAJUkqYABKklSAQNUkqQCBqgkSQUMUEmSChigkiQVMEAlSSpggEqSVMAAlSSpgAEqSVIBA1SSpAIGqCRJBQxQSZIKGKCSJBUwQCVJKmCASpJUwACVJKmAASpJUgEDVJKkAgaoJEkFDFBJkgoYoJIkFTBAJUkqYIBKklTAAJUkqYABKklSAQNUkqQCYx6gEfGeiHgoInZGxIqIOH6Y/q+u9dsZEf8REec8231KkvRsjWmARsRpwBXAp4C5wF3ATRExe5D+c4DFtX5zgU8Dn42IN5fuU5KkkTDWZ6AXAFdn5lWZ+YPMPB/YBJw7SP9zgI2ZeX6t/1XAl4ALn8U+JUl61sYsQCNif2AecMuAVbcAxw6y2TEN+t8MzI+I5xbuU5KkZ22/Mfyt5wOTgC0D2rcAJw+yzQxgSYP++9X2F63uMyLOBs6uLf7ntGnT1jZTvNQBng88Mt5FSKX+9k9GbFe/0UynsQzQfjlgORq0Dde/vz2G6NNwn5l5JXDl8GVKnSUilmfm/PGuQ5ooxjJAHwGeojqrrHcYe59B9ts8SP8nga1UQdnqPiVJetbG7B5oZu4CVgALB6xaSPXkbCN3s/el2IXA8szcXbhPSZKetbG+hHsZ8OWIuBe4k+op227giwARcQ1AZp5Z6/9F4LyI+AzwN8CrgLOAM5rdp6SmeWtDasGYBmhmXh8R04GPAjOBB4BTMnN9rcvsAf0fiohTgMupXkvZCLwvM/+phX1KakLt+QBJTYrMoZ7fkSRJjTgWriRJBQxQSZIKGKCSJBUwQCVJKmCAStpDRMTwvSQZoJIAiIiDAbLu0XzDVBqcr7FIAiAi/gH4N+AeYE1mPtqgz0GZ+diYFye1IQNUEhHxFuAfgR8CvwBWAd+lGirzh5m5szZ94E3AhZm5atyKldqEASqJiPgi8DyqITBfC5xCNb3ZT4D7qMal7gYuzcwDxqtOqZ0YoFKHi4hJwIeB52fmBXXtxwOnASdQPS/xQuD6zDxrPOqU2o0BKomI+DXg4Mz8UUQ8NzN31617HnAm1YQOL8/MFeNVp9ROxmNCbUltJjO3UJtDtz88I2I/4OnMfCIingZ+aXhKv+JrLJKIiKkD2zLzycx8uvYqy3Tg0rGvTGpfXsKVOlhEvIhqft0Tgd+keljom8DSzPzpgL6R/oMhPcMAlTpYRHwbOAi4g+oS7knAccBW4Aqqp26fiojnZObT41ep1H4MUKlDRcSJVO9+vrh+0ISImAW8Czgb+DpwfmY+NT5VSu3Le6BS55oHPAg8AdXrLLUzzYcz82KqV1v+EHj1ONYotS0DVOpci6ne7TwVIDOfqntoiMz8CvCvGKBSQwao1LnWAtcAfxURV0bEKRExrf9BoYiYARwNrB7PIqV25T1QqYPVBkk4H3gDcADV0H3bgZ8DrwQmZ+bR41eh1L4MUElExEuB3wOOAqYBM4AlwBcy86HxrE1qVwao1KFqY+A+p37Yvlp7V2b+bJzKkiYM74FKHSYi5sEzDw31D9u3f0Q8t9ZueEpNMEClDhIRLwbui4gHIuKyiJgLkJm7MnN3VPaPiFfU5v+UNAgDVOosZ1C9+3kr8DvAtyLiuxHxpxHxgtoTuF1Uk2kfNo51Sm3Pe6BSB4mIrwKPAJ+mGiB+PnA88Aqqh4dWAQHMycwjxqtOaSJwOjOpQ9SmJ/sX4DcyczOwGfh+RHwTOJxqZKITgLcA7x63QqUJwjNQqUMNnDi71nYqcCNwYGb+cnwqkyYG74FKHSIi9vjvvX7i7P7h+4BjgdsNT2l4XsKVOkd3bf7PAJ4G1mbm5sx8Eqr5PoHvANePY43ShOElXKkDRMS5wDuBPmAHsI5q2L67ga9n5tpxLE+akLyEK+3jImI68CmquT1nAscAX6I6C3078NmI+K1a30njVac00XgGKu3jIuJ84G2Z+coG646jeqVlFvCKzHxkrOuTJirPQKV93y7goIh4GVQzsPSPMpSZ36GaNHsn8NrxK1GaeAxQad93I9Xl2g9ExEGZ+URm7up/KjczNwCPAr8+nkVKE40BKu3Dak/WbgM+CiwENkbE3/UPKB8RsyPibcCRwD+OX6XSxOM9UKkDRMQhwGyq9zzfBLyqtmoz1f9IX5OZHx+f6qSJyQCV9lERcRjwR8AHqca/fZzqUu0dwD3Ac4EXAjcDP0r/MZBaYoBK+6iIuBo4Avgm1WXcaVSXal8C/BT4aGbeM24FShOcASrtg2r3Ph8DTsnM2+vaZlNNY/bHQA/w1sxcOW6FShOYDxFJ+6bfAh6ieoUFgKysz8zrgf9GdTn398epPmnCM0ClfdN/UF2mvTwiXtxgIPknqEYjet14FCftCwxQaR+UmY8D/xOYDFwDnBkRL4iI/wIQEVOAVwMPjF+V0sTmPVBpH1YbfejPgDdQDSJ/N/Az4GRgE/CuzFw9fhVKE5cBKnWA2istrwfeSDVs3wPADZn57+NamDSBGaBSh4mI52Tm0+NdhzTRGaCSJBXwISJJkgoYoJIkFTBAJUkqYIBKklTAAJUkqYABKklSgf8PQQ7VfTKmbt4AAAAASUVORK5CYII=\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 |
--------------------------------------------------------------------------------