From e8261a7650f079cf8bc676d488feaa2156c3e56b Mon Sep 17 00:00:00 2001 From: matulni Date: Mon, 11 May 2026 18:48:04 +0200 Subject: [PATCH 1/7] wip --- graphix/flow/core.py | 65 +++++++++++++++++++++ graphix/optimization.py | 107 +--------------------------------- graphix/pattern.py | 15 +++-- graphix/space_minimization.py | 4 +- tests/test_pattern.py | 3 + 5 files changed, 79 insertions(+), 115 deletions(-) diff --git a/graphix/flow/core.py b/graphix/flow/core.py index 10e02f347..008315ac3 100644 --- a/graphix/flow/core.py +++ b/graphix/flow/core.py @@ -51,11 +51,13 @@ # Unpack introduced in Python 3.12 from typing_extensions import Unpack + from graphix.measurements import BlochMeasurement from graphix.opengraph import OpenGraph from graphix.parameter import ExpressionOrSupportsFloat, Parameter from graphix.pattern import Pattern from graphix.visualization import DrawKwargs + TotalOrder = Sequence[int] _T_PauliFlowMeasurement = TypeVar("_T_PauliFlowMeasurement", bound="PauliFlow[Measurement]") @@ -195,6 +197,69 @@ def to_pattern( pattern.reorder_output_nodes(self.og.output_nodes) return pattern + def to_causal_flow(self: XZCorrections[_PM_co]) -> CausalFlow[_PM_co]: + r"""Extract a causal flow from XZ-corrections. + + This method does not call the flow-extraction routine on the underlying open graph. Instead, it reads out the correction function from the x-corrections and verifies its compatibility with the XZ-corrections intrinsic partial order. + + Returns + ------- + CausalFlow[_PM_co] + + Notes + ----- + See Theorem 1 in Ref. [1]. + + References + ---------- + [1] Browne et al., 2007 New J. Phys. 9 250 (arXiv:quant-ph/0702212). + """ + cf = CausalFlow(self.og, self.x_corrections, self.partial_order_layers) + cf.check_well_formed() # Raises a `FlowError` if the partial order and the correction function are not compatible, if a measured node is corrected by more than one node, or if nodes are not measrued on the XY plane. + return cf + + def to_gflow(self: XZCorrections[_PM_co]) -> GFlow[_PM_co]: + r"""Extract a gflow from XZ-corrections. + + This method does not call the flow-extraction routine on the underlying open graph. Instead, it reads out the correction function from the x-corrections and verifies its compatibility with the XZ-corrections intrinsic partial order. + + Returns + ------- + GFlow[_PM_co] + + Notes + ----- + See Theorem 2 in Ref. [1]. + + References + ---------- + [1] Browne et al., 2007 New J. Phys. 9 250 (arXiv:quant-ph/0702212). + """ + correction_function = { + i: x_corr | {i} if self.og.measurements[i].to_plane() in {Plane.XZ, Plane.YZ} else x_corr + for i, x_corr in self.x_corrections.items() + } + + cf = GFlow(self.og, correction_function, self.partial_order_layers) + cf.check_well_formed() # Raises a `FlowError` if the partial order and the correction function are not compatible. + return cf + + def to_bloch(self: XZCorrections[Measurement]) -> XZCorrections[BlochMeasurement]: + """Return the XZ-corrections where all measurements in the open graph are converted to Bloch. + + See :meth:`OpenGraph.to_bloch` for additional information. + """ + return XZCorrections(self.og.to_bloch(), self.x_corrections, self.z_corrections, self.partial_order_layers) + + def downcast_bloch(self: XZCorrections[Measurement]) -> XZCorrections[BlochMeasurement]: + """Return the open graph if all measurements are described as Bloch measurements; raise `TypeError` otherwise. + + See :meth:`OpenGraph.downcast_bloch` for additional information. + """ + return XZCorrections( + self.og.downcast_bloch(), self.x_corrections, self.z_corrections, self.partial_order_layers + ) + def generate_total_measurement_order(self) -> TotalOrder: """Generate a sequence of all the non-output nodes in the open graph in an arbitrary order compatible with the intrinsic partial order of the XZ-corrections. diff --git a/graphix/optimization.py b/graphix/optimization.py index 5b23d51c1..2d2c8d279 100644 --- a/graphix/optimization.py +++ b/graphix/optimization.py @@ -3,7 +3,6 @@ from __future__ import annotations import dataclasses -from collections import defaultdict from copy import copy from dataclasses import dataclass from types import MappingProxyType @@ -19,12 +18,8 @@ from graphix.clifford import Clifford, Domains from graphix.command import CommandKind, Node from graphix.flow._partial_order import compute_topological_generations -from graphix.flow.core import CausalFlow, GFlow, XZCorrections -from graphix.flow.exceptions import ( - FlowGenericError, - FlowGenericErrorReason, -) -from graphix.fundamentals import Axis, Plane, Sign +from graphix.flow.core import XZCorrections +from graphix.fundamentals import Axis, Sign from graphix.measurements import BlochMeasurement, Measurement, Outcome, PauliMeasurement from graphix.opengraph import OpenGraph from graphix.space_minimization import ( @@ -507,104 +502,6 @@ def process_domain(node: Node, domain: AbstractSet[Node]) -> None: return oset, *generations[::-1] return generations[::-1] - def extract_causal_flow(self) -> CausalFlow[BlochMeasurement]: - r"""Extract the causal flow structure from the current measurement pattern. - - This method does not call the flow-extraction routine on the underlying open graph, but constructs the flow from the pattern corrections instead. - - Returns - ------- - flow.CausalFlow[Measurement] - The causal flow associated with the current pattern. - - Raises - ------ - FlowError - If the pattern: - - Contains measurements in forbidden planes (XZ or YZ), - - Is empty, or - - Induces a correction function and a partial order which fail the well-formedness checks for a valid causal flow. - ValueError - If ``N`` commands in the pattern do not represent a :math:`\ket{+}` state or if the pattern corrections form closed loops. - - Notes - ----- - This method makes use of :func:`StandardizedPattern.extract_partial_order_layers` which computes the pattern's direct acyclical graph (DAG) induced by the corrections and returns a particular layer stratification (obtained by doing a topological sort on the DAG). Further, it constructs the pattern's induced correction function from :math:`M` and :math:`X` commands. - In general, there may exist various layerings which represent the corrections of the pattern. To ensure that a given layering is compatible with the pattern's induced correction function, the partial order must be extracted from a standardized pattern. Commutation of entanglement commands with X and Z corrections in the standardization procedure may generate new corrections, which guarantees that all the topological information of the underlying graph is encoded in the extracted partial order. - """ - correction_function: dict[int, set[int]] = defaultdict(set) - pre_measured_nodes = self.results.keys() # Not included in the flow. - - for m in self.m_list: - try: - bloch = m.measurement.downcast_bloch() - except TypeError: - valid = False - else: - valid = bloch.plane == Plane.XY - if not valid: - raise FlowGenericError(FlowGenericErrorReason.XYPlane) - _update_corrections(m.node, m.s_domain - pre_measured_nodes, correction_function) - - for node, domain in self.x_dict.items(): - _update_corrections(node, domain - pre_measured_nodes, correction_function) - - og = ( - self.extract_opengraph() - ) # Raises a `ValueError` if `N` commands in the pattern do not represent a |+⟩ state. - partial_order_layers = ( - self.extract_partial_order_layers() - ) # Raises a `ValueError` if the pattern corrections form closed loops. - cf = CausalFlow(og.downcast_bloch(), dict(correction_function), partial_order_layers) - cf.check_well_formed() # Raises a `FlowError` if the partial order and the correction function are not compatible, or if a measured node is corrected by more than one node. - return cf - - def extract_gflow(self) -> GFlow[BlochMeasurement]: - r"""Extract the generalized flow (gflow) structure from the current measurement pattern. - - This method does not call the flow-extraction routine on the underlying open graph, but constructs the gflow from the pattern corrections instead. - - Returns - ------- - flow.GFlow[Measurement] - The gflow associated with the current pattern. - - Raises - ------ - FlowError - If the pattern is empty or if the extracted structure does not satisfy - the well-formedness conditions required for a valid gflow. - TypeError - If the pattern contains a Pauli measurement - ValueError - If ``N`` commands in the pattern do not represent a :math:`\ket{+}` state or if the pattern corrections form closed loops. - - Notes - ----- - The notes provided in :func:`self.extract_causal_flow` apply here as well. - """ - correction_function: dict[int, set[int]] = {} - pre_measured_nodes = self.results.keys() # Not included in the flow. - - for m in self.m_list: - # Raises a `TypeError` if the measurement is not represented as a Bloch measurement - if m.measurement.downcast_bloch().plane in {Plane.XZ, Plane.YZ}: - correction_function.setdefault(m.node, set()).add(m.node) - _update_corrections(m.node, m.s_domain - pre_measured_nodes, correction_function) - - for node, domain in self.x_dict.items(): - _update_corrections(node, domain - pre_measured_nodes, correction_function) - - og = ( - self.extract_opengraph() - ) # Raises a `ValueError` if `N` commands in the pattern do not represent a |+⟩ state. - partial_order_layers = ( - self.extract_partial_order_layers() - ) # Raises a `ValueError` if the pattern corrections form closed loops. - gf = GFlow(og.downcast_bloch(), correction_function, partial_order_layers) - gf.check_well_formed() - return gf - def extract_xzcorrections(self) -> XZCorrections[Measurement]: r"""Extract the XZ-corrections from the current measurement pattern. diff --git a/graphix/pattern.py b/graphix/pattern.py index c28bf7555..803816ea2 100644 --- a/graphix/pattern.py +++ b/graphix/pattern.py @@ -990,11 +990,10 @@ def extract_causal_flow(self) -> CausalFlow[BlochMeasurement]: Notes ----- - - See :func:`optimization.StandardizedPattern.extract_causal_flow` for additional information on why it is required to standardized the pattern to extract a causal flow. - Applying the chain ``Pattern.extract_causal_flow().to_corrections().to_pattern()`` to a strongly deterministic pattern returns a new pattern implementing the same unitary transformation. This equivalence holds as long as the original pattern contains no Clifford commands, since those are discarded during open-graph extraction. - This method requires that all the measurements in the pattern are represented as Bloch measurements (i.e., there are no :class:`PauliMeasurement`s). Use :meth:`to_bloch()` to convert all Pauli measurements. """ - return optimization.StandardizedPattern.from_pattern(self).extract_causal_flow() + return self.extract_xzcorrections().downcast_bloch().to_causal_flow() def extract_gflow(self) -> GFlow[BlochMeasurement]: r"""Extract the generalized flow (gflow) structure from the current measurement pattern. @@ -1018,7 +1017,7 @@ def extract_gflow(self) -> GFlow[BlochMeasurement]: ----- The notes provided in :func:`self.extract_causal_flow` apply here as well. """ - return optimization.StandardizedPattern.from_pattern(self).extract_gflow() + return self.extract_xzcorrections().downcast_bloch().to_gflow() def extract_xzcorrections(self) -> XZCorrections[Measurement]: """Extract the XZ-corrections from the current measurement pattern. @@ -1509,12 +1508,12 @@ def draw( flow: PauliFlow[Measurement] | None = None if flow_from_pattern: - pattern_std = optimization.StandardizedPattern.from_pattern(self) + xzcorrections = self.extract_xzcorrections().downcast_bloch() try: - flow = pattern_std.extract_causal_flow() + flow = xzcorrections.to_causal_flow() except FlowError: try: - flow = pattern_std.extract_gflow() + flow = xzcorrections.to_gflow() except (FlowError, TypeError): warn( "The pattern is not consistent with a causal flow or a gflow. An attempt to be extract the flow from the underlying open graph will be made.", @@ -1539,8 +1538,8 @@ def draw( gv = GraphVisualizer.from_flow(flow=flow, **options) case DrawPatternAnnotations.XZCorrections: - xzcorrections = self.extract_xzcorrections() - gv = GraphVisualizer.from_xzcorrections(xz_corr=xzcorrections, **options) + xzcorrections_ = self.extract_xzcorrections() + gv = GraphVisualizer.from_xzcorrections(xz_corr=xzcorrections_, **options) gv.visualize() diff --git a/graphix/space_minimization.py b/graphix/space_minimization.py index 602e42461..89856770e 100644 --- a/graphix/space_minimization.py +++ b/graphix/space_minimization.py @@ -193,8 +193,8 @@ def causal_flow(pattern: StandardizedPattern) -> SpaceMinimizationHeuristicResul This minimization heuristic is optimal but requires the pattern to have a causal flow. """ try: - cf = pattern.extract_causal_flow() - except FlowError: + cf = pattern.extract_xzcorrections().downcast_bloch().to_causal_flow() + except (TypeError, FlowError): return None else: meas_order = tuple(chain(*reversed(cf.partial_order_layers[1:]))) diff --git a/tests/test_pattern.py b/tests/test_pattern.py index 948c5d9ca..55041ebf8 100644 --- a/tests/test_pattern.py +++ b/tests/test_pattern.py @@ -999,6 +999,7 @@ class PatternFlowTestCase(NamedTuple): # Extract causal flow from random circuits @pytest.mark.parametrize("jumps", range(1, 11)) def test_extract_causal_flow_rnd_circuit(self, fx_bg: PCG64, jumps: int) -> None: + """Tests the round trip Pattern -> XZCorrections -> CausalFlow -> XZCorrections -> Pattern.""" rng = Generator(fx_bg.jumped(jumps)) nqubits = 2 depth = 2 @@ -1018,6 +1019,7 @@ def test_extract_causal_flow_rnd_circuit(self, fx_bg: PCG64, jumps: int) -> None # Extract gflow from random circuits @pytest.mark.parametrize("jumps", range(1, 11)) def test_extract_gflow_rnd_circuit(self, fx_bg: PCG64, jumps: int) -> None: + """Tests the round trip Pattern -> XZCorrections -> GFlow -> XZCorrections -> Pattern.""" rng = Generator(fx_bg.jumped(jumps)) nqubits = 2 depth = 2 @@ -1050,6 +1052,7 @@ def test_extract_causal_flow(self, fx_rng: Generator, test_case: PatternFlowTest @pytest.mark.parametrize("test_case", PATTERN_FLOW_TEST_CASES) def test_extract_gflow(self, fx_rng: Generator, test_case: PatternFlowTestCase) -> None: + """Tests the round trip Pattern -> XZCorrections -> GFlow -> XZCorrections -> Pattern.""" if test_case.has_gflow: alpha = 2 * np.pi * fx_rng.random() s_ref = test_case.pattern.simulate_pattern(input_state=PlanarState(Plane.XZ, alpha), rng=fx_rng) From 34543ea17732e959310b80b102ea9fe414bd64e1 Mon Sep 17 00:00:00 2001 From: matulni Date: Mon, 11 May 2026 19:54:21 +0200 Subject: [PATCH 2/7] Fix bug in corr to gflow --- graphix/flow/core.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/graphix/flow/core.py b/graphix/flow/core.py index 008315ac3..22fb825c9 100644 --- a/graphix/flow/core.py +++ b/graphix/flow/core.py @@ -235,14 +235,19 @@ def to_gflow(self: XZCorrections[_PM_co]) -> GFlow[_PM_co]: ---------- [1] Browne et al., 2007 New J. Phys. 9 250 (arXiv:quant-ph/0702212). """ - correction_function = { - i: x_corr | {i} if self.og.measurements[i].to_plane() in {Plane.XZ, Plane.YZ} else x_corr - for i, x_corr in self.x_corrections.items() - } + correction_function: dict[int, set[int]] = {} - cf = GFlow(self.og, correction_function, self.partial_order_layers) - cf.check_well_formed() # Raises a `FlowError` if the partial order and the correction function are not compatible. - return cf + for i, meas in self.og.measurements.items(): + corrections = set(self.x_corrections.get(i, set())) + + if meas.to_plane() in {Plane.XZ, Plane.YZ}: + corrections.add(i) + + correction_function[i] = corrections + + gf = GFlow(self.og, correction_function, self.partial_order_layers) + gf.check_well_formed() # Raises a `FlowError` if the partial order and the correction function are not compatible. + return gf def to_bloch(self: XZCorrections[Measurement]) -> XZCorrections[BlochMeasurement]: """Return the XZ-corrections where all measurements in the open graph are converted to Bloch. From c76f17dc920494a6a4dcf3af2ce7f2fcb7c9bbcc Mon Sep 17 00:00:00 2001 From: matulni Date: Mon, 11 May 2026 20:07:11 +0200 Subject: [PATCH 3/7] Fix typing error visualization --- graphix/pattern.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/graphix/pattern.py b/graphix/pattern.py index 803816ea2..a7810b480 100644 --- a/graphix/pattern.py +++ b/graphix/pattern.py @@ -1508,12 +1508,12 @@ def draw( flow: PauliFlow[Measurement] | None = None if flow_from_pattern: - xzcorrections = self.extract_xzcorrections().downcast_bloch() + xz_corrections = self.extract_xzcorrections() try: - flow = xzcorrections.to_causal_flow() - except FlowError: + flow = xz_corrections.downcast_bloch().to_causal_flow() + except (FlowError, TypeError): try: - flow = xzcorrections.to_gflow() + flow = xz_corrections.downcast_bloch().to_gflow() except (FlowError, TypeError): warn( "The pattern is not consistent with a causal flow or a gflow. An attempt to be extract the flow from the underlying open graph will be made.", @@ -1538,8 +1538,8 @@ def draw( gv = GraphVisualizer.from_flow(flow=flow, **options) case DrawPatternAnnotations.XZCorrections: - xzcorrections_ = self.extract_xzcorrections() - gv = GraphVisualizer.from_xzcorrections(xz_corr=xzcorrections_, **options) + xzcorrections = self.extract_xzcorrections() + gv = GraphVisualizer.from_xzcorrections(xz_corr=xzcorrections, **options) gv.visualize() From 2ecdd015dfc3246cf93322d3a1591860e163dc9d Mon Sep 17 00:00:00 2001 From: matulni Date: Tue, 12 May 2026 11:36:55 +0200 Subject: [PATCH 4/7] Up docs --- graphix/flow/core.py | 4 ++-- graphix/pattern.py | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/graphix/flow/core.py b/graphix/flow/core.py index 22fb825c9..464f14f1d 100644 --- a/graphix/flow/core.py +++ b/graphix/flow/core.py @@ -200,7 +200,7 @@ def to_pattern( def to_causal_flow(self: XZCorrections[_PM_co]) -> CausalFlow[_PM_co]: r"""Extract a causal flow from XZ-corrections. - This method does not call the flow-extraction routine on the underlying open graph. Instead, it reads out the correction function from the x-corrections and verifies its compatibility with the XZ-corrections intrinsic partial order. + This method does not invoke the flow-extraction routine on the underlying open graph. Instead, it assigns the ``x_corrections`` mapping to the flow's correction function and verifies that it is compatible with the intrinsic partial order of the XZ-corrections. If the resulting correction function is incompatible with this partial order, or the open graph contains measurements in XZ or YZ planes, a ``FlowError`` is raised. Returns ------- @@ -221,7 +221,7 @@ def to_causal_flow(self: XZCorrections[_PM_co]) -> CausalFlow[_PM_co]: def to_gflow(self: XZCorrections[_PM_co]) -> GFlow[_PM_co]: r"""Extract a gflow from XZ-corrections. - This method does not call the flow-extraction routine on the underlying open graph. Instead, it reads out the correction function from the x-corrections and verifies its compatibility with the XZ-corrections intrinsic partial order. + This method does not invoke the flow-extraction routine on the underlying open graph. Instead, it assigns the ``x_corrections`` mapping to the flow's correction function and verifies that it is compatible with the intrinsic partial order of the XZ-corrections. Nodes measured in planes XZ or YZ are assigned to their correcting set. If the resulting correction function is incompatible with this partial order ``FlowError`` is raised. Returns ------- diff --git a/graphix/pattern.py b/graphix/pattern.py index a7810b480..0d26d01f6 100644 --- a/graphix/pattern.py +++ b/graphix/pattern.py @@ -963,8 +963,6 @@ def extract_partial_order_layers(self) -> tuple[frozenset[int], ...]: Notes ----- - This function wraps :func:`optimization.StandardizedPattern.extract_partial_order_layers`, and the returned object is described in the notes of this method. - - - See :func:`optimization.StandardizedPattern.extract_causal_flow` for additional information on why it is required to standardized the pattern to extract the partial order layering. """ return optimization.StandardizedPattern.from_pattern(self).extract_partial_order_layers() From 31f85ecdd26b4ad038010e004bd7322d56508a47 Mon Sep 17 00:00:00 2001 From: matulni Date: Tue, 12 May 2026 11:50:02 +0200 Subject: [PATCH 5/7] Fix typo in comment --- graphix/flow/core.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/graphix/flow/core.py b/graphix/flow/core.py index 464f14f1d..f4904f664 100644 --- a/graphix/flow/core.py +++ b/graphix/flow/core.py @@ -200,7 +200,11 @@ def to_pattern( def to_causal_flow(self: XZCorrections[_PM_co]) -> CausalFlow[_PM_co]: r"""Extract a causal flow from XZ-corrections. - This method does not invoke the flow-extraction routine on the underlying open graph. Instead, it assigns the ``x_corrections`` mapping to the flow's correction function and verifies that it is compatible with the intrinsic partial order of the XZ-corrections. If the resulting correction function is incompatible with this partial order, or the open graph contains measurements in XZ or YZ planes, a ``FlowError`` is raised. + This method does not invoke the flow-extraction routine on the underlying open graph. + Instead, it assigns the ``x_corrections`` mapping to the flow's correction function + and verifies that it is compatible with the intrinsic partial order of the XZ-corrections. + If the resulting correction function is incompatible with this partial order, + or the open graph contains measurements in XZ or YZ planes, a ``FlowError`` is raised. Returns ------- @@ -215,13 +219,17 @@ def to_causal_flow(self: XZCorrections[_PM_co]) -> CausalFlow[_PM_co]: [1] Browne et al., 2007 New J. Phys. 9 250 (arXiv:quant-ph/0702212). """ cf = CausalFlow(self.og, self.x_corrections, self.partial_order_layers) - cf.check_well_formed() # Raises a `FlowError` if the partial order and the correction function are not compatible, if a measured node is corrected by more than one node, or if nodes are not measrued on the XY plane. + cf.check_well_formed() # Raises a `FlowError` if the partial order and the correction function are not compatible, if a measured node is corrected by more than one node, or if nodes are not measured on the XY plane. return cf def to_gflow(self: XZCorrections[_PM_co]) -> GFlow[_PM_co]: r"""Extract a gflow from XZ-corrections. - This method does not invoke the flow-extraction routine on the underlying open graph. Instead, it assigns the ``x_corrections`` mapping to the flow's correction function and verifies that it is compatible with the intrinsic partial order of the XZ-corrections. Nodes measured in planes XZ or YZ are assigned to their correcting set. If the resulting correction function is incompatible with this partial order ``FlowError`` is raised. + This method does not invoke the flow-extraction routine on the underlying open graph. + Instead, it assigns the ``x_corrections`` mapping to the flow's correction function + and verifies that it is compatible with the intrinsic partial order of the XZ-corrections. + Nodes measured in planes XZ or YZ are assigned to their correcting set. If the resulting + correction function is incompatible with this partial order ``FlowError`` is raised. Returns ------- From 0ddcb03d539e5d6985b969fe9fc191c6c573ca36 Mon Sep 17 00:00:00 2001 From: matulni Date: Tue, 12 May 2026 13:36:32 +0200 Subject: [PATCH 6/7] Call downcast_bloch once in pattern.draw --- graphix/pattern.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/graphix/pattern.py b/graphix/pattern.py index 0d26d01f6..6ee1279c0 100644 --- a/graphix/pattern.py +++ b/graphix/pattern.py @@ -1506,17 +1506,21 @@ def draw( flow: PauliFlow[Measurement] | None = None if flow_from_pattern: - xz_corrections = self.extract_xzcorrections() try: - flow = xz_corrections.downcast_bloch().to_causal_flow() - except (FlowError, TypeError): + xz_corrections = self.extract_xzcorrections().downcast_bloch() + except TypeError: + pass + else: try: - flow = xz_corrections.downcast_bloch().to_gflow() - except (FlowError, TypeError): - warn( - "The pattern is not consistent with a causal flow or a gflow. An attempt to be extract the flow from the underlying open graph will be made.", - stacklevel=stacklevel, - ) + flow = xz_corrections.to_causal_flow() + except FlowError: + try: + flow = xz_corrections.to_gflow() + except FlowError: + warn( + "The pattern is not consistent with a causal flow or a gflow. An attempt to be extract the flow from the underlying open graph will be made.", + stacklevel=stacklevel, + ) if flow is None: og = self.extract_opengraph() From fdd93e9aadfa1aebb172531567b95ad97b6b35a5 Mon Sep 17 00:00:00 2001 From: matulni Date: Tue, 12 May 2026 13:38:29 +0200 Subject: [PATCH 7/7] Up changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9cdab9f23..fddc3d857 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - #476 Introduced new methods `OpenGraph.extract_circuit`, `CliffordMap.to_tableau` and new function `graphix.circ_ext.compilation.cm_berg_pass`. Circuit extraction can be done natively in Graphix. +- #505 + - Added new methods `XZCorrections.to_causal_flow` and `XZCorrections.to_gflow` which subsume `StandardizedPattern.extract_causal_flow` and `StandardizedPattern.extract_gflow`. + - Added new methods `XZCorrections.to_bloch` and `XZCorrections.downcast_bloch`. + ### Fixed ### Changed