-
Notifications
You must be signed in to change notification settings - Fork 59
feat: add ConstructCircuitDAG director pattern
#2214
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
andrijapau
merged 130 commits into
feature/graph-visualization
from
feature/mlir-to-dag-pass
Nov 28, 2025
Merged
Changes from all commits
Commits
Show all changes
130 commits
Select commit
Hold shift + click to select a range
265cd4d
copy files over
andrijapau e9ceaa7
add pydot to requirements.txt
andrijapau ae50ca1
add files
andrijapau a0e37b0
rename
andrijapau 76b5565
add base class
andrijapau 659f480
quick changes
andrijapau 8699557
add control flow support
andrijapau db6edc9
clean-up
andrijapau 2be63e4
Apply suggestion from @andrijapau
andrijapau 12fa2af
Apply suggestion from @andrijapau
andrijapau 2c93330
Apply suggestion from @andrijapau
andrijapau e68c3f4
Apply suggestion from @andrijapau
andrijapau 4aad864
Apply suggestion from @andrijapau
andrijapau 3be39dc
update cluster label logic
andrijapau a383ba8
fix dag builders test
andrijapau 8ddaa5d
fix pydot dag builders test
andrijapau 1166f40
update doc
andrijapau b0fbf7e
Merge branch 'feature/graph-visualization' into feature/dag-builders
andrijapau df9bf45
basic cl
andrijapau bd75450
Merge branch 'feature/dag-builders' into feature/mlir-to-dag-pass
andrijapau 8ca5b1f
basic cl
andrijapau b579a3f
Trigger CI
andrijapau a94d843
Trigger CI
andrijapau 331e349
Apply suggestion from @andrijapau
andrijapau a87d117
just do customop
andrijapau 9713aa3
fix wording
andrijapau 68e8453
Merge branch 'feature/graph-visualization' into feature/dag-builders
andrijapau 8faae36
Merge branch 'feature/dag-builders' into feature/mlir-to-dag-pass
andrijapau 7bbc224
rename
andrijapau d6db965
add back
andrijapau 11b08f0
Update frontend/catalyst/python_interface/visualization/pydot_dag_bui…
andrijapau a76b5bd
Update frontend/catalyst/python_interface/visualization/pydot_dag_bui…
andrijapau 66a87ab
Merge branch 'feature/dag-builders' into feature/mlir-to-dag-pass
andrijapau 90e4ebd
fix
andrijapau 3d9e4bb
fix
andrijapau e303ef1
Merge branch 'feature/graph-visualization' into feature/mlir-to-dag-pass
andrijapau 2504c13
clean-up
andrijapau 4e78777
remove unnecessary stuff
andrijapau e17c111
add test skeleton
andrijapau 19ca1b5
add basic tests
andrijapau 7f88834
basic test idea
andrijapau 3d48c92
make visit private
andrijapau 49b3834
make visit private
andrijapau 80ca59d
fix tests
andrijapau 430ceb8
fix tests
andrijapau 0aff4e5
clean-up
andrijapau e22cbd2
fix: upgrade DAG builders to have get_ methods
andrijapau acf3da7
cl
andrijapau bc978ad
update pydot to adhere to new base class methods
andrijapau dc4cb1c
add test skeletons
andrijapau 7e825d6
add tests
andrijapau 41fc4d1
Apply suggestion from @andrijapau
andrijapau 1868346
add tests
andrijapau fd8d721
fix tests
andrijapau 284ba07
update tests
andrijapau 95ace87
fix documentation
andrijapau ec9caae
fix documentation
andrijapau 99bd602
fix tests
andrijapau 7622b50
whoops
andrijapau 86e8389
whoops
andrijapau a5dc1ac
rename a bunch of stuff
andrijapau fe7ef47
fix documentation
andrijapau b2a13cf
rename a bunch of stuff
andrijapau abfd932
add dev comment
andrijapau a481a04
rename
andrijapau 9a18e5c
update test
andrijapau afa60ee
merge fix/upgrade-dag-builders to feature/mlir-to-dag-pass
andrijapau 0f6ab76
add immutability tests
andrijapau 5584c90
Merge branch 'fix/upgrade-dag-builders' into feature/mlir-to-dag-pass
andrijapau 6d15d7b
clean-up
andrijapau 888d025
clean-up
andrijapau d4b34f9
whoops
andrijapau 2f27f08
Merge branch 'fix/upgrade-dag-builders' into feature/mlir-to-dag-pass
andrijapau 33aa334
fix test
andrijapau d50cfdc
whoops
andrijapau a364869
cleanup
andrijapau cddb234
clean-up
andrijapau 1b5210c
fix formatting issue
andrijapau 14b28bb
isort
andrijapau a1e9211
update tests
andrijapau aad7449
Apply suggestion from @andrijapau
andrijapau 8225658
isort
andrijapau b51016e
Merge branch 'fix/upgrade-dag-builders' into feature/mlir-to-dag-pass
andrijapau 07a0597
Update frontend/catalyst/python_interface/visualization/construct_cir…
andrijapau 40b1eb4
move things around
andrijapau 77dd502
minor cleanup
andrijapau b4ccd61
refactor the get_ to properties
andrijapau d354dba
Merge branch 'fix/upgrade-dag-builders' into feature/mlir-to-dag-pass
andrijapau d14c15b
update fake dag builder
andrijapau 0e0ddfd
attempt to get rid of _subgraphs
andrijapau c41adb9
clean-up test
andrijapau e803543
rename __base__ to None
andrijapau 42cede2
Merge branch 'fix/upgrade-dag-builders' into feature/mlir-to-dag-pass
andrijapau 085ec57
clean-up
andrijapau c08a84c
whoops
andrijapau edc2076
add cluster_ prefix
andrijapau 4c71876
add debug string
andrijapau f1e5849
bring back cache
andrijapau 0ff2ce9
Merge branch 'fix/upgrade-dag-builders' into feature/mlir-to-dag-pass
andrijapau 3c9ca3a
add good dev comment
andrijapau b83e2a4
Merge branch 'fix/upgrade-dag-builders' into feature/mlir-to-dag-pass
andrijapau bc54dbf
Apply suggestion from @andrijapau
andrijapau ee57f40
Apply suggestion from @andrijapau
andrijapau c341858
whoops
andrijapau 2ded5dc
Merge branch 'fix/upgrade-dag-builders' into feature/mlir-to-dag-pass
andrijapau 0460cac
refactor singledispatch
andrijapau 0cbe9af
Update frontend/catalyst/python_interface/visualization/dag_builder.py
andrijapau 4dbdb13
Merge branch 'fix/upgrade-dag-builders' into feature/mlir-to-dag-pass
andrijapau e752329
add more details to docstring
andrijapau 86b5662
Update frontend/catalyst/python_interface/visualization/dag_builder.py
andrijapau 9c26efd
Update frontend/catalyst/python_interface/visualization/pydot_dag_bui…
andrijapau 81a9aa6
Update frontend/catalyst/python_interface/visualization/pydot_dag_bui…
andrijapau ab06276
Update frontend/test/pytest/python_interface/visualization/test_pydot…
andrijapau 3e4102b
Update frontend/catalyst/python_interface/visualization/pydot_dag_bui…
andrijapau 194f14a
Update frontend/catalyst/python_interface/visualization/dag_builder.py
andrijapau 685842c
fix fakebackend
andrijapau 986fb3f
Merge branch 'fix/upgrade-dag-builders' into feature/mlir-to-dag-pass
andrijapau 8c64d81
isort
andrijapau 606f5f5
Merge branch 'fix/upgrade-dag-builders' into feature/mlir-to-dag-pass
andrijapau f666a9f
add exceptions check
andrijapau e28b2b7
add better documentation
andrijapau 952fd7f
fix typo
andrijapau 99f9fc6
Merge branch 'fix/upgrade-dag-builders' into feature/mlir-to-dag-pass
andrijapau 8f2dc98
Apply suggestion from @andrijapau
andrijapau eac25d5
Merge branch 'fix/upgrade-dag-builders' into feature/mlir-to-dag-pass
andrijapau 83225b3
Merge branch 'feature/graph-visualization' into feature/mlir-to-dag-pass
andrijapau ffc9726
fix naming
andrijapau 08b1e6f
Update frontend/catalyst/python_interface/visualization/construct_cir…
andrijapau 3632ebe
mock in test
andrijapau aa16b2a
format
andrijapau File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
71 changes: 71 additions & 0 deletions
71
frontend/catalyst/python_interface/visualization/construct_circuit_dag.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,71 @@ | ||
| # Copyright 2025 Xanadu Quantum Technologies Inc. | ||
|
|
||
| # 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. | ||
|
|
||
| """Contains the ConstructCircuitDAG tool for constructing a DAG from an xDSL module.""" | ||
|
|
||
| from functools import singledispatchmethod | ||
|
|
||
| from xdsl.dialects import builtin | ||
| from xdsl.ir import Block, Operation, Region | ||
|
|
||
| from catalyst.python_interface.visualization.dag_builder import DAGBuilder | ||
|
|
||
|
|
||
| class ConstructCircuitDAG: | ||
| """Utility tool following the director pattern to build a DAG representation of a compiled quantum program. | ||
|
|
||
| This tool traverses an xDSL module and constructs a Directed Acyclic Graph (DAG) | ||
| of it's quantum program using an injected DAGBuilder instance. This tool does not mutate the xDSL module. | ||
|
|
||
| **Example** | ||
|
|
||
| >>> builder = PyDotDAGBuilder() | ||
| >>> director = ConstructCircuitDAG(builder) | ||
| >>> director.construct(module) | ||
| >>> director.dag_builder.to_string() | ||
| ... | ||
| """ | ||
|
|
||
| def __init__(self, dag_builder: DAGBuilder) -> None: | ||
| self.dag_builder: DAGBuilder = dag_builder | ||
|
|
||
| def construct(self, module: builtin.ModuleOp) -> None: | ||
| """Constructs the DAG from the module. | ||
|
|
||
| Args: | ||
| module (xdsl.builtin.ModuleOp): The module containing the quantum program to visualize. | ||
|
|
||
| """ | ||
| for op in module.ops: | ||
| self._visit_operation(op) | ||
|
|
||
| # ============= | ||
| # IR TRAVERSAL | ||
| # ============= | ||
|
|
||
| @singledispatchmethod | ||
| def _visit_operation(self, operation: Operation) -> None: | ||
mehrdad2m marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| """Visit an xDSL Operation. Default to visiting each region contained in the operation.""" | ||
| for region in operation.regions: | ||
| self._visit_region(region) | ||
|
|
||
| def _visit_region(self, region: Region) -> None: | ||
| """Visit an xDSL Region operation.""" | ||
| for block in region.blocks: | ||
| self._visit_block(block) | ||
|
|
||
| def _visit_block(self, block: Block) -> None: | ||
| """Visit an xDSL Block operation, dispatching handling for each contained Operation.""" | ||
| for op in block.ops: | ||
| self._visit_operation(op) | ||
andrijapau marked this conversation as resolved.
Show resolved
Hide resolved
|
||
126 changes: 126 additions & 0 deletions
126
frontend/test/pytest/python_interface/visualization/test_construct_circuit_dag.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,126 @@ | ||
| # Copyright 2025 Xanadu Quantum Technologies Inc. | ||
|
|
||
| # 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. | ||
| """Unit tests for the ConstructCircuitDAG utility.""" | ||
|
|
||
| from unittest.mock import Mock | ||
|
|
||
| import pytest | ||
|
|
||
| pytestmark = pytest.mark.usefixtures("requires_xdsl") | ||
|
|
||
| from xdsl.dialects import test | ||
| from xdsl.dialects.builtin import ModuleOp | ||
| from xdsl.ir.core import Block, Region | ||
|
|
||
| # pylint: disable=wrong-import-position | ||
| # This import needs to be after pytest in order to prevent ImportErrors | ||
| from catalyst.python_interface.visualization.construct_circuit_dag import ( | ||
| ConstructCircuitDAG, | ||
| ) | ||
| from catalyst.python_interface.visualization.dag_builder import DAGBuilder | ||
|
|
||
|
|
||
| class FakeDAGBuilder(DAGBuilder): | ||
| """ | ||
| A concrete implementation of DAGBuilder used ONLY for testing. | ||
| It stores all graph manipulation calls in data structures | ||
| for easy assertion of the final graph state. | ||
| """ | ||
|
|
||
| def __init__(self): | ||
| self._nodes = {} | ||
| self._edges = [] | ||
| self._clusters = {} | ||
|
|
||
| def add_node(self, id, label, cluster_id=None, **attrs) -> None: | ||
| self._nodes[id] = { | ||
| "id": id, | ||
| "label": label, | ||
| "parent_cluster_id": cluster_id, | ||
| "attrs": attrs, | ||
| } | ||
|
|
||
| def add_edge(self, from_id: str, to_id: str, **attrs) -> None: | ||
| self._edges.append( | ||
| { | ||
| "from_id": from_id, | ||
| "to_id": to_id, | ||
| "attrs": attrs, | ||
| } | ||
| ) | ||
|
|
||
| def add_cluster( | ||
| self, | ||
| id, | ||
| node_label=None, | ||
| cluster_id=None, | ||
| **attrs, | ||
| ) -> None: | ||
| self._clusters[id] = { | ||
| "id": id, | ||
| "node_label": node_label, | ||
| "cluster_label": attrs.get("label"), | ||
| "parent_cluster_id": cluster_id, | ||
| "attrs": attrs, | ||
| } | ||
|
|
||
| @property | ||
| def nodes(self): | ||
| return self._nodes | ||
|
|
||
| @property | ||
| def edges(self): | ||
| return self._edges | ||
|
|
||
| @property | ||
| def clusters(self): | ||
| return self._clusters | ||
|
|
||
| def to_file(self, output_filename): | ||
| pass | ||
|
|
||
| def to_string(self) -> str: | ||
| return "graph" | ||
|
|
||
|
|
||
| @pytest.mark.unit | ||
| def test_dependency_injection(): | ||
| """Tests that relevant dependencies are injected.""" | ||
|
|
||
| mock_dag_builder = Mock(DAGBuilder) | ||
| utility = ConstructCircuitDAG(mock_dag_builder) | ||
| assert utility.dag_builder is mock_dag_builder | ||
|
|
||
|
|
||
| @pytest.mark.unit | ||
| def test_does_not_mutate_module(): | ||
| """Test that the module is not mutated.""" | ||
|
|
||
| # Create module | ||
| op = test.TestOp() | ||
| block = Block(ops=[op]) | ||
| region = Region(blocks=[block]) | ||
| container_op = test.TestOp(regions=[region]) | ||
| module_op = ModuleOp(ops=[container_op]) | ||
|
|
||
| # Save state before | ||
| module_op_str_before = str(module_op) | ||
|
|
||
| # Process module | ||
| mock_dag_builder = Mock(DAGBuilder) | ||
| utility = ConstructCircuitDAG(mock_dag_builder) | ||
| utility.construct(module_op) | ||
|
|
||
| # Ensure not mutated | ||
| assert str(module_op) == module_op_str_before |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.