From 48a5c8dbe49bb64ba54615acc6157a1c68ad7a2e Mon Sep 17 00:00:00 2001 From: Aleks Kissinger Date: Wed, 18 Dec 2024 11:21:58 +0000 Subject: [PATCH] pauli webs and cnot tests --- demos/PauliWebs.ipynb | 9047 ++++++++++++++++++++++++++++++++++++++++- pyzx/pauliweb.py | 86 +- 2 files changed, 8952 insertions(+), 181 deletions(-) diff --git a/demos/PauliWebs.ipynb b/demos/PauliWebs.ipynb index 84236966..75c05e97 100644 --- a/demos/PauliWebs.ipynb +++ b/demos/PauliWebs.ipynb @@ -10,77 +10,8880 @@ "sys.path.insert(0,os.path.expanduser('~/git/pyzx')) # git version\n", "sys.path.insert(0,'/workspaces/pyzx')\n", "import pyzx as zx\n", - "from pyzx.pauliweb import preprocess, compute_pauli_webs" + "from pyzx.pauliweb import PauliWeb, compute_pauli_webs" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "This notebook demonstrates using PyZX's simplifier to construct the reduced ZX diagram of a random Clifford+T circuit, then using PyZX's gflow-finding algorithm to automatically associate each node `n` in the diagram to an integer `order[n]` and a Pauli web (a.k.a. _correlation surface_) `web[n]` with the following properties:\n", + "This notebook demonstrates using PyZX's methods for automatically computing and drawing (bounded) Pauli webs. A Pauli web (a.k.a. _correlation surface_) is a coloring of the edges of ZX-diagram with the following properties for every Z spider `v`:\n", "\n", - "1. the boundary of `web[n]` consists of `n` and inputs\n", - "2. `web[n]` connects to `n` by a single edge, which is the same colour as `n`\n", - "3. for non-Clifford nodes `m, n`, if `m` is in `web[n].vertices()` then `order[m] < order[n]`\n", + "- _all-or-nothing_: either no incident edges or all incident edges of `v` are labelled X or Y\n", + "- _parity_: an even number of incident edges of `v` are labelled Y or Z\n", "\n", - "The values of `web[n]` at non-Clifford nodes and at outputs should be enough data to deterministically implement the diagram via lattice surgery and either measure at the end or compute the updated Pauli frame." + "All X spiders satisfy analogous conditions, swapping the role of X and Z. A _bounded Pauli web_ is a Pauli web with a chosen set of spiders, called the _boundary_ where the parity condition is allowed to be violated.\n", + "\n", + "We say a spider `anti-commutes` with a Pauli web if it is touching an edge of a different colour.\n", + "\n", + "The function `compute_pauli_webs` automitically associates each non-input vertex `v` in the diagram to an integer `order[v]` giving a time-ordering, and one or two bounded Pauli webs, with the following properties:\n", + "1. the boundary of the web consists of only `v` itself and inputs\n", + "2. Z spiders have a web `zweb[v]` with a Z-colored edge incident to `v`\n", + "3. X spiders have a web `xweb[v]` with a X-colored edge incident to `v`\n", + "4. output vertices have two webs `zweb[v]` and `xweb[v]` corresponding to both colors at `v`\n", + "5. for non-Pauli spiders `v, w`, if `v` anti-commutes with the Pauli web of `w` then `order[v] < order[w]`\n", + "\n", + "Under the hood, this is using PyZX's gflow-finding algorithm to compute a focussed gflow and translate this data into Pauli webs." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Here's a simple example of a single CNOT gate\n", + "\n", + "c = zx.qasm(\"\"\"\n", + "qreg q[2];\n", + "cx q[0], q[1];\n", + "\"\"\")\n", + "g = c.to_graph()\n", + "order, zwebs, xwebs = compute_pauli_webs(g)\n", + "zx.draw(g, labels=True)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n", + "" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n", + "" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n", + "" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# There are 4 interesting Pauli webs corresponding to the two outputs\n", + "zx.draw(g, labels=True, pauli_web=xwebs[4])\n", + "zx.draw(g, labels=True, pauli_web=xwebs[5])\n", + "zx.draw(g, labels=True, pauli_web=zwebs[4])\n", + "zx.draw(g, labels=True, pauli_web=zwebs[5])" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n", + "" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# The CNOT example also has 2 more bounded Pauli webs, with boundaries on the two interior spiders.\n", + "# Since we aren't injecting magic states at these locations, we don't need these Pauli webs.\n", + "zx.draw(g, labels=True, pauli_web=zwebs[3])\n", + "zx.draw(g, labels=True, pauli_web=xwebs[2])" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Here's an example with three CNOT gates\n", + "\n", + "c = zx.qasm(\"\"\"\n", + "qreg q[3];\n", + "cx q[0], q[1];\n", + "cx q[1], q[2];\n", + "cx q[2], q[0];\n", + "\"\"\")\n", + "g = c.to_graph()\n", + "\n", + "order, zwebs, xwebs = compute_pauli_webs(g)\n", + "\n", + "zx.draw(g, labels=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n", + "" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n", + "" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n", + "" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n", + "" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n", + "" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "zx.draw(g, labels=True, pauli_web=xwebs[9])\n", + "zx.draw(g, labels=True, pauli_web=xwebs[10])\n", + "zx.draw(g, labels=True, pauli_web=xwebs[11])\n", + "zx.draw(g, labels=True, pauli_web=zwebs[9])\n", + "zx.draw(g, labels=True, pauli_web=zwebs[10])\n", + "zx.draw(g, labels=True, pauli_web=zwebs[11])" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n", + "" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Here's an example with more CNOT gates\n", + "\n", + "c = zx.qasm(\"\"\"\n", + "qreg q[3];\n", + "cx q[0], q[1];\n", + "cx q[1], q[2];\n", + "cx q[0], q[2];\n", + "cx q[2], q[1];\n", + "cx q[0], q[1];\n", + "cx q[2], q[0];\n", + "\"\"\")\n", + "g = c.to_graph()\n", + "\n", + "zx.draw(g)\n", + "\n", + "# Adjacent spiders of the same color need to be fused for the Pauli web computation to work.\n", + "# We can accomplish this with spider_simp:\n", + "zx.spider_simp(g, quiet=True)\n", + "\n", + "# This is not a fundamental problem, it just requires more case distinctions for compute_pauli_webs\n", + "# to handle unfused spiders.\n", + "\n", + "order, zwebs, xwebs = compute_pauli_webs(g)\n", + "\n", + "zx.draw(g, labels=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n", + "" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n", + "" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n", + "" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n", + "" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n", + "" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "zx.draw(g, labels=True, pauli_web=xwebs[15])\n", + "zx.draw(g, labels=True, pauli_web=xwebs[16])\n", + "zx.draw(g, labels=True, pauli_web=xwebs[17])\n", + "zx.draw(g, labels=True, pauli_web=zwebs[15])\n", + "zx.draw(g, labels=True, pauli_web=zwebs[16])\n", + "zx.draw(g, labels=True, pauli_web=zwebs[17])" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Generate a random CNOT, H, T circuit\n", + "random.seed(1330)\n", + "c = zx.generate.CNOT_HAD_PHASE_circuit(qubits=3, depth=40)\n", + "# for g in c.gates: print(g)\n", + "zx.draw(c)" ] }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 10, "metadata": {}, "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CNOT(0,1)\n", - "CNOT(1,0)\n", - "CNOT(2,0)\n", - "HAD(2)\n", - "CNOT(2,1)\n", - "HAD(2)\n", - "CNOT(1,0)\n", - "CNOT(0,2)\n", - "CNOT(1,2)\n", - "T(0)\n", - "T(1)\n", - "HAD(2)\n", - "T(2)\n", - "HAD(1)\n", - "HAD(0)\n", - "CNOT(0,2)\n", - "CNOT(0,2)\n", - "CNOT(1,0)\n", - "T(2)\n", - "HAD(2)\n", - "HAD(1)\n", - "CNOT(1,0)\n", - "CNOT(0,1)\n", - "CNOT(2,1)\n", - "T(0)\n", - "CNOT(2,0)\n", - "T(0)\n", - "T(0)\n", - "T(0)\n", - "CNOT(2,0)\n", - "CNOT(0,2)\n", - "T(2)\n", - "T(1)\n", - "T(1)\n", - "T(0)\n", - "HAD(1)\n", - "T(1)\n", - "CNOT(1,0)\n", - "CNOT(1,2)\n", - "CNOT(1,0)\n" - ] - }, { "data": { "text/html": [ - "
\n", + "
\n", "" ], "text/plain": [ @@ -456,37 +9259,11 @@ "output_type": "display_data" } ], - "source": [ - "# Generate a random CNOT, H, T circuit\n", - "random.seed(1330)\n", - "c = zx.generate.CNOT_HAD_PHASE_circuit(qubits=3, depth=40)\n", - "for g in c.gates: print(g)\n", - "zx.draw(c)" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "ename": "KeyError", - "evalue": "58", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[3], line 10\u001b[0m\n\u001b[1;32m 6\u001b[0m g\u001b[38;5;241m.\u001b[39mnormalize()\n\u001b[1;32m 8\u001b[0m \u001b[38;5;66;03m# Compute the time-ordering on nodes (which is only important for the non-Clifford nodes) and compute the Pauli\u001b[39;00m\n\u001b[1;32m 9\u001b[0m \u001b[38;5;66;03m# webs for every node.\u001b[39;00m\n\u001b[0;32m---> 10\u001b[0m order, zwebs, xwebs \u001b[38;5;241m=\u001b[39m \u001b[43mcompute_pauli_webs\u001b[49m\u001b[43m(\u001b[49m\u001b[43mg\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 12\u001b[0m \u001b[38;5;66;03m# Draw the simplified ZX diagram. Note blue edges correspond to edges with Hadamard gates\u001b[39;00m\n\u001b[1;32m 13\u001b[0m zx\u001b[38;5;241m.\u001b[39mdraw(g, labels\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mTrue\u001b[39;00m)\n", - "File \u001b[0;32m~/git/pyzx/pyzx/pauliweb.py:191\u001b[0m, in \u001b[0;36mcompute_pauli_webs\u001b[0;34m(g)\u001b[0m\n\u001b[1;32m 188\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 189\u001b[0m ref \u001b[38;5;241m=\u001b[39m v\n\u001b[0;32m--> 191\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[43mg1\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mtype\u001b[49m\u001b[43m(\u001b[49m\u001b[43mv\u001b[49m\u001b[43m)\u001b[49m \u001b[38;5;241m==\u001b[39m VertexType\u001b[38;5;241m.\u001b[39mZ: zwebs[ref] \u001b[38;5;241m=\u001b[39m pw\n\u001b[1;32m 192\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m g1\u001b[38;5;241m.\u001b[39mtype(v) \u001b[38;5;241m==\u001b[39m VertexType\u001b[38;5;241m.\u001b[39mX: xwebs[ref] \u001b[38;5;241m=\u001b[39m pw\n\u001b[1;32m 195\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m (order, zwebs, xwebs)\n", - "File \u001b[0;32m~/git/pyzx/pyzx/graph/graph_s.py:293\u001b[0m, in \u001b[0;36mGraphS.type\u001b[0;34m(self, vertex)\u001b[0m\n\u001b[1;32m 292\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mtype\u001b[39m(\u001b[38;5;28mself\u001b[39m, vertex):\n\u001b[0;32m--> 293\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mty\u001b[49m\u001b[43m[\u001b[49m\u001b[43mvertex\u001b[49m\u001b[43m]\u001b[49m\n", - "\u001b[0;31mKeyError\u001b[0m: 58" - ] - } - ], "source": [ "# Convert to a ZX diagram and call the full_reduce procedure on it (PyZX's main ZX diagram optimisation pass)\n", "g = c.to_graph()\n", "zx.full_reduce(g)\n", + "zx.to_rg(g)\n", "\n", "# Normalise compacts the circuit visually and ensures every input/output is connected to a Z spider\n", "g.normalize()\n", @@ -501,13 +9278,63 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{(16, 5): 'Y',\n", + " (5, 16): 'Y',\n", + " (5, 2): 'X',\n", + " (2, 5): 'Z',\n", + " (16, 43): 'Z',\n", + " (43, 16): 'Z',\n", + " (16, 58): 'Z',\n", + " (58, 16): 'X',\n", + " (16, 14): 'Y',\n", + " (14, 16): 'Y',\n", + " (3, 1): 'Z',\n", + " (1, 3): 'Z',\n", + " (3, 43): 'Z',\n", + " (43, 3): 'Z',\n", + " (3, 5): 'Y',\n", + " (5, 3): 'Y',\n", + " (3, 58): 'Z',\n", + " (58, 3): 'X',\n", + " (3, 54): 'Z',\n", + " (54, 3): 'Z',\n", + " (3, 14): 'Y',\n", + " (14, 3): 'Y',\n", + " (5, 43): 'X',\n", + " (43, 5): 'Z',\n", + " (5, 58): 'X',\n", + " (58, 5): 'X',\n", + " (5, 54): 'X',\n", + " (54, 5): 'Z',\n", + " (14, 58): 'X',\n", + " (58, 14): 'X'}" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pw = zwebs[43]\n", + "pw.half_edges()" + ] + }, + { + "cell_type": "code", + "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/html": [ - "
\n", + "
\n", "" ], @@ -886,7 +9713,7 @@ "source": [ "# Once the Pauli webs have been computed, a specific web can be highlighted by `zx.draw` by passing it in as\n", "# an optional argument. Note that webs change color when they cross Hadamard edges.\n", - "zx.draw(g, labels=True, pauli_web=webs[67])" + "zx.draw(g, labels=True, pauli_web=zwebs[43])" ] }, { @@ -900,13 +9727,13 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/html": [ - "
\n", + "
\n", "" @@ -1281,17 +10108,10 @@ "metadata": {}, "output_type": "display_data" }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[] []\n" - ] - }, { "data": { "text/html": [ - "
\n", + "
\n", "" ], @@ -1679,7 +10499,7 @@ "order, zwebs, xwebs = compute_pauli_webs(g)\n", "\n", "# highlight the web associated to the T spider\n", - "zx.draw(g, labels=True, pauli_web=webs[3])" + "zx.draw(g, labels=True, pauli_web=None)" ] }, { @@ -1691,13 +10511,13 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/html": [ - "
\n", + "
\n", "" @@ -2072,17 +10892,10 @@ "metadata": {}, "output_type": "display_data" }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[] []\n" - ] - }, { "data": { "text/html": [ - "
\n", + "
\n", "" ], @@ -2482,7 +11295,7 @@ "order, zwebs, xwebs = compute_pauli_webs(g)\n", "\n", "# highlight the web associated to the T spider\n", - "zx.draw(g, labels=True, pauli_web=webs[15])" + "zx.draw(g, labels=True, pauli_web=zwebs[15])" ] }, { diff --git a/pyzx/pauliweb.py b/pyzx/pauliweb.py index 551245c9..9908d382 100644 --- a/pyzx/pauliweb.py +++ b/pyzx/pauliweb.py @@ -50,7 +50,7 @@ def __init__(self, g: BaseGraph[VT,ET]): self.es: Dict[Tuple[VT,VT], str] = dict() self.vs: Set[VT] = set() - def add_edge(self, v_pair: Tuple[VT, VT], pauli: str): + def add_edge(self, v_pair: Tuple[VT, VT], pauli: str, spread_to_input: bool=False): s, t = v_pair self.vs.add(s) self.vs.add(t) @@ -60,10 +60,18 @@ def add_edge(self, v_pair: Tuple[VT, VT], pauli: str): self.es[(s,t)] = multiply_paulis(t1, pauli) self.es[(t,s)] = multiply_paulis(t2, pauli if et == EdgeType.SIMPLE else h_pauli(pauli)) - def add_vertex(self, v: VT): + if spread_to_input and ('Z' if self.g.type(t) == VertexType.Z else 'X') == pauli: + inp = self.g.inputs() + for v2 in self.g.neighbors(t): + if v2 in inp: + self.add_edge((t, v2), pauli, spread_to_input=False) + break + + + def add_vertex(self, v: VT, spread_to_input: bool=False): p = 'X' if self.g.type(v) == VertexType.Z else 'Z' for v1 in self.g.neighbors(v): - self.add_edge((v, v1), p) + self.add_edge((v, v1), p, spread_to_input=spread_to_input) def vertices(self): return self.vs @@ -74,64 +82,6 @@ def half_edges(self) -> Dict[Tuple[VT,VT],str]: def __repr__(self): return 'PauliWeb' + str(self.vs) - -def preprocess(g: BaseGraph[VT,ET]): - #g.normalize() - #gadgetize(g) - #gadgets = set(v for v in g.vertices() if g.is_phase_gadget(v)) - #boundary_spiders = set(v for v in g.vertices() if any(g.type(w) == VertexType.BOUNDARY for w in g.neighbors(v))) - #to_rg(g, init_z=None, init_x=gadgets) - - in_circ = Circuit(len(g.inputs())) - for j,i in enumerate(g.inputs()): - e = g.incident_edges(i)[0] - v = next(iter(g.neighbors(i))) - p = g.phase(v) - ty = g.type(v) - - # remove local cliffords from the inputs - if g.edge_type(e) == EdgeType.HADAMARD: - in_circ.add_gate('H', j) - g.set_edge_type(e, EdgeType.SIMPLE) - if p != 0: - g.set_phase(v, 0) - in_circ.add_gate("ZPhase" if ty == VertexType.Z else "XPhase", j, phase=p) - - out_circ = Circuit(len(g.outputs())) - for j,o in enumerate(g.outputs()): - r = g.row(o) - g.set_row(o, r + 2) - e = g.incident_edges(o)[0] - v = next(iter(g.neighbors(o))) - p = g.phase(v) - ty = g.type(v) - - # remove local cliffords from the outputs - if p != 0: - g.set_phase(v, 0) - out_circ.add_gate("ZPhase" if ty == VertexType.Z else "XPhase", j, phase=p) - - if g.edge_type(e) == EdgeType.HADAMARD: - out_circ.add_gate('H', j) - g.remove_edge(e) - - # introduce ID spiders at the outputs for computing pauli webs - if ty == VertexType.X: - v1 = g.add_vertex(VertexType.Z, qubit=g.qubit(o), row=r) - g.add_edge((v,v1), EdgeType.SIMPLE) - else: - v1 = v - g.set_row(v1, r) - - v2 = g.add_vertex(VertexType.X, qubit=g.qubit(o), row=r+1) - - - g.add_edge((v1,v2), EdgeType.SIMPLE) - g.add_edge((v2,o), EdgeType.SIMPLE) - - return (in_circ, out_circ) - - def transpose_corrections(c: Dict[VT, Set[VT]]) -> Dict[VT, Set[VT]]: ct: Dict[VT, Set[VT]] = dict() for k,s in c.items(): @@ -172,16 +122,15 @@ def compute_pauli_webs(g: BaseGraph[VT,ET]) -> Tuple[Dict[VT, int], Dict[VT, Pau xwebs: Dict[VT, PauliWeb[VT,ET]] = dict() vset = g.vertex_set() corr_t = transpose_corrections(corr) - print(corr_t) for v,c in corr_t.items(): pw = PauliWeb(g) for v1 in c: if v1 in vset: - pw.add_vertex(v1) + pw.add_vertex(v1, spread_to_input=True) elif v1 in out_edge: o, vo = out_edge[v1] - pw.add_edge((o,vo), 'Z' if g1.type(v1) == VertexType.X else 'X') + pw.add_edge((o,vo), 'Z' if g1.type(v1) == VertexType.X else 'X', spread_to_input=True) if v in out_edge: # o, vo = out_edge[v] # pw.add_edge((o,vo), 'Z' if g1.type(v) == VertexType.Z else 'X') @@ -192,5 +141,14 @@ def compute_pauli_webs(g: BaseGraph[VT,ET]) -> Tuple[Dict[VT, int], Dict[VT, Pau if g1.type(v) == VertexType.Z: zwebs[ref] = pw elif g1.type(v) == VertexType.X: xwebs[ref] = pw + for i in g.inputs(): + v = next(iter(g.neighbors(i))) + pw = PauliWeb(g) + if g.type(v) == VertexType.Z: + pw.add_edge((v, i), 'Z') + zwebs[v] = pw + elif g.type(v) == VertexType.X: + pw.add_edge((v, i), 'X') + xwebs[v] = pw return (order, zwebs, xwebs) \ No newline at end of file