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