Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Empty outputs layer removed from flow's partial order.
- Flow well-formedness check does not trigger false negative for flows on open graphs without outputs.

- #561: Fixed #555. Method `Pattern.draw` computes Pauli flow from pattern.

### Changed

- #452: Use `uv` for dependency management
Expand Down
38 changes: 18 additions & 20 deletions graphix/pattern.py
Original file line number Diff line number Diff line change
Expand Up @@ -1525,7 +1525,7 @@ def draw(
- ``DrawPatternAnnotations.XZCorrections``: show the pattern's XZ-corrections.
- ``None``: show the underlying open graph only.
flow_from_pattern : bool, default=True
If ``True``, the command sequence of the pattern is used to derive flow or gflow structure. If ``False``, only the underlying opengraph is used.
If ``True``, the command sequence of the pattern is used to derive a flow structure. If ``False``, only the underlying open graph is used.
options : Unpack[DrawKwargs]
Options controlling graph visualization. See :class:`VisualizationOptions`.
stacklevel : int, optional
Expand All @@ -1535,37 +1535,36 @@ def draw(
Raises
------
PatternError
If the underlying opengraph does not have flow.
If the underlying open graph does not have flow.

Notes
-----
If ``flow_from_pattern==True`` but the pattern is not compatible with a gflow, an attempt to be extract the flow from the underlying open graph will be made while warning the user.
If ``flow_from_pattern==True`` but the pattern is not compatible with a causal flow, gflow, or Pauli flow, an attempt to be extract the flow from the underlying open graph will be made while warning the user.
"""
if annotations is None:
og = self.extract_opengraph()
gv = GraphVisualizer.from_opengraph(og=og, **options)
gv = GraphVisualizer.from_opengraph(og, **options)
else:
xzcorrections = self.extract_xzcorrections()
match annotations:
case DrawPatternAnnotations.Flow:
flow: PauliFlow[Measurement] | None = None

if flow_from_pattern:
try:
xz_corrections = self.extract_xzcorrections().downcast_bloch()
except TypeError:
pass
else:
# We first try to extract a causal flow because the plotting
# algorithm for causal flows yields nicer plots.
flow = xzcorrections.downcast_bloch().to_causal_flow()
except (TypeError, FlowError):
try:
flow = xz_corrections.to_causal_flow()
# If the pattern is not consistent with a Pauli flow,
# it won't be consistent with a gflow.
flow = xzcorrections.to_pauli_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,
)

warn(
"The pattern is not consistent with a flow. 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()
try:
Expand All @@ -1581,11 +1580,10 @@ def draw(
"The pattern's open graph does not have Pauli flow. Consider setting the `annotations` parameter to `None` or `DrawPatternAnnotations.XZCorrections`."
)

gv = GraphVisualizer.from_flow(flow=flow, **options)
gv = GraphVisualizer.from_flow(flow, **options)

case DrawPatternAnnotations.XZCorrections:
xzcorrections = self.extract_xzcorrections()
gv = GraphVisualizer.from_xzcorrections(xz_corr=xzcorrections, **options)
gv = GraphVisualizer.from_xzcorrections(xzcorrections, **options)

gv.visualize()

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
35 changes: 28 additions & 7 deletions tests/test_visualization.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,19 @@ def test_og() -> None:
pattern.draw(annotations=None)


@pytest.mark.usefixtures("mock_plot")
def test_non_determinist() -> None:
pattern = Pattern(
input_nodes=[0],
cmds=[command.N(1), command.E((0, 1)), command.M(0)],
)
with pytest.warns(
UserWarning,
match="The pattern is not consistent with a flow. An attempt to be extract the flow from the underlying open graph will be made.",
):
pattern.draw()


# Compare with baseline/test_draw_graph_reference.png
# Update baseline by running: pytest --mpl-generate-path=tests/baseline
@pytest.mark.usefixtures("mock_plot")
Expand Down Expand Up @@ -242,26 +255,34 @@ def test_xzcorr_draw() -> Figure:


@pytest.mark.usefixtures("mock_plot")
@pytest.mark.parametrize("flow_and_not_pauli_presimulate", [False, True])
@pytest.mark.parametrize("flow_from_pattern_and_to_bloch", [False, True])
@pytest.mark.mpl_image_compare
def test_draw_graph_reference(flow_and_not_pauli_presimulate: bool) -> Figure:
def test_draw_graph_reference(flow_from_pattern_and_to_bloch: bool) -> Figure:
circuit = Circuit(3)
circuit.cnot(0, 1)
circuit.cnot(2, 1)
circuit.rx(0, ANGLE_PI / 3)
circuit.x(2)
circuit.cnot(2, 1)
pattern = circuit.transpile().pattern
if flow_and_not_pauli_presimulate:
# Pauli flow extraction from pattern is not implemented yet;
# therefore, the pattern should not contain Pauli measurements
# to have causal flow.
if flow_from_pattern_and_to_bloch:
pattern = pattern.to_bloch()
else:
pattern = pattern.infer_pauli_measurements()
pattern.remove_pauli_measurements()
pattern.standardize()
pattern.draw(
flow_from_pattern=flow_and_not_pauli_presimulate, node_distance=(1, 1), measurement_labels=True, legend=False
flow_from_pattern=flow_from_pattern_and_to_bloch, node_distance=(1, 1), measurement_labels=True, legend=False
)
return plt.gcf()


@pytest.mark.usefixtures("mock_plot")
@pytest.mark.parametrize("flow_from_pattern", [False, True])
@pytest.mark.mpl_image_compare
def test_draw_graph_reference_pauli_flow(flow_from_pattern: bool) -> Figure:
circuit = Circuit(2)
circuit.rzz(0, 1, 0.3)
pattern = circuit.transpile().pattern.infer_pauli_measurements()
pattern.draw(flow_from_pattern=flow_from_pattern, node_distance=(1, 1), measurement_labels=True, legend=False)
return plt.gcf()
Loading