Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
66e0597
Enable type-checking for `visualization.py`
thierry-martinez Oct 6, 2025
2eca607
Fix regression in `visualize_w_gflow` and add test
thierry-martinez Oct 7, 2025
e5411f3
Refactor visualization
thierry-martinez Oct 30, 2025
703ed89
Fix plane labels and scaling
thierry-martinez Nov 5, 2025
f098ba5
Merge branch 'master' into typing_visualization
thierry-martinez Nov 5, 2025
97671be
Do not show graphs when saving to a file
thierry-martinez Nov 10, 2025
d5dd09c
Add a reference graph to catch regression
thierry-martinez Nov 10, 2025
7cdcf20
:arrow_up: Bump ruff from 0.14.3 to 0.14.4 in the python-packages gro…
dependabot[bot] Nov 10, 2025
25ccb27
Fix ruff and mypy
thierry-martinez Nov 10, 2025
8a112b2
Merge branch 'master' into typing_visualization
thierry-martinez Nov 12, 2025
e6b1a54
Update graphix/visualization.py
thierry-martinez Nov 12, 2025
38f5341
Update graphix/visualization.py
thierry-martinez Nov 12, 2025
f3cd9f0
Fix according to Mateo's comment
thierry-martinez Nov 12, 2025
dc10850
Fix typo
thierry-martinez Nov 12, 2025
175bc49
Add `pytest --mpl` option to noxfile
thierry-martinez Nov 14, 2025
7b76164
Update baseline
thierry-martinez Nov 14, 2025
6da0e73
Scale layout before computing paths
thierry-martinez Nov 14, 2025
eeb715c
No --mpl on Python 3.9
thierry-martinez Nov 15, 2025
c173226
Merge branch 'master' into typing_visualization
thierry-martinez Nov 17, 2025
1180071
Merge branch 'master' into typing_visualization
thierry-martinez Nov 17, 2025
d53dd91
Update CHANGELOG.md
thierry-martinez Nov 17, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- #354, #357: `RZZ` gates are now supported by the transpiler.

- #347: The `visualization.py` module has been partially refactored
and is now well-typed. Pauli nodes are now systematically detected.

### Changed

- #337: Dropped dependence on `sympy` and `galois`.
Expand All @@ -51,6 +54,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- #220, #332: `Pattern.get_measurements_commands` is renamed into
`Pattern.extract_measurement_commands`.

- #347: There is no longer `save` flag in `Pattern.draw_graph`: the
figure is saved to a file as soon as `filename` is not `None` (i.e.,
contains a `Path`). In this case, no window is opened to show the
plot interactively (i.e., the plot is shown interactively in a
window only if `filename` is `None`).

## [0.3.2] - 2025-08-12

### Added
Expand Down
2 changes: 1 addition & 1 deletion examples/visualization.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
edges = [(1, 4), (1, 6), (2, 4), (2, 5), (2, 6), (3, 5), (3, 6)]
inputs = {1, 2, 3}
outputs = {4, 5, 6}
graph = nx.Graph()
graph: nx.Graph[int] = nx.Graph()
graph.add_nodes_from(nodes)
graph.add_edges_from(edges)
meas_planes = {1: Plane.XY, 2: Plane.XY, 3: Plane.XY}
Expand Down
2 changes: 1 addition & 1 deletion graphix/generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ def generate_from_graph(

# search for flow first
f, l_k = graphix.gflow.find_flow(graph, inputs_set, outputs_set, meas_planes=meas_planes)
if f is not None:
if f is not None and l_k is not None:
# flow found
pattern = _flow2pattern(graph, angles, inputs, f, l_k)
pattern.reorder_output_nodes(outputs)
Expand Down
24 changes: 15 additions & 9 deletions graphix/gflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ def find_flow(
iset: set[int],
oset: set[int],
meas_planes: dict[int, Plane] | None = None,
) -> tuple[dict[int, set[int]], dict[int, int]]:
) -> tuple[dict[int, set[int]], dict[int, int]] | tuple[None, None]:
"""Causal flow finding algorithm.

For open graph g with input, output, and measurement planes, this returns causal flow.
Expand Down Expand Up @@ -282,7 +282,7 @@ def find_pauliflow(
return pf[0], pf[1]


def flow_from_pattern(pattern: Pattern) -> tuple[dict[int, set[int]], dict[int, int]]:
def flow_from_pattern(pattern: Pattern) -> tuple[dict[int, set[int]], dict[int, int]] | tuple[None, None]:
"""Check if the pattern has a valid flow. If so, return the flow and layers.

Parameters
Expand All @@ -292,9 +292,11 @@ def flow_from_pattern(pattern: Pattern) -> tuple[dict[int, set[int]], dict[int,

Returns
-------
f: dict
None, None:
The tuple ``(None, None)`` is returned if the pattern does not have a valid causal flow.
f: dict[int, set[int]]
flow function. g[i] is the set of qubits to be corrected for the measurement of qubit i.
l_k: dict
l_k: dict[int, int]
layers obtained by flow algorithm. l_k[d] is a node set of depth d.
"""
if not pattern.is_standard(strict=True):
Expand Down Expand Up @@ -332,7 +334,7 @@ def flow_from_pattern(pattern: Pattern) -> tuple[dict[int, set[int]], dict[int,
return None, None


def gflow_from_pattern(pattern: Pattern) -> tuple[dict[int, set[int]], dict[int, int]]:
def gflow_from_pattern(pattern: Pattern) -> tuple[dict[int, set[int]], dict[int, int]] | tuple[None, None]:
"""Check if the pattern has a valid gflow. If so, return the gflow and layers.

Parameters
Expand All @@ -342,9 +344,11 @@ def gflow_from_pattern(pattern: Pattern) -> tuple[dict[int, set[int]], dict[int,

Returns
-------
g: dict
None, None:
The tuple ``(None, None)`` is returned if the pattern does not have a valid gflow.
g: dict[int, set[int]]
gflow function. g[i] is the set of qubits to be corrected for the measurement of qubit i.
l_k: dict
l_k: dict[int, int]
layers obtained by gflow algorithm. l_k[d] is a node set of depth d.
"""
if not pattern.is_standard(strict=True):
Expand Down Expand Up @@ -404,9 +408,11 @@ def pauliflow_from_pattern(

Returns
-------
p: dict
None, None:
The tuple ``(None, None)`` is returned if the pattern does not have a valid Pauli flow.
p: dict[int, set[int]]
Pauli flow function. p[i] is the set of qubits to be corrected for the measurement of qubit i.
l_k: dict
l_k: dict[int, int]
layers obtained by Pauli flow algorithm. l_k[d] is a node set of depth d.
"""
if not pattern.is_standard(strict=True):
Expand Down
22 changes: 9 additions & 13 deletions graphix/pattern.py
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Eventually we should update the docstrings for consistency too.

Original file line number Diff line number Diff line change
Expand Up @@ -994,11 +994,11 @@ def get_measurement_order_from_flow(self) -> list[int] | None:
measurement order
"""
graph = self.extract_graph()
vin = set(self.input_nodes) if self.input_nodes is not None else set()
vin = set(self.input_nodes)
vout = set(self.output_nodes)
meas_planes = self.get_meas_plane()
f, l_k = find_flow(graph, vin, vout, meas_planes=meas_planes)
if f is None:
if f is None or l_k is None:
return None
depth, layer = get_layers(l_k)
meas_order: list[int] = []
Expand All @@ -1020,7 +1020,7 @@ def get_measurement_order_from_gflow(self) -> list[int]:
isolated = list(nx.isolates(graph))
if isolated:
raise ValueError("The input graph must be connected")
vin = set(self.input_nodes) if self.input_nodes is not None else set()
vin = set(self.input_nodes)
vout = set(self.output_nodes)
meas_planes = self.get_meas_plane()
flow, l_k = find_gflow(graph, vin, vout, meas_planes=meas_planes)
Expand Down Expand Up @@ -1389,10 +1389,9 @@ def draw_graph(
show_local_clifford: bool = False,
show_measurement_planes: bool = False,
show_loop: bool = True,
node_distance: tuple[int, int] = (1, 1),
node_distance: tuple[float, float] = (1, 1),
figsize: tuple[int, int] | None = None,
save: bool = False,
filename: str | None = None,
filename: Path | None = None,
) -> None:
"""Visualize the underlying graph of the pattern with flow or gflow structure.

Expand All @@ -1412,13 +1411,12 @@ def draw_graph(
Distance multiplication factor between nodes for x and y directions.
figsize : tuple
Figure size of the plot.
save : bool
If True, the plot is saved as a png file.
filename : str
Filename of the saved plot.
filename : Path | None
If not None, filename of the png file to save the plot. If None, the plot is not saved.
Default in None.
"""
graph = self.extract_graph()
vin = self.input_nodes if self.input_nodes is not None else []
vin = self.input_nodes
vout = self.output_nodes
meas_planes = self.get_meas_plane()
meas_angles = self.get_angles()
Expand All @@ -1435,7 +1433,6 @@ def draw_graph(
show_loop=show_loop,
node_distance=node_distance,
figsize=figsize,
save=save,
filename=filename,
)
else:
Expand All @@ -1446,7 +1443,6 @@ def draw_graph(
show_loop=show_loop,
node_distance=node_distance,
figsize=figsize,
save=save,
filename=filename,
)

Expand Down
Loading