From b46711eab98d6f19469a8770129c5fa93a49f6bd Mon Sep 17 00:00:00 2001
From: John van de Wetering <john@vdwetering.name>
Date: Wed, 22 Jan 2025 16:48:23 +0100
Subject: [PATCH 1/4] Remove all features related to interacting with
 Quantomatic

---
 pyzx/__init__.py         |   1 -
 pyzx/graph/jsonparser.py |  19 ---
 pyzx/io.py               | 262 ---------------------------------------
 pyzx/quantomatic.py      |  79 ------------
 4 files changed, 361 deletions(-)
 delete mode 100644 pyzx/io.py
 delete mode 100644 pyzx/quantomatic.py

diff --git a/pyzx/__init__.py b/pyzx/__init__.py
index 53e142bb..197940fd 100644
--- a/pyzx/__init__.py
+++ b/pyzx/__init__.py
@@ -31,7 +31,6 @@
 from .local_search.genetic import GeneticOptimizer
 from .circuit.qasmparser import qasm
 from .circuit.sqasm import sqasm
-from . import quantomatic
 from . import generate
 from . import todd
 from . import linalg
diff --git a/pyzx/graph/jsonparser.py b/pyzx/graph/jsonparser.py
index 8286fb69..5015a8a8 100644
--- a/pyzx/graph/jsonparser.py
+++ b/pyzx/graph/jsonparser.py
@@ -431,22 +431,3 @@ def to_graphml(g: BaseGraph[VT,ET]) -> str:
     return gml
 
 
