Skip to content

Instantly share code, notes, and snippets.

@caryan
Created November 20, 2019 04:50
Show Gist options
  • Save caryan/ceec9b1dded5466c9f4ac8ec347f61f8 to your computer and use it in GitHub Desktop.
Save caryan/ceec9b1dded5466c9f4ac8ec347f61f8 to your computer and use it in GitHub Desktop.
fully connected Ising QAOA mapped to a line with CZ and iSWAP
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Introduction\n",
"\n",
"We were looking for situtations where having both CZ and iSWAP gates give an advantage. Marcus suggested that looking at QAOA instances where the problem graph did not fit the native topology would force many SWAP gates. Then we could take advantage of the equivalence between a CZ + iSWAP and a full SWAP to save one gate per SWAP. \n",
"\n",
"After some messing around we happened on the surprising result that with CZ + iSWAP QAOA with Ising cost functions on a fully connected $n$ qubit graph can be mapped to a $n$ qubit QPU with line connectivity with no additional 2Q gates. This notebook uses QUILC to demonstrate that this holds for up to 9 qubits."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import random \n",
"from collections import Counter\n",
"\n",
"import networkx as nx\n",
"import matplotlib.pyplot as plt\n",
"%matplotlib inline\n",
"import pandas as pd\n",
"\n",
"from pyquil.api import QVMCompiler\n",
"from pyquil.device import Device\n",
"from pyquil.device._isa import isa_from_graph\n",
"\n",
"from pyquil.quil import Program\n",
"from pyquil.gates import *"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"def create_graph(num_qubits, connectivity):\n",
" g = nx.Graph()\n",
" g.add_nodes_from(range(num_qubits))\n",
" if connectivity == \"all_to_all\":\n",
" for i in range(num_qubits):\n",
" for j in range(i+1, num_qubits):\n",
" g.add_edge(i,j)\n",
" elif connectivity == \"line\":\n",
" for i in range(num_qubits):\n",
" g.add_edge(i, i+1)\n",
" else:\n",
" raise ValueError\n",
" return g\n",
"NUM_QUBITS = 5\n",
"qpu_topology = create_graph(NUM_QUBITS, \"all_to_all\")\n",
"nx.draw(qpu_topology)"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"# use the graph topology to mock out an ISA dictionary\n",
"# twoq_types = [\"CZ\"]\n",
"twoq_types = [\"CZ\", \"ISWAP\"]\n",
"raw_dict = {\"isa\": isa_from_graph(qpu_topology, oneq_type=\"Xhalves\", twoq_type=twoq_types).to_dict()}\n",
"\n",
"# now construct a fake device to give to QUILC\n",
"device = Device(\"dummy\", raw_dict)\n",
"\n",
"compiler = QVMCompiler(device=device, endpoint=\"tcp://localhost:5555\")"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"def ising_program(num_qubits):\n",
" \"\"\"\n",
" Return a PyQuil program with random ising terms (CPHASE) on all to all connectivity.\n",
" \"\"\"\n",
" p = Program('PRAGMA INITIAL_REWIRING \"NAIVE\"') # keep qubits I ask for\n",
"\n",
" # all-to-all problem connectivity \n",
" edges = [(i,j) for i in range(num_qubits) for j in range(i+1, num_qubits)]\n",
" for edge in edges:\n",
" p.inst(CPHASE(random.random(), *edge))\n",
" p.measure_all() # not necessary; nice for seeing relabelling\n",
" \n",
" return p "
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"PRAGMA INITIAL_REWIRING \"NAIVE\"\n",
"CPHASE(0.1909210645887659) 0 1\n",
"CPHASE(0.8805896368481334) 0 2\n",
"CPHASE(0.1237664829421179) 0 3\n",
"CPHASE(0.4309580075168765) 0 4\n",
"CPHASE(0.8273814628723947) 1 2\n",
"CPHASE(0.762557411672792) 1 3\n",
"CPHASE(0.12574313722211305) 1 4\n",
"CPHASE(0.5682618245962114) 2 3\n",
"CPHASE(0.28573081286535484) 2 4\n",
"CPHASE(0.07597992584819635) 3 4\n",
"DECLARE ro BIT[5]\n",
"MEASURE 0 ro[0]\n",
"MEASURE 1 ro[1]\n",
"MEASURE 2 ro[2]\n",
"MEASURE 3 ro[3]\n",
"MEASURE 4 ro[4]\n",
"\n",
"-------------------------- \n",
"\n",
"compiled CZ count: 16\n",
"compiled XY count: 4\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"/home/cryan/miniconda3/envs/willow/lib/python3.6/site-packages/rpcq/_client.py:177: UserWarning: SIMPLE-WARNING: Chip specification contained fidelity 1.0d0 > 0.99999d0. Truncating to 0.99999d0.\n",
" warn(f\"{warning.kind}: {warning.body}\")\n"
]
}
],
"source": [
"# sample program\n",
"p = ising_program(NUM_QUBITS)\n",
"print(p)\n",
"print(\"-------------------------- \\n\")\n",
"compiled = compiler.quil_to_native_quil(p, protoquil=True)\n",
"# print(compiled)\n",
"\n",
"CZ_count = [isinstance(i, Gate) and i.name == \"CZ\" for i in compiled.instructions].count(True)\n",
"iSWAP_count = [isinstance(i, Gate) and i.name == \"ISWAP\" for i in compiled.instructions].count(True)\n",
"print(f\"compiled CZ count: {CZ_count}\")\n",
"print(f\"compiled XY count: {iSWAP_count}\")"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"In 10 trials:\n",
"40%: 20 2Q gates (16 CZ; 4 iSWAP)\n",
"50%: 20 2Q gates (14 CZ; 6 iSWAP)\n",
"10%: 20 2Q gates (12 CZ; 8 iSWAP)\n"
]
}
],
"source": [
"gate_counts = Counter()\n",
"total_counts = []\n",
"for ct in range(10):\n",
" p = ising_program(NUM_QUBITS)\n",
" \n",
" compiled = compiler.quil_to_native_quil(p, protoquil=True)\n",
" CZ_count = [isinstance(i, Gate) and i.name == \"CZ\" for i in compiled.instructions].count(True)\n",
" iSWAP_count = [isinstance(i, Gate) and i.name == \"ISWAP\" for i in compiled.instructions].count(True)\n",
" gate_counts.update([(CZ_count,iSWAP_count)])\n",
"\n",
"total_trials = sum(gate_counts.values())\n",
"print(f\"In {total_trials} trials:\")\n",
"for k,v in gate_counts.items():\n",
" print(f\"{100*v/total_trials:.0f}%: {k[0]+k[1]} 2Q gates ({k[0]} CZ; {k[1]} iSWAP)\")"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"# loop over everything\n",
"stats = []\n",
"for num_qubits in range(3, 10):\n",
" for connectivity in (\"all_to_all\", \"line\"):\n",
" # ISA from topology\n",
" qpu_topology = create_graph(num_qubits, connectivity)\n",
" \n",
" for gateset in ([\"CZ\"], [\"CZ\", \"ISWAP\"]):\n",
"\n",
" raw_dict = {\"isa\": isa_from_graph(qpu_topology, oneq_type=\"Xhalves\", twoq_type=gateset).to_dict()}\n",
"\n",
" # now construct a fake device to give to QUILC\n",
" device = Device(\"dummy\", raw_dict)\n",
" compiler = QVMCompiler(device=device, endpoint=\"tcp://localhost:5555\")\n",
"\n",
" gate_counts = []\n",
" gate_depths = []\n",
" for ct in range(10):\n",
" p = ising_program(num_qubits)\n",
" compiled = compiler.quil_to_native_quil(p, protoquil=True)\n",
" gate_count = [isinstance(i, Gate) and i.name in gateset for i in compiled.instructions].count(True)\n",
" gate_counts.append(gate_count)\n",
" gate_depths.append(compiled.native_quil_metadata.multiqubit_gate_depth)\n",
" \n",
" stats.append(dict(\n",
" num_qubits=num_qubits,\n",
" connectivity=connectivity,\n",
" gateset=gateset,\n",
" gate_count=min(gate_counts),\n",
" gate_depth = min(gate_depths)\n",
" ))"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>connectivity</th>\n",
" <th>gate_count</th>\n",
" <th>gate_depth</th>\n",
" <th>gateset</th>\n",
" <th>num_qubits</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>all_to_all</td>\n",
" <td>6</td>\n",
" <td>6</td>\n",
" <td>[CZ]</td>\n",
" <td>3</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>all_to_all</td>\n",
" <td>6</td>\n",
" <td>6</td>\n",
" <td>[CZ, ISWAP]</td>\n",
" <td>3</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>line</td>\n",
" <td>9</td>\n",
" <td>9</td>\n",
" <td>[CZ]</td>\n",
" <td>3</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>line</td>\n",
" <td>8</td>\n",
" <td>8</td>\n",
" <td>[CZ, ISWAP]</td>\n",
" <td>3</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>all_to_all</td>\n",
" <td>12</td>\n",
" <td>10</td>\n",
" <td>[CZ]</td>\n",
" <td>4</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>all_to_all</td>\n",
" <td>12</td>\n",
" <td>10</td>\n",
" <td>[CZ, ISWAP]</td>\n",
" <td>4</td>\n",
" </tr>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>line</td>\n",
" <td>17</td>\n",
" <td>14</td>\n",
" <td>[CZ]</td>\n",
" <td>4</td>\n",
" </tr>\n",
" <tr>\n",
" <th>7</th>\n",
" <td>line</td>\n",
" <td>12</td>\n",
" <td>10</td>\n",
" <td>[CZ, ISWAP]</td>\n",
" <td>4</td>\n",
" </tr>\n",
" <tr>\n",
" <th>8</th>\n",
" <td>all_to_all</td>\n",
" <td>20</td>\n",
" <td>14</td>\n",
" <td>[CZ]</td>\n",
" <td>5</td>\n",
" </tr>\n",
" <tr>\n",
" <th>9</th>\n",
" <td>all_to_all</td>\n",
" <td>20</td>\n",
" <td>14</td>\n",
" <td>[CZ, ISWAP]</td>\n",
" <td>5</td>\n",
" </tr>\n",
" <tr>\n",
" <th>10</th>\n",
" <td>line</td>\n",
" <td>29</td>\n",
" <td>20</td>\n",
" <td>[CZ]</td>\n",
" <td>5</td>\n",
" </tr>\n",
" <tr>\n",
" <th>11</th>\n",
" <td>line</td>\n",
" <td>20</td>\n",
" <td>14</td>\n",
" <td>[CZ, ISWAP]</td>\n",
" <td>5</td>\n",
" </tr>\n",
" <tr>\n",
" <th>12</th>\n",
" <td>all_to_all</td>\n",
" <td>30</td>\n",
" <td>18</td>\n",
" <td>[CZ]</td>\n",
" <td>6</td>\n",
" </tr>\n",
" <tr>\n",
" <th>13</th>\n",
" <td>all_to_all</td>\n",
" <td>30</td>\n",
" <td>18</td>\n",
" <td>[CZ, ISWAP]</td>\n",
" <td>6</td>\n",
" </tr>\n",
" <tr>\n",
" <th>14</th>\n",
" <td>line</td>\n",
" <td>44</td>\n",
" <td>26</td>\n",
" <td>[CZ]</td>\n",
" <td>6</td>\n",
" </tr>\n",
" <tr>\n",
" <th>15</th>\n",
" <td>line</td>\n",
" <td>30</td>\n",
" <td>18</td>\n",
" <td>[CZ, ISWAP]</td>\n",
" <td>6</td>\n",
" </tr>\n",
" <tr>\n",
" <th>16</th>\n",
" <td>all_to_all</td>\n",
" <td>42</td>\n",
" <td>22</td>\n",
" <td>[CZ]</td>\n",
" <td>7</td>\n",
" </tr>\n",
" <tr>\n",
" <th>17</th>\n",
" <td>all_to_all</td>\n",
" <td>42</td>\n",
" <td>22</td>\n",
" <td>[CZ, ISWAP]</td>\n",
" <td>7</td>\n",
" </tr>\n",
" <tr>\n",
" <th>18</th>\n",
" <td>line</td>\n",
" <td>62</td>\n",
" <td>32</td>\n",
" <td>[CZ]</td>\n",
" <td>7</td>\n",
" </tr>\n",
" <tr>\n",
" <th>19</th>\n",
" <td>line</td>\n",
" <td>42</td>\n",
" <td>22</td>\n",
" <td>[CZ, ISWAP]</td>\n",
" <td>7</td>\n",
" </tr>\n",
" <tr>\n",
" <th>20</th>\n",
" <td>all_to_all</td>\n",
" <td>56</td>\n",
" <td>26</td>\n",
" <td>[CZ]</td>\n",
" <td>8</td>\n",
" </tr>\n",
" <tr>\n",
" <th>21</th>\n",
" <td>all_to_all</td>\n",
" <td>56</td>\n",
" <td>26</td>\n",
" <td>[CZ, ISWAP]</td>\n",
" <td>8</td>\n",
" </tr>\n",
" <tr>\n",
" <th>22</th>\n",
" <td>line</td>\n",
" <td>83</td>\n",
" <td>38</td>\n",
" <td>[CZ]</td>\n",
" <td>8</td>\n",
" </tr>\n",
" <tr>\n",
" <th>23</th>\n",
" <td>line</td>\n",
" <td>56</td>\n",
" <td>26</td>\n",
" <td>[CZ, ISWAP]</td>\n",
" <td>8</td>\n",
" </tr>\n",
" <tr>\n",
" <th>24</th>\n",
" <td>all_to_all</td>\n",
" <td>72</td>\n",
" <td>30</td>\n",
" <td>[CZ]</td>\n",
" <td>9</td>\n",
" </tr>\n",
" <tr>\n",
" <th>25</th>\n",
" <td>all_to_all</td>\n",
" <td>72</td>\n",
" <td>30</td>\n",
" <td>[CZ, ISWAP]</td>\n",
" <td>9</td>\n",
" </tr>\n",
" <tr>\n",
" <th>26</th>\n",
" <td>line</td>\n",
" <td>107</td>\n",
" <td>44</td>\n",
" <td>[CZ]</td>\n",
" <td>9</td>\n",
" </tr>\n",
" <tr>\n",
" <th>27</th>\n",
" <td>line</td>\n",
" <td>72</td>\n",
" <td>30</td>\n",
" <td>[CZ, ISWAP]</td>\n",
" <td>9</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" connectivity gate_count gate_depth gateset num_qubits\n",
"0 all_to_all 6 6 [CZ] 3\n",
"1 all_to_all 6 6 [CZ, ISWAP] 3\n",
"2 line 9 9 [CZ] 3\n",
"3 line 8 8 [CZ, ISWAP] 3\n",
"4 all_to_all 12 10 [CZ] 4\n",
"5 all_to_all 12 10 [CZ, ISWAP] 4\n",
"6 line 17 14 [CZ] 4\n",
"7 line 12 10 [CZ, ISWAP] 4\n",
"8 all_to_all 20 14 [CZ] 5\n",
"9 all_to_all 20 14 [CZ, ISWAP] 5\n",
"10 line 29 20 [CZ] 5\n",
"11 line 20 14 [CZ, ISWAP] 5\n",
"12 all_to_all 30 18 [CZ] 6\n",
"13 all_to_all 30 18 [CZ, ISWAP] 6\n",
"14 line 44 26 [CZ] 6\n",
"15 line 30 18 [CZ, ISWAP] 6\n",
"16 all_to_all 42 22 [CZ] 7\n",
"17 all_to_all 42 22 [CZ, ISWAP] 7\n",
"18 line 62 32 [CZ] 7\n",
"19 line 42 22 [CZ, ISWAP] 7\n",
"20 all_to_all 56 26 [CZ] 8\n",
"21 all_to_all 56 26 [CZ, ISWAP] 8\n",
"22 line 83 38 [CZ] 8\n",
"23 line 56 26 [CZ, ISWAP] 8\n",
"24 all_to_all 72 30 [CZ] 9\n",
"25 all_to_all 72 30 [CZ, ISWAP] 9\n",
"26 line 107 44 [CZ] 9\n",
"27 line 72 30 [CZ, ISWAP] 9"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pd.DataFrame(stats)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.9"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment