From f2083ff8bc3e17359ce830532c26bda9317d55fd Mon Sep 17 00:00:00 2001 From: matulni Date: Wed, 22 Jul 2026 10:06:00 +0200 Subject: [PATCH 1/2] Remove method Pattern.graph --- CHANGELOG.md | 3 +++ COMPATIBILITY.md | 2 ++ docs/source/tutorial.rst | 2 +- examples/fusion_extraction.py | 2 +- examples/ghz_with_tn.py | 2 +- examples/qft_with_tn.py | 2 +- examples/tn_simulation.py | 2 +- graphix/pattern.py | 34 ++++++++++---------------------- graphix/sim/tensornet.py | 2 +- tests/test_pattern.py | 2 +- tests/test_space_minimization.py | 2 +- 11 files changed, 23 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 974eb998d..22033ca80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -107,6 +107,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `.to__or_none` for transformations that can return `object` or `None`. Equivalently, we use `.from__or_none` for constructors. - accessor methods use nouns instead of verb + noun. Example: `Pattern.max_degree` instead of `Pattern.compute_max_degree`. +- #571: Removed method `Pattern.graph` + + ## [0.3.5] - 2026-03-26 ### Added diff --git a/COMPATIBILITY.md b/COMPATIBILITY.md index e8df7ec89..e8810fffb 100644 --- a/COMPATIBILITY.md +++ b/COMPATIBILITY.md @@ -4,6 +4,8 @@ Graphix does not guarantee backwards compatibility between 0.x version releases. ## Unreleased +- #571: Method `Pattern.graph` (formely `Pattern.extract_graph`) is removed. Use instead `Pattern.to_opengraph().graph` which standardizes the pattern and fails gracefully if there are non-commutative CLiffords. + - #557: Namespace homogenisation. The following methods and classes have been renamed to provide a homogeneous, consistent and pythonic naming convention: diff --git a/docs/source/tutorial.rst b/docs/source/tutorial.rst index ed0ed0925..2d0fb9205 100644 --- a/docs/source/tutorial.rst +++ b/docs/source/tutorial.rst @@ -157,7 +157,7 @@ This reveals the graph structure of the resource state which we can inspect: .. code-block:: python import networkx as nx - graph = pattern.graph() + graph = pattern.to_opengraph().graph pos = {0: (0, 0), 1: (0, -0.5), 2: (1, 0), 3: (4, 0), 4: (1, -0.5), 5: (2, -0.5), 6: (3, -0.5), 7: (4, -0.5)} graph_params = {'node_size': 240, 'node_color': 'w', 'edgecolors': 'k', 'with_labels': True} nx.draw(graph, pos=pos, **graph_params) diff --git a/examples/fusion_extraction.py b/examples/fusion_extraction.py index 7a450e42c..47e5703e0 100644 --- a/examples/fusion_extraction.py +++ b/examples/fusion_extraction.py @@ -26,7 +26,7 @@ # %% # Here we say we want a graph state with 9 nodes and 12 edges. -# We can obtain resource graph for a measurement pattern by using :code:`pattern.graph()`. +# We can obtain resource graph for a measurement pattern by using :code:`pattern.to_opengraph().graph`. gs = Graph() nodes = [0, 1, 2, 3, 4, 5, 6, 7, 8] edges = [(0, 1), (1, 2), (2, 3), (3, 0), (3, 4), (0, 5), (4, 5), (5, 6), (6, 7), (7, 0), (7, 8), (8, 1)] diff --git a/examples/ghz_with_tn.py b/examples/ghz_with_tn.py index a734b54ab..c0b300367 100644 --- a/examples/ghz_with_tn.py +++ b/examples/ghz_with_tn.py @@ -35,7 +35,7 @@ pattern = circuit.transpile().pattern pattern.standardize() -graph = pattern.graph() +graph = pattern.to_opengraph().graph print(f"Number of nodes: {len(graph.nodes)}") print(f"Number of edges: {len(graph.edges)}") pos = nx.spring_layout(graph) diff --git a/examples/qft_with_tn.py b/examples/qft_with_tn.py index af8f6a43d..34b2db099 100644 --- a/examples/qft_with_tn.py +++ b/examples/qft_with_tn.py @@ -59,7 +59,7 @@ def qft(circuit: Circuit, n: int) -> None: pattern = circuit.transpile().pattern pattern.standardize() pattern.shift_signals() -graph = pattern.graph() +graph = pattern.to_opengraph().graph print(f"Number of nodes: {len(graph.nodes)}") print(f"Number of edges: {len(graph.edges)}") diff --git a/examples/tn_simulation.py b/examples/tn_simulation.py index 873ca1e14..66959b85a 100644 --- a/examples/tn_simulation.py +++ b/examples/tn_simulation.py @@ -78,7 +78,7 @@ def ansatz( # %% # Print some properties of the graph. -graph = pattern.graph() +graph = pattern.to_opengraph().graph print(f"Number of nodes: {len(graph.nodes)}") print(f"Number of edges: {len(graph.edges)}") diff --git a/graphix/pattern.py b/graphix/pattern.py index 122c3ad91..d7c20b390 100644 --- a/graphix/pattern.py +++ b/graphix/pattern.py @@ -1192,7 +1192,7 @@ def max_degree(self) -> int: max_degree : int max degree of a pattern """ - graph = self.graph() + graph = self.to_opengraph().graph degree = graph.degree() assert isinstance(degree, nx.classes.reportviews.DiDegreeView) degrees = dict(degree).values() @@ -1200,27 +1200,6 @@ def max_degree(self) -> int: return 0 return int(max(degrees)) - def graph(self) -> nx.Graph[int]: - """Return the graph state from the command sequence, extracted from ``N`` and ``E`` commands. - - Returns - ------- - graph_state: nx.Graph[int] - """ - graph: nx.Graph[int] = nx.Graph() - graph.add_nodes_from(self.input_nodes) - for cmd in self.__seq: - match cmd.kind: - case CommandKind.N: - graph.add_node(cmd.node) - case CommandKind.E: - u, v = cmd.nodes - if graph.has_edge(u, v): - graph.remove_edge(u, v) - else: - graph.add_edge(u, v) - return graph - def nodes(self) -> set[int]: """Return the set of nodes of the pattern.""" nodes = set(self.input_nodes) @@ -1237,8 +1216,15 @@ def isolated_nodes(self) -> set[int]: isolated_nodes : set[int] set of the isolated nodes """ - graph = self.graph() - return {node for node, d in graph.degree if d == 0} + nodes = set(self.input_nodes) + for cmd in self.__seq: + match cmd.kind: + case CommandKind.N: + nodes.add(cmd.node) + case CommandKind.E: + u, v = cmd.nodes + nodes -= {u, v} + return nodes def to_opengraph(self) -> OpenGraph[Measurement]: r"""Extract the underlying resource-state open graph from the pattern. diff --git a/graphix/sim/tensornet.py b/graphix/sim/tensornet.py index d505d505e..c9f4b3bf3 100644 --- a/graphix/sim/tensornet.py +++ b/graphix/sim/tensornet.py @@ -648,7 +648,7 @@ def __init__( if graph_prep == "parallel": if not pattern.is_standard(): raise ValueError("parallel preparation strategy does not support not-standardized pattern") - graph = pattern.graph() + graph = pattern.to_opengraph().graph state = MBQCTensorNet( graph_nodes=graph.nodes, graph_edges=graph.edges, diff --git a/tests/test_pattern.py b/tests/test_pattern.py index b8cb40606..64a0f957a 100644 --- a/tests/test_pattern.py +++ b/tests/test_pattern.py @@ -1256,7 +1256,7 @@ def test_graph(self) -> None: circuit.rx(v, ANGLE_PI / 9) pattern = circuit.transpile().pattern - graph = pattern.graph() + graph = pattern.to_opengraph().graph graph_ref: nx.Graph[int] = nx.Graph() graph_ref.add_nodes_from(range(27)) diff --git a/tests/test_space_minimization.py b/tests/test_space_minimization.py index 9e99104ec..e8312de58 100644 --- a/tests/test_space_minimization.py +++ b/tests/test_space_minimization.py @@ -77,7 +77,7 @@ def test_minimization_by_degree_edge_ordering() -> None: ] ) # Verify Networkx node ordering behaves as expected - graph = p.graph() + graph = p.to_opengraph().graph assert set(graph.edges()) == {(0, 2), (1, 2)} assert set(graph.edges(2)) == {(2, 0), (2, 1)} From baeabb2e53579d4834234f1c1732aed703486a2f Mon Sep 17 00:00:00 2001 From: matulni Date: Wed, 22 Jul 2026 10:38:21 +0200 Subject: [PATCH 2/2] Fix doc error --- docs/source/modifier.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/source/modifier.rst b/docs/source/modifier.rst index 7a4fff5ce..c2efa1393 100644 --- a/docs/source/modifier.rst +++ b/docs/source/modifier.rst @@ -50,8 +50,6 @@ Pattern Manipulation .. automethod:: is_standard - .. automethod:: graph - .. automethod:: nodes .. automethod:: to_causalflow