-# class ComplexEncoder(json.JSONEncoder):
-#     def default(self, obj):
-#         if isinstance(obj, complex):
-#             return str(obj)
-#         return super().default(obj)
-
-# class ComplexDecoder(json.JSONDecoder):
-#     def __init__(self, *args, **kwargs):
-#         json.JSONDecoder.__init__(self, object_hook=self.object_hook, *args, **kwargs)
-
-#     def object_hook(self, dct):
-#         for k, v in dct.items():
-#             if isinstance(v, str):
-#                 try:
-#                     dct[k] = complex(v)
-#                 except ValueError:
-#                     pass
-#         return dct
-
diff --git a/pyzx/io.py b/pyzx/io.py
deleted file mode 100644
index ffb4b344..00000000
--- a/pyzx/io.py
+++ /dev/null
@@ -1,262 +0,0 @@
-# PyZX - Python library for quantum circuit rewriting
-#        and optimization using the ZX-calculus
-# Copyright (C) 2018 - Aleks Kissinger and John van de Wetering
-
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-
-#    http://www.apache.org/licenses/LICENSE-2.0
-
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import json
-from fractions import Fraction
-from typing import List, Dict, Any
-
-from .utils import FractionLike
-from .graph import Graph, EdgeType, VertexType
-from .graph.base import BaseGraph, VT, ET
-from .symbolic import Poly
-
-__all__ = ['json_to_graph', 'graph_to_json', 'to_graphml']
-
-def _quanto_value_to_phase(s: str) -> Fraction:
-    if not s: return Fraction(0)
-    if r'\pi' in s:
-        try:
-            r = s.replace(r'\pi','').strip()
-            if r.startswith('-'): r = "-1"+r[1:]
-            if r.startswith('/'): r = "1"+r
-            return Fraction(str(r)) if r else Fraction(1)
-        except ValueError:
-            raise ValueError("Invalid phase '{}'".format(s))
-    return Fraction(s)
-
-def _phase_to_quanto_value(p: FractionLike) -> str:
-    if not p: return ""
-    if isinstance(p, Poly):
-        raise ValueError("Symbolic phases not supported")
-    p = Fraction(p)
-    if p.numerator == -1: v = "-"
-    elif p.numerator == 1: v = ""
-    else: v = str(p.numerator)
-    d = "/"+str(p.denominator) if p.denominator!=1 else ""
-    return r"{}\pi{}".format(v,d)
-
-
-def json_to_graph(js: str, force_deprecated_behavior=False) -> BaseGraph:
-    """Converts the json representation of a .qgraph Quantomatic graph into
-    a pyzx graph."""
-    print("json_to_graph(js) is deprecated. Please use zx.Graph.from_json(js) instead.")
-    if not force_deprecated_behavior:
-        return Graph.from_json(js)  # type: ignore
-    j = json.loads(js)
-    g = Graph()
-
-    names: Dict[str, Any] = {} # TODO: Any = VT
-    hadamards: Dict[str, List[Any]] = {}
-
-    inputs = []
-    outputs = []
-    for name,attr in j.get('node_vertices',{}).items():
-        if ('data' in attr and 'type' in attr['data'] and attr['data']['type'] == "hadamard"
-            and 'is_edge' in attr['data'] and attr['data']['is_edge'] == 'true'):
-            hadamards[name] = []
-            continue
-        c = attr['annotation']['coord']
-        q, r = -c[1], c[0]
-        if q == int(q): q = int(q)
-        if r == int(r): r = int(r)
-        v = g.add_vertex(qubit=q, row=r)
-        g.set_vdata(v,'name',name)
-        names[name] = v
-        if 'data' in attr:
-            d = attr['data']
-            if not 'type' in d or d['type'] == 'Z': g.set_type(v,VertexType.Z)
-            elif d['type'] == 'X': g.set_type(v,VertexType.X)
-            elif d['type'] == 'hadamard': g.set_type(v,VertexType.H_BOX)
-            else: raise TypeError("unsupported type '{}'".format(d['type']))
-            if 'value' in d:
-                g.set_phase(v,_quanto_value_to_phase(d['value']))
-            else:
-                g.set_phase(v,Fraction(0,1))
-        else:
-            g.set_type(v,VertexType.Z)
-            g.set_phase(v,Fraction(0,1))
-
-        #g.set_vdata(v, 'x', c[0])
-        #g.set_vdata(v, 'y', c[1])
-    for name,attr in j.get('wire_vertices',{}).items():
-        ann = attr['annotation']
-        c = ann['coord']
-        q, r = -c[1], c[0]
-        if q == int(q): q = int(q)
-        if r == int(r): r = int(r)
-        v = g.add_vertex(VertexType.BOUNDARY,q,r)
-        g.set_vdata(v,'name',name)
-        names[name] = v
-        if "input" in ann and ann["input"]: inputs.append(v)
-        if "output" in ann and ann["output"]: outputs.append(v)
-        #g.set_vdata(v, 'x', c[0])
-        #g.set_vdata(v, 'y', c[1])
-
-    g.set_inputs(tuple(inputs))
-    g.set_outputs(tuple(outputs))
-
-    edges: Dict[Any, List[int]] = {} # TODO: Any = ET
-    for edge in j.get('undir_edges',{}).values():
-        n1, n2 = edge['src'], edge['tgt']
-        if n1 in hadamards and n2 in hadamards: #Both
-            v = g.add_vertex(VertexType.Z)
-            name = "v"+str(len(names))
-            g.set_vdata(v, 'name',name)
-            names[name] = v
-            hadamards[n1].append(v)
-            hadamards[n2].append(v)
-            continue
-        if n1 in hadamards:
-            hadamards[n1].append(names[n2])
-            continue
-        if n2 in hadamards:
-            hadamards[n2].append(names[n1])
-            continue
-
-        amount = edges.get(g.edge(names[n1],names[n2]),[0,0])
-        amount[0] += 1
-        edges[g.edge(names[n1],names[n2])] = amount
-
-    for l in hadamards.values():
-        if len(l) != 2: raise TypeError("Can't parse graphs with irregular Hadamard nodes")
-        e = g.edge(*tuple(l))
-        amount = edges.get(e,[0,0])
-        amount[1] += 1
-        edges[e] = amount
-    g.add_edge_table(edges)
-
-    return g
-
-def graph_to_json(g: BaseGraph[VT,ET], force_deprecated_behavior=False) -> str:
-    """Converts a PyZX graph into JSON output compatible with Quantomatic."""
-    print("graph_to_json(g) is deprecated. Please use g.to_json() instead (for a given graph g).")
-    if not force_deprecated_behavior:
-        return g.to_json()
-    node_vs: Dict[str, Dict[str, Any]] = {}
-    wire_vs: Dict[str, Dict[str, Any]] = {}
-    edges: Dict[str, Dict[str, str]] = {}
-    names: Dict[VT, str] = {}
-    freenamesv = ["v"+str(i) for i in range(g.num_vertices()+g.num_edges())]
-    freenamesb = ["b"+str(i) for i in range(g.num_vertices())]
-
-    inputs = g.inputs()
-    outputs = g.outputs()
-
-    for v in g.vertices():
-        t = g.type(v)
-        coord = [g.row(v),-g.qubit(v)]
-        name = g.vdata(v, 'name')
-        if not name:
-            if t == VertexType.BOUNDARY: name = freenamesb.pop(0)
-            else: name = freenamesv.pop(0)
-        else:
-            try:
-                freenamesb.remove(name) if t==VertexType.BOUNDARY else freenamesv.remove(name)
-            except:
-                pass
-                #print("couldn't remove name '{}'".format(name))
-
-        names[v] = name
-        if t == VertexType.BOUNDARY:
-            wire_vs[name] = {"annotation":{"boundary":True,"coord":coord,
-                                           "input":(v in inputs), "output":(v in outputs)}}
-        else:
-            node_vs[name] = {"annotation": {"coord":coord},"data":{}}
-            if t==VertexType.Z:
-                node_vs[name]["data"]["type"] = "Z"
-            elif t==VertexType.X:
-                node_vs[name]["data"]["type"] = "X"
-            elif t==VertexType.H_BOX:
-                node_vs[name]["data"]["type"] = "hadamard"
-                node_vs[name]["data"]["is_edge"] = "false"
-            else: raise Exception("Unkown vertex type "+ str(t))
-            phase = _phase_to_quanto_value(g.phase(v))
-            if phase: node_vs[name]["data"]["value"] = phase
-            if not node_vs[name]["data"]: del node_vs[name]["data"]
-
-    i = 0
-    for e in g.edges():
-        src,tgt = g.edge_st(e)
-        et = g.edge_type(e)
-        if et == EdgeType.SIMPLE:
-            edges["e"+ str(i)] = {"src": names[src],"tgt": names[tgt]}
-            i += 1
-        elif et==EdgeType.HADAMARD:
-            x1,y1 = g.row(src), -g.qubit(src)
-            x2,y2 = g.row(tgt), -g.qubit(tgt)
-            hadname = freenamesv.pop(0)
-            node_vs[hadname] = {"annotation": {"coord":[(x1+x2)/2.0,(y1+y2)/2.0]},
-                             "data": {"type": "hadamard","is_edge": "true"}}
-            edges["e"+str(i)] = {"src": names[src],"tgt": hadname}
-            i += 1
-            edges["e"+str(i)] = {"src": names[tgt],"tgt": hadname}
-            i += 1
-        else:
-            raise TypeError("Edge of type 0")
-
-
-    return json.dumps({"wire_vertices": wire_vs,
-            "node_vertices": node_vs,
-            "undir_edges": edges})
-
-def to_graphml(g: BaseGraph[VT,ET], force_deprecated_behavior=False) -> str:
-    gml = """<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<graphml xmlns="http://graphml.graphdrawing.org/xmlns">
-    <key attr.name="type" attr.type="int" for="node" id="type">
-        <default>1</default>
-    </key>
-    <key attr.name="phase" attr.type="string" for="node" id="phase">
-        <default>0</default>
-    </key>
-    <key attr.name="edge type" attr.type="int" for="edge" id="etype">
-        <default>1</default>
-    </key>
-    <key attr.name="x" attr.type="double" for="node" id="x">
-        <default>0</default>
-    </key>
-    <key attr.name="y" attr.type="double" for="node" id="y">
-        <default>0</default>
-    </key>
-    <graph edgedefault="undirected">
-"""
-    print("to_graphml(g) is deprecated. Please use g.to_graphml() instead (where g is a Graph instance).")
-    if not force_deprecated_behavior:
-        return g.to_graphml()
-
-    for v in g.vertices():
-        gml += (
-            (8*" " +
-             """<node id="{!s}"><data key="type">{!s}</data><data key="phase">{!s}</data>"""+
-             """<data key="x">{!s}</data><data key="y">{!s}</data></node>\n"""
-            ).format(
-                v, g.type(v), g.phase(v), g.row(v) * 100, g.qubit(v) * 100
-            ))
-
-    for e in g.edges():
-        s,t = g.edge_st(e)
-        gml += (
-            (8*" " +
-             """<edge id="{!s}_{!s}" source="{!s}" target="{!s}">"""+
-             """<data key="etype">{!s}</data></edge>\n"""
-            ).format(
-                s, t, s, t, g.edge_type(e)
-            ))
-    gml += """
-    </graph>
-</graphml>
-"""
-
-    return gml
diff --git a/pyzx/quantomatic.py b/pyzx/quantomatic.py
deleted file mode 100644
index 6e6968bf..00000000
--- a/pyzx/quantomatic.py
+++ /dev/null
@@ -1,79 +0,0 @@
-# PyZX - Python library for quantum circuit rewriting 
-#        and optimization using the ZX-calculus
-# Copyright (C) 2018 - Aleks Kissinger and John van de Wetering
-
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-
-#    http://www.apache.org/licenses/LICENSE-2.0
-
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""
-Implements methods for interacting with Quantomatic::
-
-	import pyzx as zx
-	zx.settings.quantomatic_location = "path/to/quantomatic/jar/file.jar"
-	g = zx.generate.cliffordT(3,10,0.2)
-	g2 = zx.quantomatic.edit_graph(g) # Opens Quantomatic with the graph g opened. Execution is blocked until Quantomatic is closed again.
-	# If you have saved the qgraph file in quantomatic, then g2 should now contain your changes.
-
-"""
-
-import tempfile
-import os
-import subprocess
-
-from .utils import settings
-from .io import json_to_graph, graph_to_json
-from .graph.base import BaseGraph
-
-def edit_graph(g: BaseGraph) -> BaseGraph:
-	"""Opens Quantomatic with the graph ``g`` loaded. When you are done editing the graph, 
-	you save it in Quantomatic and close the executable. The resulting graph is returned by this function.
-	Note that this function blocks until the Quantomatic executable is closed. For this function to work
-	you must first set ``zx.settings.quantomatic_location`` to point towards the Quantomatic .jar file."""
-	if not settings.quantomatic_location or not os.path.exists(settings.quantomatic_location):
-		raise Exception("Please point towards the Quantomatic jar file with pyzx.settings.quantomatic_location")
-
-	with tempfile.TemporaryDirectory() as tmpdirname:
-		projectname = os.path.join(tmpdirname, "main.qgraph")
-		with open(projectname,'w') as f:
-			f.write(pyzx_qproject)
-		js = graph_to_json(g)
-		fname = os.path.join(tmpdirname, "pyzxgraph.qgraph")
-		with open(fname,'w') as f:
-			f.write(js)
-		print("Opening Quantomatic...")
-		subprocess.check_call(["java", "-jar",settings.quantomatic_location, projectname, fname])
-		print("Done")
-		with open(fname, 'r') as f:
-			js = f.read()
-			g = json_to_graph(js)
-	return g
-
-
-pyzx_qproject = """
-{"name":"PyZX",
-"theory":{"name":"Red/green theory","core_name":"red_green",
-"vertex_types":{
-	"X":{"value":{"type":"angle_expr","latex_constants":true,"validate_with_core":false},
-		"style":{"label":{"position":"inside","fg_color":[1.0,1.0,1.0]},"stroke_color":[0.0,0.0,0.0],"fill_color":[1.0,0.0,0.0],"shape":"circle","stroke_width":1},"default_data":{"type":"X","value":""}},
-	"Z":{"value":{"type":"angle_expr","latex_constants":true,"validate_with_core":false},
-		"style":{"label":{"position":"inside","fg_color":[0.0,0.0,0.0]},"stroke_color":[0.0,0.0,0.0],"fill_color":[0.0,0.800000011920929,0.0],"shape":"circle","stroke_width":1},"default_data":{"type":"Z","value":""}},
-	"hadamard":{"value":{"type":"string","latex_constants":false,"validate_with_core":false},
-		"style":{"label":{"position":"inside","fg_color":[0.0,0.20000000298023224,0.0]},"stroke_color":[0.0,0.0,0.0],"fill_color":[1.0,1.0,0.0],"shape":"rectangle","stroke_width":1},"default_data":{"type":"hadamard","value":""}},
-	"var":{"value":{"type":"string","latex_constants":false,"validate_with_core":false},
-		"style":{"label":{"position":"inside","fg_color":[0.0,0.0,0.0]},"stroke_color":[0.0,0.0,0.0],"fill_color":[0.6000000238418579,1.0,0.800000011920929],"shape":"rectangle","stroke_width":1},"default_data":{"type":"var","value":""}}
-	},
-"default_vertex_type":"Z",
-"default_edge_type":"string",
-"edge_types":{
-	"string":{"value":{"type":"string","latex_constants":false,"validate_with_core":false},"style":{"stroke_color":[0.0,0.0,0.0],"stroke_width":1,"label":{"position":"center","fg_color":[0.0,0.0,1.0],"bg_color":[0.800000011920929,0.800000011920929,1.0,0.699999988079071]}},"default_data":{"type":"string","value":""}}}
-	}
-}"""
\ No newline at end of file

From da7b9e7cafa201b9e4d74090f7d4cd88134005e2 Mon Sep 17 00:00:00 2001
From: John van de Wetering <john@vdwetering.name>
Date: Wed, 22 Jan 2025 16:48:50 +0100
Subject: [PATCH 2/4] Modify AllFeatures demo notebook to use ZXLive instead of
 Quantomatic for editing graphs

---
 demos/AllFeatures.ipynb | 76 ++++++++++++++++++++---------------------
 1 file changed, 38 insertions(+), 38 deletions(-)

diff --git a/demos/AllFeatures.ipynb b/demos/AllFeatures.ipynb
index af029675..b8e1636a 100644
--- a/demos/AllFeatures.ipynb
+++ b/demos/AllFeatures.ipynb
@@ -8,7 +8,7 @@
     "\n",
     "## Contents:\n",
     "* [Loading and saving circuits](#circuits)\n",
-    "* [Interacting with Quantomatic](#quantomatic)\n",
+    "* [Importing, exporting and editing diagrams](#diagram-io)\n",
     "* [Optimizing ZX-diagrams](#optimization-zx)\n",
     "* [Extracting and optimizing circuits](#optimization-circuits)\n",
     "* [Phase Teleportation](#phase-teleportation)"
@@ -172,11 +172,9 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "<a id=\"quantomatic\"></a>\n",
-    "# Interacting with Quantomatic\n",
-    "PyZX allows easy integration with quantomatic.\n",
-    "\n",
-    "First of all, Quantomatic graph files can be imported into PyZX:"
+    "<a id=\"diagram-io\"></a>\n",
+    "# Importing, exporting and editing diagrams\n",
+    "PyZX also has its own json format for exporting graphs and interacts with [ZXLive](https://github.com/zxcalc/zxlive) to make manually modifying diagrams easy. First, let's see that we can indeed load diagrams:"
    ]
   },
   {
@@ -195,24 +193,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "PyZX saves the names of the vertices:"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "print(g.vdata(12,'name'))\n",
-    "print(g.vdata(1,'name'))"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "Because this graph was originally exported from PyZX, it has automatically remembered what its inputs and outputs are:"
+    "Because this graph was originally exported from PyZX starting as a circuit, it has automatically remembered what its inputs and outputs are:"
    ]
   },
   {
@@ -228,7 +209,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "For a graph that originated from Quantomatic we need to tell it what its inputs and outputs are.\n",
+    "For a graph that was built manually, we might need to tell it what its inputs and outputs are.\n",
     "\n",
     "This can be done either manually:\n",
     "\n",
@@ -243,17 +224,17 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "g.set_inputs(())\n",
+    "g.set_inputs(()) # Reset the inputs and outputs, so we can let PyZX auto-detect them\n",
     "g.set_outputs(())\n",
     "g.auto_detect_io()\n",
     "print(g.inputs(), g.outputs())"
    ]
   },
   {
-   "cell_type": "markdown",
+   "cell_type": "raw",
    "metadata": {},
    "source": [
-    "We can also call Quantomatic from PyZX. To do this we first need to tell PyZX where the Quantomatic executable can be found:"
+    "we can export a diagram to a JSON format that can be loaded back into PyZX (or ZXLive):"
    ]
   },
   {
@@ -262,14 +243,14 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "zx.quantomatic.quantomatic_location = os.path.join('path', 'to', 'Quantomatic.jar')"
+    "print(g.to_json())"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "Now, we can load a PyZX graph into Quantomatic using the following line:"
+    "We can call ZXLive from within a Jupyter notebook, in order to modify diagrams on the fly:"
    ]
   },
   {
@@ -278,18 +259,37 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "result = zx.quantomatic.edit_graph(g)"
+    "%gui qt6\n",
+    "\n",
+    "# First make sure zxlive is installed by `pip install zxlive`\n",
+    "from zxlive import app\n",
+    "\n",
+    "g =  zx.Graph('multigraph') # ZXLive works solely with the multigraph backend, so make sure you set the correct backend first.\n",
+    "g.add_vertex(zx.VertexType.Z, 0, 0)\n",
+    "g.add_vertex(zx.VertexType.X, 0, 1)\n",
+    "g.add_edge((0, 1))\n",
+    "zx.draw(g)\n",
+    "\n",
+    "zxl = app.get_embedded_app()\n",
+    "zxl.edit_graph(g, 'g1')\n",
+    "zxl.edit_graph(g, 'g2')"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "This starts Quantomatic with the graph ``g`` loaded. When you are done editing the graph, you simply save the file in Quantomatic, and close it. The result is then loaded and returned.\n",
-    "\n",
-    "NOTE1: The Notebook will be blocked until the Quantomatic executable is closed.\n",
-    "\n",
-    "NOTE2: Currently this only works with a recent build of Quantomatic that is as of yet only available via the repository, so make sure you are working with an up-to-date branch of Quantomatic."
+    "After making some edits within ZXLive, we can get the diagram back into this window so we can continue to do further work with them:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "zx.draw(zxl.get_copy_of_graph('g1'))\n",
+    "zx.draw(zxl.get_copy_of_graph('g2'))"
    ]
   },
   {
@@ -689,7 +689,7 @@
  ],
  "metadata": {
   "kernelspec": {
-   "display_name": "Python 3",
+   "display_name": "Python 3 (ipykernel)",
    "language": "python",
    "name": "python3"
   },
@@ -703,7 +703,7 @@
    "name": "python",
    "nbconvert_exporter": "python",
    "pygments_lexer": "ipython3",
-   "version": "3.8.10"
+   "version": "3.11.2"
   }
  },
  "nbformat": 4,

From b61a6a4ade4cfdaeaac1f75e1949046c2a4d0641 Mon Sep 17 00:00:00 2001
From: John van de Wetering <john@vdwetering.name>
Date: Thu, 23 Jan 2025 10:28:46 +0100
Subject: [PATCH 3/4] Modify AllFeatures

---
 demos/AllFeatures.ipynb | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/demos/AllFeatures.ipynb b/demos/AllFeatures.ipynb
index b8e1636a..e8862f16 100644
--- a/demos/AllFeatures.ipynb
+++ b/demos/AllFeatures.ipynb
@@ -264,7 +264,7 @@
     "# First make sure zxlive is installed by `pip install zxlive`\n",
     "from zxlive import app\n",
     "\n",
-    "g =  zx.Graph('multigraph') # ZXLive works solely with the multigraph backend, so make sure you set the correct backend first.\n",
+    "g =  zx.Graph()\n",
     "g.add_vertex(zx.VertexType.Z, 0, 0)\n",
     "g.add_vertex(zx.VertexType.X, 0, 1)\n",
     "g.add_edge((0, 1))\n",
@@ -289,7 +289,9 @@
    "outputs": [],
    "source": [
     "zx.draw(zxl.get_copy_of_graph('g1'))\n",
-    "zx.draw(zxl.get_copy_of_graph('g2'))"
+    "zx.draw(zxl.get_copy_of_graph('g2'))\n",
+    "#Note that ZXLive only works with MultiGraph's, and hence zxl.get_copy_of_graph() always returns an instance of MultiGraph, \n",
+    "#and not of the default graph backend."
    ]
   },
   {

From 3de596926272290d8a8cde99180bb3de5b469ef8 Mon Sep 17 00:00:00 2001
From: John van de Wetering <john@vdwetering.name>
Date: Thu, 23 Jan 2025 10:29:03 +0100
Subject: [PATCH 4/4] Remove Quantomatic from docs

---
 doc/api.rst | 10 +---------
 1 file changed, 1 insertion(+), 9 deletions(-)

diff --git a/doc/api.rst b/doc/api.rst
index 2139c27e..362286d6 100644
--- a/doc/api.rst
+++ b/doc/api.rst
@@ -150,7 +150,7 @@ Below is listed the content of ``drawing.py``.
    :undoc-members:
 
 
-Tikz and Quantomatic functionality
+Tikz functionality
 ----------------------------------
 
 .. _tikz:
@@ -165,11 +165,3 @@ Below is listed the content of ``tikz.py``.
 
 .. _quanto:
 
-Below is listed the content of ``quantomatic.py``.
-
-.. module:: quantomatic
-
-.. automodule:: pyzx.quantomatic
-   :members:
-   :undoc-members:
-