-
Notifications
You must be signed in to change notification settings - Fork 28
Compiler for Code Switching #524
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
Conversation
|
Note Reviews pausedUse the following commands to manage reviews:
📝 WalkthroughWalkthroughAdds a graph-based code-switching compiler and utilities, CLI scripts to generate and simulate QASM circuits with orchestration shell scripts, tests, documentation, and dependency/config updates (.gitignore and networkx). Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant User
participant Gen as Generator\n(generate_random_circuits.py)
participant FS as FileSystem
participant Sim as Simulator\n(simulate_circuit_performance.py)
participant Compiler as MinimalCodeSwitchingCompiler
participant Qiskit as Qiskit
User->>Gen: run --n --num_circuits --distr_type
loop per-seed
Gen->>Qiskit: random_universal_circuit(...) -> QuantumCircuit
Qiskit-->>Gen: QuantumCircuit
Gen->>FS: write .qasm (skip if exists)
end
User->>Sim: run --qasm_path --n --seed --distr_type
Sim->>FS: read .qasm
FS-->>Sim: qasm content
Sim->>Qiskit: loads -> QuantumCircuit
Sim->>Sim: naive_switching(circuit) => naive_count
Sim->>Compiler: build_from_qiskit(circuit,...)
Compiler->>Compiler: build graph (temporal/bias/idle)
Compiler->>Compiler: compute_min_cut()
Compiler-->>Sim: mincut_count + switch_positions
Sim->>Sim: compute savings, append_to_csv
Sim-->>User: CSV updated
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
pyproject.toml (1)
50-68: Add networkx to [project.dependencies] as explicit direct dependency.While networkx is currently available transitively through pymatching and qecsim, the code directly imports it (
src/mqt/qecc/circuit_compilation/code_switching_compiler.py:14). Best practice is to explicitly declare all direct imports to avoid fragility from transitive dependency changes.Apply the suggested diff with
networkx>=3.0(covers tested versions 3.4.2 and 3.5 from lock file).
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (3)
pyproject.toml(1 hunks)src/mqt/qecc/circuit_compilation/__init__.py(1 hunks)src/mqt/qecc/circuit_compilation/code_switching_compiler.py(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/mqt/qecc/circuit_compilation/__init__.py (1)
src/mqt/qecc/circuit_compilation/code_switching_compiler.py (1)
CodeSwitchGraph(20-179)
🪛 Ruff (0.14.1)
src/mqt/qecc/circuit_compilation/code_switching_compiler.py
178-178: Unused noqa directive (non-enabled: N806)
Remove unused noqa directive
(RUF100)
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: 🐍 Test (ubuntu-24.04-arm) / 🐍 ubuntu-24.04-arm
- GitHub Check: 🐍 Test (macos-15-intel) / 🐍 macos-15-intel
- GitHub Check: 🐍 Test (ubuntu-24.04) / 🐍 ubuntu-24.04
- GitHub Check: 🐍 Test (windows-2022) / 🐍 windows-2022
🔇 Additional comments (3)
pyproject.toml (1)
156-157: mypy override for networkx looks fine.Adding "networkx.*" to ignore_missing_imports aligns with new NX usage.
src/mqt/qecc/circuit_compilation/__init__.py (1)
12-14: Public re-export looks good.
CodeSwitchGraphis correctly exposed via__all__.src/mqt/qecc/circuit_compilation/code_switching_compiler.py (1)
115-127: Redundant edge additions in add_cnot_links.
add_infinite_edgealready adds both directions; calling it twice duplicates work. Keep one call.Apply this diff:
- self.add_infinite_edge(control_node, target_node) - self.add_infinite_edge(target_node, control_node) + self.add_infinite_edge(control_node, target_node)Likely an incorrect or invalid review comment.
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
For this we fixed the arbitrary convention that the 2D Code corresponds to the source and the 3D code to the sink.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 7
♻️ Duplicate comments (2)
src/mqt/qecc/circuit_compilation/code_switching_compiler.py (2)
112-133: Fix inline comments that contradict implementation.The inline comments claim the opposite of what the code does:
- Line 129 says "Source code can perform T" but line 130 connects T to sink
- Line 132 says "Sink code can perform H" but line 133 connects H to source
The docstring at lines 115-116 correctly describes the intended behavior (source=2D Color Code with H, sink=3D Surface Code with T).
Apply this diff to fix the comments:
- # Source code can perform T and CNOT gates + # Sink code (3D Surface Code) can perform T gates if gate_type == "T": self.add_infinite_edge(self.sink, node_id) - # Sink code can perform H and CNOT gates + # Source code (2D Color Code) can perform H gates if gate_type == "H": self.add_infinite_edge(node_id, self.source)
186-198: Remove unusednoqadirective.The
# noqa: N806on line 197 is unnecessary because the N806 rule (non-lowercase variable names) is not enabled in your Ruff configuration.Apply this diff:
- cut_value, (S, T) = nx.minimum_cut(self.G, self.source, self.sink, capacity="capacity") # noqa: N806 + cut_value, (S, T) = nx.minimum_cut(self.G, self.source, self.sink, capacity="capacity")Based on static analysis hints.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (1)
src/mqt/qecc/circuit_compilation/code_switching_compiler.py(1 hunks)
🧰 Additional context used
🪛 Ruff (0.14.1)
src/mqt/qecc/circuit_compilation/code_switching_compiler.py
70-70: Boolean-typed positional argument in function definition
(FBT001)
70-70: Boolean default positional argument in function definition
(FBT002)
86-86: Boolean-typed positional argument in function definition
(FBT001)
86-86: Boolean default positional argument in function definition
(FBT002)
98-98: Boolean-typed positional argument in function definition
(FBT001)
98-98: Boolean default positional argument in function definition
(FBT002)
135-135: Boolean-typed positional argument in function definition
(FBT001)
135-135: Boolean default positional argument in function definition
(FBT002)
147-147: Boolean-typed positional argument in function definition
(FBT001)
147-147: Boolean default positional argument in function definition
(FBT002)
197-197: Unused noqa directive (non-enabled: N806)
Remove unused noqa directive
(RUF100)
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: 🐍 Test (windows-2022) / 🐍 windows-2022
- GitHub Check: 🐍 Test (macos-15-intel) / 🐍 macos-15-intel
- GitHub Check: 🐍 Test (ubuntu-24.04) / 🐍 ubuntu-24.04
this helps to distinguish between unary edges used for bias and temporal edges used for actual switching locations
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
♻️ Duplicate comments (3)
src/mqt/qecc/circuit_compilation/code_switching_compiler.py (3)
88-98: Document thebidirectionalparameter.The
bidirectionalparameter is missing from the docstring and should be keyword-only for clarity.This issue was previously flagged in past reviews.
152-162: Document theone_way_transversal_cnotparameter.The
one_way_transversal_cnotparameter is missing from the docstring and should be keyword-only for clarity.This issue was previously flagged in past reviews.
145-150: Fix inline comments that contradict the implementation.The inline comments at lines 145 and 148 are inconsistent with the implementation and the detailed explanation in lines 132-133:
- Line 145 says "Source code can perform T and CNOT gates" but then connects T to sink (line 147)
- Line 148 says "Sink code can perform H and CNOT gates" but then connects H to source (line 150)
According to your convention (lines 132-133), source = 2D Color Code (performs H), sink = 3D Surface Code (performs T), which matches the implementation but not these comments.
Apply this diff to fix the inline comments:
- # Source code can perform T and CNOT gates + # Sink code (3D Surface Code) can perform T gates if gate_type == "T": self.add_infinite_edge(self.sink, node_id) - # Sink code can perform H and CNOT gates + # Source code (2D Color Code) can perform H gates if gate_type == "H": self.add_infinite_edge(node_id, self.source)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (1)
src/mqt/qecc/circuit_compilation/code_switching_compiler.py(1 hunks)
🧰 Additional context used
🪛 Ruff (0.14.3)
src/mqt/qecc/circuit_compilation/code_switching_compiler.py
71-71: Boolean-typed positional argument in function definition
(FBT001)
71-71: Boolean default positional argument in function definition
(FBT002)
88-88: Boolean-typed positional argument in function definition
(FBT001)
88-88: Boolean default positional argument in function definition
(FBT002)
100-100: Boolean-typed positional argument in function definition
(FBT001)
100-100: Boolean default positional argument in function definition
(FBT002)
152-152: Boolean-typed positional argument in function definition
(FBT001)
152-152: Boolean default positional argument in function definition
(FBT002)
165-165: Boolean-typed positional argument in function definition
(FBT001)
165-165: Boolean default positional argument in function definition
(FBT002)
165-165: Boolean-typed positional argument in function definition
(FBT001)
165-165: Boolean default positional argument in function definition
(FBT002)
208-208: Boolean-typed positional argument in function definition
(FBT001)
208-208: Boolean default positional argument in function definition
(FBT002)
219-219: Unused noqa directive (non-enabled: N806)
Remove unused noqa directive
(RUF100)
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: 🐍 Test (macos-15-intel) / 🐍 macos-15-intel
- GitHub Check: 🐍 Test (windows-2022) / 🐍 windows-2022
- GitHub Check: 🐍 Test (ubuntu-24.04-arm) / 🐍 ubuntu-24.04-arm
🔇 Additional comments (2)
src/mqt/qecc/circuit_compilation/code_switching_compiler.py (2)
220-231: LGTM: Edge-counting logic correctly handles bidirectional edges.The deduplication using
tuple(sorted((u, v)))as a key (lines 226-227) properly avoids double-counting bidirectional edges when determining the number of code switches. The filtering by edge type and cut-crossing check are also correct.
20-68: Well-structured API for code-switching graph construction.The
CodeSwitchGraphclass provides a clean, composable API with separate methods for adding different edge types (infinite, regular, bias) and node types. The use of NetworkX for graph representation and min-cut computation is appropriate for this domain.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (7)
src/mqt/qecc/circuit_compilation/code_switching_compiler.py (7)
26-33: Correct source/sink mapping in class docstring.Doc claims SRC anchors T/CNOT and SNK anchors H/CNOT, but connect_to_code() actually ties T nodes to SNK (Line 152) and H nodes to SRC (Line 155), leaving CNOT unanchored. Please align the docstring with the implementation so downstream users don’t build the wrong mental model.
- - Source (SRC) and sink (SNK) nodes represent two different codes: - * Source-connected nodes (T, CNOT) → operations that can be done transversally in code A. - * Sink-connected nodes (H, CNOT) → operations that can be done transversally in code B. + - Source (SRC) and sink (SNK) nodes represent two different codes: + * Source-connected nodes (H) → operations transversal in the 2D Color Code. + * Sink-connected nodes (T) → operations transversal in the 3D Surface Code. + * CNOT operations are supported by both codes and remain unanchored.
103-117: Fix add_regular_edge documentation to match implementation.The doc still advertises “a regular directed edge” with default capacity 1.0, but the function defaults to DEFAULT_TEMPORAL_EDGE_CAPACITY (100.0) and, unless bidirectional=False, inserts both directions. Please correct the wording and defaults so the public API description is accurate.
- """Add a regular (finite-capacity) directed edge. + """Add regular (finite-capacity) temporal edge(s) between two nodes. @@ - capacity : float, optional - Edge capacity (default is 1.0). + capacity : float, optional + Edge capacity (default is 100.0 via DEFAULT_TEMPORAL_EDGE_CAPACITY). + bidirectional : bool, optional + If True (default), adds both u→v and v→u with the given capacity; otherwise only u→v.
119-126: Document biased_code correctly.biased_code is a str flag choosing between "SRC" and "SNK", yet the docstring still declares it as float/capacity. Please update the parameter section so users understand which values are valid and what effect they have.
- biased_code : float - Capacity of the biased_code edges to be added. + node_id : str + Node to bias toward one of the terminal codes. + biased_code : str, optional + Either "SRC" or "SNK", indicating which terminal should receive the stronger unary edge (default "SRC").
157-167: Document one_way_transversal_cnot parameter.The optional one_way_transversal_cnot flag flips edge directionality but is absent from the docstring. Please describe its behavior (True ⇒ only control→target, False ⇒ bidirectional) so callers understand when to enable it.
target_node : str Node representing the target qubit's CNOT operation. + one_way_transversal_cnot : bool, optional + If True, adds only the control→target infinite edge. If False (default), + adds both directions to keep the qubits in the same code.
234-245: Document all build_from_qiskit feature flags.The docstring covers one_way_transversal_cnot and code_bias but leaves idle_bonus undocumented, and the descriptions are very high-level. Please add explicit entries so users know what enabling idle_bonus does (idle-aware temporal capacities) and reiterate how code_bias affects unary edges.
code_bias : bool, optional - If True, add bias edges for CNOT nodes. + If True, add bias edges for CNOT nodes to prefer one code over the other. + idle_bonus : bool, optional + If True, reduce temporal edge capacity after idle stretches via _edge_capacity_with_idle_bonus.
284-311: Fix compute_min_cut signature, docs, and unused noqa.With return_raw_data=False (the default), the method returns (num_switches: int, S, T), not a float. The signature and Returns section should reflect this union, and the parameter needs documenting. While touching the block, please drop the now-unused
# noqa.- def compute_min_cut(self, return_raw_data: bool = False) -> tuple[float, set[str], set[str]]: + def compute_min_cut(self, *, return_raw_data: bool = False) -> tuple[int | float, set[str], set[str]]: @@ - Returns: + Parameters + ---------- + return_raw_data : bool, optional + If True, return the raw NetworkX cut capacity (float). If False (default), + return the counted number of switching edges (int). + + Returns ------- - Tuple[float, Set[str], Set[str]] - A tuple (cut_value, S, T) where: - - cut_value is the total capacity of the minimum cut, + tuple[int | float, set[str], set[str]] + A tuple (cut_value_or_count, S, T) where: + - cut_value_or_count is the raw capacity (return_raw_data=True) or number of switches (False), @@ - cut_value, (S, T) = nx.minimum_cut(self.G, self.source, self.sink, capacity="capacity") # noqa: N806 + cut_value, (S, T) = nx.minimum_cut(self.G, self.source, self.sink, capacity="capacity")
73-90: Docstring must reflect bidirectional edge behavior.add_edge_with_capacity() says it adds “a directed edge”, yet with bidirectional=True (the default) it installs both u→v and v→u and also accepts an
edge_typelabel. Please update the docstring (and ideally the summary line) so call sites know the method creates reciprocal edges unless they explicitly pass bidirectional=False.- """Add a directed edge with specified capacity between two nodes. + """Add edges with specified capacity between two nodes. @@ capacity : float Edge capacity. + edge_type : str, optional + Edge category stored on the graph (default "temporal"). + bidirectional : bool, optional + If True (default), adds both u→v and v→u with the same capacity and edge_type. + If False, adds only the directed edge u→v.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (1)
src/mqt/qecc/circuit_compilation/code_switching_compiler.py(1 hunks)
🧰 Additional context used
🪛 Ruff (0.14.3)
src/mqt/qecc/circuit_compilation/code_switching_compiler.py
74-74: Boolean-typed positional argument in function definition
(FBT001)
74-74: Boolean default positional argument in function definition
(FBT002)
91-91: Boolean-typed positional argument in function definition
(FBT001)
91-91: Boolean default positional argument in function definition
(FBT002)
104-104: Boolean-typed positional argument in function definition
(FBT001)
104-104: Boolean default positional argument in function definition
(FBT002)
157-157: Boolean-typed positional argument in function definition
(FBT001)
157-157: Boolean default positional argument in function definition
(FBT002)
224-224: Boolean-typed positional argument in function definition
(FBT001)
224-224: Boolean default positional argument in function definition
(FBT002)
225-225: Boolean-typed positional argument in function definition
(FBT001)
225-225: Boolean default positional argument in function definition
(FBT002)
226-226: Boolean-typed positional argument in function definition
(FBT001)
226-226: Boolean default positional argument in function definition
(FBT002)
284-284: Boolean-typed positional argument in function definition
(FBT001)
284-284: Boolean default positional argument in function definition
(FBT002)
295-295: Unused noqa directive (non-enabled: N806)
Remove unused noqa directive
(RUF100)
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: 🐍 Test (windows-2022) / 🐍 windows-2022
- GitHub Check: 🐍 Test (macos-15-intel) / 🐍 macos-15-intel
- GitHub Check: 🐍 Test (ubuntu-24.04) / 🐍 ubuntu-24.04
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (8)
src/mqt/qecc/circuit_compilation/code_switching_compiler.py (8)
26-33: Fix class docstring to reflect actual code anchors.The docstring still claims T/CNOT attach to the source and H/CNOT to the sink, and mentions a 1.0 default capacity. The implementation anchors T nodes to the sink, H nodes to the source, and uses
DEFAULT_TEMPORAL_EDGE_CAPACITY = 100.0. Please sync the documentation with the code.@@ - - Source (SRC) and sink (SNK) nodes represent two different codes: - * Source-connected nodes (T, CNOT) → operations that can be done transversally in code A. - * Sink-connected nodes (H, CNOT) → operations that can be done transversally in code B. + - Source (SRC) and sink (SNK) nodes represent two different codes: + * Source-connected nodes (H) → operations that can be done transversally in the 2D Color Code. + * Sink-connected nodes (T) → operations that can be done transversally in the 3D Surface Code. + * CNOT operations are supported by both codes and remain unanchored. @@ - - Finite-capacity edges (default 1.0) represent potential code transitions along qubit timelines. + - Finite-capacity edges (default 100.0) represent potential code transitions along qubit timelines.
73-90: Document edge_type/bidirectional and clarify bidirectional behavior.
add_edge_with_capacityadds both directions by default and acceptsedge_type, but neither parameter is documented. Please update the docstring and make it clear this method creates reciprocal edges whenbidirectional=True.- def add_edge_with_capacity( - self, u: str, v: str, capacity: float, edge_type: str = "temporal", bidirectional: bool = True - ) -> None: - """Add a directed edge with specified capacity between two nodes. + def add_edge_with_capacity( + self, u: str, v: str, capacity: float, edge_type: str = "temporal", bidirectional: bool = True + ) -> None: + """Add an edge (optionally bidirectional) with specified capacity between two nodes. @@ capacity : float Edge capacity. + edge_type : str, optional + Label describing the edge category (e.g., "temporal", "entangling", "unary"). Default is "temporal". + bidirectional : bool, optional + If True (default), also creates the reverse edge (v→u) with the same capacity and edge_type. + If False, only the edge u→v is added.
91-101: Explain bidirectional semantics for infinite edges.
add_infinite_edgeforwardsbidirectionaltoadd_edge_with_capacity, but the docstring omits it. Documenting this parameter avoids misuse.def add_infinite_edge(self, u: str, v: str, bidirectional: bool = True) -> None: """Add an edge of infinite capacity between two nodes. @@ v : str Target node identifier. + bidirectional : bool, optional + If True (default), also adds the reverse infinite-capacity edge (v→u). If False, only u→v is added.
103-118: Fix default capacity note and document bidirectional flag.
DEFAULT_TEMPORAL_EDGE_CAPACITYis 100.0 andbidirectionalcontrols reverse edges, yet the docstring still states a 1.0 default and omits the flag.def add_regular_edge( self, u: str, v: str, capacity: float = DEFAULT_TEMPORAL_EDGE_CAPACITY, bidirectional: bool = True ) -> None: """Add a regular (finite-capacity) directed edge. @@ capacity : float, optional - Edge capacity (default is 1.0). + Edge capacity (default is 100.0). + bidirectional : bool, optional + If True (default), also adds the reverse edge (v→u) with the same capacity.
119-132: Correctadd_bias_edgesparameter docs.The docstring lists only
biased_code(wrongly typed as float) and omitsnode_id. Please match the signature and explain the string options.- def add_bias_edges(self, node_id: str, biased_code: str = "SRC") -> None: - """Add biased_code unary edges to the terminal nodes slightly preferring one code over the other. + def add_bias_edges(self, node_id: str, biased_code: str = "SRC") -> None: + """Add unary edges to bias a node toward one code or the other. @@ - biased_code : float - Capacity of the biased_code edges to be added. + node_id : str + Node identifier receiving the bias edges. + biased_code : str, optional + Which code to favor. Use "SRC" (default) to bias toward the source/2D Color Code, + or "SNK" to bias toward the sink/3D Surface Code.
150-155: Align inline comments with actual anchoring behavior.These comments say the source handles T and the sink handles H, but the implementation (and surrounding docstring) do the opposite. Please update the comments to avoid misleading future maintainers.
- # Source code can perform T and CNOT gates + # Sink code anchors T gates @@ - # Sink code can perform H and CNOT gates + # Source code anchors H gates
157-167: Documentone_way_transversal_cnot.This flag changes the topology (unidirectional vs bidirectional edges) yet the docstring never mentions it. Add a brief description so callers know when to enable it.
def add_cnot_links(self, control_node: str, target_node: str, one_way_transversal_cnot: bool = False) -> None: """Add bidirectional infinite-capacity edges between two CNOT-related nodes to enforce that both qubits remain in the same code. @@ target_node : str Node representing the target qubit's CNOT operation. + one_way_transversal_cnot : bool, optional + If True, add only the control→target edge (one-way transversal CNOT). If False (default), + add edges in both directions to keep the qubits in the same code.
284-311: Aligncompute_min_cutsignature/docs with behavior and drop unused noqa.
return_raw_dataisn’t documented, the return type changes between raw/processed modes, and the# noqais redundant. Please update the signature, docstring, and remove the directive.- def compute_min_cut(self, return_raw_data: bool = False) -> tuple[float, set[str], set[str]]: + def compute_min_cut(self, return_raw_data: bool = False) -> tuple[float | int, set[str], set[str]]: """Compute the minimum s-t cut between the source and sink. + Parameters + ---------- + return_raw_data : bool, optional + If True, return the raw min-cut capacity from NetworkX (float). + If False (default), return the number of temporal/entangling edges crossing the cut (int). + Returns: ------- - Tuple[float, Set[str], Set[str]] - A tuple (cut_value, S, T) where: - - cut_value is the total capacity of the minimum cut, + tuple[float | int, set[str], set[str]] + A tuple (cut_value, S, T) where: + - cut_value is either the raw cut capacity (return_raw_data=True) or the number of switches (return_raw_data=False), - S is the set of nodes reachable from the source, - T is the complementary set of nodes. """ - cut_value, (S, T) = nx.minimum_cut(self.G, self.source, self.sink, capacity="capacity") # noqa: N806 + cut_value, (S, T) = nx.minimum_cut(self.G, self.source, self.sink, capacity="capacity")
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (1)
src/mqt/qecc/circuit_compilation/code_switching_compiler.py(1 hunks)
🧰 Additional context used
🪛 Ruff (0.14.3)
src/mqt/qecc/circuit_compilation/code_switching_compiler.py
74-74: Boolean-typed positional argument in function definition
(FBT001)
74-74: Boolean default positional argument in function definition
(FBT002)
91-91: Boolean-typed positional argument in function definition
(FBT001)
91-91: Boolean default positional argument in function definition
(FBT002)
104-104: Boolean-typed positional argument in function definition
(FBT001)
104-104: Boolean default positional argument in function definition
(FBT002)
157-157: Boolean-typed positional argument in function definition
(FBT001)
157-157: Boolean default positional argument in function definition
(FBT002)
224-224: Boolean-typed positional argument in function definition
(FBT001)
224-224: Boolean default positional argument in function definition
(FBT002)
225-225: Boolean-typed positional argument in function definition
(FBT001)
225-225: Boolean default positional argument in function definition
(FBT002)
226-226: Boolean-typed positional argument in function definition
(FBT001)
226-226: Boolean default positional argument in function definition
(FBT002)
284-284: Boolean-typed positional argument in function definition
(FBT001)
284-284: Boolean default positional argument in function definition
(FBT002)
295-295: Unused noqa directive (non-enabled: N806)
Remove unused noqa directive
(RUF100)
prior every edge with nodes in different codes were counted but this included one-way
This reverts commit 73ffd1c.
now infinite edges are of type "fixed" and won't be count
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
♻️ Duplicate comments (2)
src/mqt/qecc/circuit_compilation/code_switching_compiler.py (2)
120-121: Specify the default capacity value in the docstring.The docstring for the
capacityparameter doesn't mention its default value, making it unclear to users what capacity will be used if not specified.Apply this diff:
capacity : float, optional - Edge capacity. + Edge capacity (default is 100.0).
127-140: Fix parameter documentation: wrong type and missing parameter.The docstring has two critical issues:
biased_codeis documented asfloatbut the signature shows it'sstrwith default"SRC"- The
node_idparameter is completely missing from the docstring- The description "Capacity of the biased_code edges" is confusing—it should describe which code to bias toward
Apply this diff:
"""Add biased_code unary edges to the terminal nodes slightly preferring one code over the other. Parameters ---------- - biased_code : float - Capacity of the biased_code edges to be added. + node_id : str + Node identifier to which bias edges will be added. + biased_code : str, optional + Which code to bias toward: "SRC" (source/2D Color Code) or "SNK" (sink/3D Surface Code). + Default is "SRC". """
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (1)
src/mqt/qecc/circuit_compilation/code_switching_compiler.py(1 hunks)
🧰 Additional context used
🪛 Ruff (0.14.3)
src/mqt/qecc/circuit_compilation/code_switching_compiler.py
74-74: Boolean-typed positional argument in function definition
(FBT001)
74-74: Boolean default positional argument in function definition
(FBT002)
95-95: Boolean-typed positional argument in function definition
(FBT001)
95-95: Boolean default positional argument in function definition
(FBT002)
110-110: Boolean-typed positional argument in function definition
(FBT001)
110-110: Boolean default positional argument in function definition
(FBT002)
165-165: Boolean-typed positional argument in function definition
(FBT001)
165-165: Boolean default positional argument in function definition
(FBT002)
234-234: Boolean-typed positional argument in function definition
(FBT001)
234-234: Boolean default positional argument in function definition
(FBT002)
235-235: Boolean-typed positional argument in function definition
(FBT001)
235-235: Boolean default positional argument in function definition
(FBT002)
236-236: Boolean-typed positional argument in function definition
(FBT001)
236-236: Boolean default positional argument in function definition
(FBT002)
297-297: Boolean-typed positional argument in function definition
(FBT001)
297-297: Boolean default positional argument in function definition
(FBT002)
308-308: Unused noqa directive (non-enabled: N806)
Remove unused noqa directive
(RUF100)
now we can add to a given qiskit circuit the switching operations as placeholder operations with a given depth to simulate how much switching operations increase circuit depth
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 8
♻️ Duplicate comments (8)
tests/code_switching/test_code_switching_compilation.py (3)
45-45: Remove unusednoqadirective.Ruff flags
# noqa: N806as unused (RUF100) because the N806 rule is not enabled.- N = 100 # noqa: N806 + N = 100
65-67: Remove unusednoqadirective.Ruff flags
# noqa: SLF001as unused (RUF100) because the SLF001 rule is not enabled.- eff_cap = simple_graph._edge_capacity_with_idle_bonus( # noqa: SLF001 + eff_cap = simple_graph._edge_capacity_with_idle_bonus(
75-75: Remove unusednoqadirective.Ruff flags
# noqa: N806as unused (RUF100) because the N806 rule is not enabled.- huge_N = 1_000_000 # noqa: N806 + huge_N = 1_000_000src/mqt/qecc/code_switching/code_switching_compiler.py (5)
187-205: Fix incorrect parameter type in docstring.The docstring states
biased_code : floatbut the parameter isstr | None. Additionally, invalidbiased_codevalues are silently ignored.def _add_bias_edges(self, node_id: str, biased_code: str | None = None) -> None: - """Add biased_code bias edges to the terminal nodes slightly preferring one code over the other. + """Add bias edges to terminal nodes, slightly preferring one code over the other. Parameters ---------- - biased_code : float - Capacity of the biased_code edges to be added. + biased_code : str | None, optional + Which code to bias towards ("SRC" or "SNK"). Defaults to config.biased_code. """
239-265: Docstring is missingtotal_edgesparameter description.Parameters ---------- depths : list[int] The ordered list of depth indices for a given qubit's gates. + total_edges : int + Total count of temporal edges in the circuit, used for normalization. base_capacity : float, optional The default temporal edge capacity.
319-339: Incomplete docstring for_process_gate_operation.The Parameters section only documents
nodeanddepth, but the method has 10 parameters. Since this is a private helper, consider either documenting all parameters or removing the incomplete stub.def _process_gate_operation( self, node: DAGOpNode, depth: int, circuit: QuantumCircuit, qubit_activity: dict[int, list[int]], qubit_last_node: list[str | None], one_way_gates: dict[str, tuple[str, str]], code_bias: bool, idle_bonus: bool, total_temporal_edges: int, ) -> None: - """Handle node creation, temporal edges, and code constraints for a single gate. - - Parameters. - ---------- - node : DAGOpNode - The gate operation node from the DAG. - depth : int - The depth (layer index) of the operation in the circuit. - """ + """Handle node creation, temporal edges, and code constraints for a single gate."""
427-427: Remove unusednoqadirective.Ruff flags
# noqa: N806as unused (RUF100).- _, (S, T) = nx.minimum_cut(self.G, self.source, self.sink, capacity="capacity") # noqa: N806 + _, (S, T) = nx.minimum_cut(self.G, self.source, self.sink, capacity="capacity")
431-431: Remove unusednoqadirective.Ruff flags
# noqa: N803as unused (RUF100).- def _extract_switch_locations(self, S: set[str], T: set[str]) -> tuple[int, list[tuple[int, int]]]: # noqa: N803 + def _extract_switch_locations(self, S: set[str], T: set[str]) -> tuple[int, list[tuple[int, int]]]:
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (3)
docs/CodeSwitching.md(1 hunks)src/mqt/qecc/code_switching/code_switching_compiler.py(1 hunks)tests/code_switching/test_code_switching_compilation.py(1 hunks)
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: burgholzer
Repo: munich-quantum-toolkit/yaqs PR: 212
File: CHANGELOG.md:12-15
Timestamp: 2025-10-14T14:37:38.047Z
Learning: In the munich-quantum-toolkit/yaqs project, changelog entries follow the template: "- $TITLE ([#$NUMBER]($URL)) ([**AUTHOR**](https://github.com/$AUTHOR))". Issue references should not be included in changelog entries; the PR number is sufficient for traceability.
📚 Learning: 2025-11-24T10:19:41.147Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/core PR: 1326
File: python/mqt/core/__init__.py:22-22
Timestamp: 2025-11-24T10:19:41.147Z
Learning: In the munich-quantum-toolkit/core repository, Ruff is configured with 'ALL' rules enabled by default, and only specific rules are selectively disabled. When reviewing changes that enable previously-disabled rules (like PLC0415), noqa directives for those rules become necessary and should be retained.
Applied to files:
tests/code_switching/test_code_switching_compilation.pysrc/mqt/qecc/code_switching/code_switching_compiler.py
📚 Learning: 2025-11-27T21:26:39.677Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/qmap PR: 846
File: python/mqt/qmap/plugins/qiskit/sc/load_calibration.py:34-34
Timestamp: 2025-11-27T21:26:39.677Z
Learning: In the qmap project, the Ruff linter has the "PL" (pylint) rule category enabled, which includes PLC0415 (import-outside-top-level). Therefore, `# noqa: PLC0415` directives on lazy imports are appropriate and necessary, not unused.
Applied to files:
tests/code_switching/test_code_switching_compilation.pysrc/mqt/qecc/code_switching/code_switching_compiler.py
🪛 LanguageTool
docs/CodeSwitching.md
[grammar] ~106-~106: Please add a punctuation mark at the end of paragraph.
Context: ...de and the target qubit in the 2D color code To account for this, we can can pass a...
(PUNCTUATION_PARAGRAPH_END)
[grammar] ~108-~108: Ensure spelling is correct
Context: ...g gates that can be implemented one-way transverally together with their direction. To see h...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
[grammar] ~153-~153: Ensure spelling is correct
Context: ...ch that switching operations are placed preferribly on idling qubits while keeping the tota...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
🪛 Ruff (0.14.7)
tests/code_switching/test_code_switching_compilation.py
45-45: Unused noqa directive (non-enabled: N806)
Remove unused noqa directive
(RUF100)
65-65: Unused noqa directive (non-enabled: SLF001)
Remove unused noqa directive
(RUF100)
75-75: Unused noqa directive (non-enabled: N806)
Remove unused noqa directive
(RUF100)
src/mqt/qecc/code_switching/code_switching_compiler.py
327-327: Boolean-typed positional argument in function definition
(FBT001)
328-328: Boolean-typed positional argument in function definition
(FBT001)
367-367: Boolean-typed positional argument in function definition
(FBT001)
427-427: Unused noqa directive (non-enabled: N806)
Remove unused noqa directive
(RUF100)
431-431: Unused noqa directive (non-enabled: N803)
Remove unused noqa directive
(RUF100)
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: 🐍 Test (ubuntu-24.04) / 🐍 ubuntu-24.04
- GitHub Check: 🐍 Test (windows-2022) / 🐍 windows-2022
- GitHub Check: 🐍 Test (ubuntu-24.04-arm) / 🐍 ubuntu-24.04-arm
🔇 Additional comments (8)
tests/code_switching/test_code_switching_compilation.py (3)
41-81: Test logic is sound; float comparisons are appropriately handled.The test correctly uses:
- Exact equality for
0.0comparisons (lines 48, 51) — safe because zero is exactly representable in IEEE 754pytest.approxfor non-zero float comparisons (lines 62, 70)The test coverage for idle bonus logic is thorough, including edge cases (short idle, active bonus, large graph scaling).
87-151: Integration tests provide solid coverage of min-cut behavior.The tests exercise:
- Forced switches (H→T pattern)
- No switches needed (same-code gates)
- One-way transversal gates with direction tuples
- Invariance of one-way transversal behavior across source/sink swaps
The assertions on
num_switchesandswitch_poscorrectly validate the expected min-cut results.
153-175: Code bias test validates configuration-driven behavior.The test demonstrates that
CompilerConfig(biased_code="SNK")correctly shifts switch positions compared to the default source bias. The assertionswitch_pos_sink_bias != switch_pos_source_biasalong with the specific position check ensures the bias mechanism works as intended.docs/CodeSwitching.md (1)
9-34: Documentation is well-structured and explains the min-cut model clearly.The introduction effectively motivates code switching and explains the graph-based formulation. The node/edge semantics are clearly defined.
src/mqt/qecc/code_switching/code_switching_compiler.py (4)
26-34: CompilerConfig dataclass is well-designed.The configuration parameters are sensibly typed with reasonable defaults. The dataclass approach provides clean initialization and immutability.
362-403: Code constraint logic is well-structured.The method correctly handles:
- Source-unique gates (infinite edge to source)
- Sink-unique gates (infinite edge to sink)
- Common gates with multi-qubit handling and optional one-way transversal direction
- Code bias edges for common gates
405-413: Good input validation in_parse_one_way_direction.The static method validates the direction tuple and raises a clear
ValueErrorfor invalid inputs, preventing silent failures.
69-91: Initialization and graph setup look good.The constructor properly initializes the graph with source/sink nodes and computes common gates. The
base_unary_capacitycalculation correctly combines the configuration parameters.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
♻️ Duplicate comments (8)
tests/code_switching/test_code_switching_compilation.py (3)
45-45: Remove unusednoqadirective.Ruff flags
# noqa: N806as unused (RUF100) because the N806 rule is not enabled.- N = 100 # noqa: N806 + N = 100
65-67: Remove unusednoqadirective.Ruff flags
# noqa: SLF001as unused (RUF100) because the SLF001 rule is not enabled.- eff_cap = simple_graph._edge_capacity_with_idle_bonus( # noqa: SLF001 + eff_cap = simple_graph._edge_capacity_with_idle_bonus( depths=[0, 10], total_edges=N, base_capacity=base_cap )
75-75: Remove unusednoqadirective.Ruff flags
# noqa: N806as unused (RUF100) because the N806 rule is not enabled.- huge_N = 1_000_000 # noqa: N806 + huge_N = 1_000_000src/mqt/qecc/code_switching/code_switching_compiler.py (5)
427-427: Remove unusednoqadirective.Ruff flags
# noqa: N806as unused (RUF100).- _, (S, T) = nx.minimum_cut(self.G, self.source, self.sink, capacity="capacity") # noqa: N806 + _, (S, T) = nx.minimum_cut(self.G, self.source, self.sink, capacity="capacity")
431-431: Remove unusednoqadirective.Ruff flags
# noqa: N803as unused (RUF100).- def _extract_switch_locations(self, S: set[str], T: set[str]) -> tuple[int, list[tuple[int, int]]]: # noqa: N803 + def _extract_switch_locations(self, S: set[str], T: set[str]) -> tuple[int, list[tuple[int, int]]]:
239-265: Docstring missingtotal_edgesparameter.The
total_edgesparameter is not documented in the docstring.Parameters ---------- depths : list[int] The ordered list of depth indices for a given qubit's gates. + total_edges : int + The total count of temporal edges in the circuit, used for normalization. base_capacity : float, optional The default temporal edge capacity.
319-339: Incomplete docstring for private helper.The docstring only documents
nodeanddepth, but the method has 10 parameters. Since this is a private helper, consider either completing the documentation or simplifying to a one-line summary.def _process_gate_operation( ... ) -> None: - """Handle node creation, temporal edges, and code constraints for a single gate. - - Parameters. - ---------- - node : DAGOpNode - The gate operation node from the DAG. - depth : int - The depth (layer index) of the operation in the circuit. - """ + """Handle node creation, temporal edges, and code constraints for a single gate."""
187-205: Docstring has incorrect parameter type.The docstring states
biased_code : floatbut the parameter isstr | None. Additionally, invalid values are silently ignored.def _add_bias_edges(self, node_id: str, biased_code: str | None = None) -> None: - """Add biased_code bias edges to the terminal nodes slightly preferring one code over the other. + """Add bias edges to the terminal nodes slightly preferring one code over the other. Parameters ---------- - biased_code : float - Capacity of the biased_code edges to be added. + biased_code : str, optional + Which code to bias towards ("SRC" or "SNK"). Defaults to config.biased_code. """
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (3)
docs/CodeSwitching.md(1 hunks)src/mqt/qecc/code_switching/code_switching_compiler.py(1 hunks)tests/code_switching/test_code_switching_compilation.py(1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-11-24T10:19:41.147Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/core PR: 1326
File: python/mqt/core/__init__.py:22-22
Timestamp: 2025-11-24T10:19:41.147Z
Learning: In the munich-quantum-toolkit/core repository, Ruff is configured with 'ALL' rules enabled by default, and only specific rules are selectively disabled. When reviewing changes that enable previously-disabled rules (like PLC0415), noqa directives for those rules become necessary and should be retained.
Applied to files:
tests/code_switching/test_code_switching_compilation.pysrc/mqt/qecc/code_switching/code_switching_compiler.py
📚 Learning: 2025-11-27T21:26:39.677Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/qmap PR: 846
File: python/mqt/qmap/plugins/qiskit/sc/load_calibration.py:34-34
Timestamp: 2025-11-27T21:26:39.677Z
Learning: In the qmap project, the Ruff linter has the "PL" (pylint) rule category enabled, which includes PLC0415 (import-outside-top-level). Therefore, `# noqa: PLC0415` directives on lazy imports are appropriate and necessary, not unused.
Applied to files:
tests/code_switching/test_code_switching_compilation.pysrc/mqt/qecc/code_switching/code_switching_compiler.py
🧬 Code graph analysis (2)
tests/code_switching/test_code_switching_compilation.py (1)
src/mqt/qecc/code_switching/code_switching_compiler.py (6)
CompilerConfig(27-33)parse_node_id(466-473)compute_idle_bonus(206-237)_edge_capacity_with_idle_bonus(239-265)build_from_qiskit(267-317)compute_min_cut(415-429)
src/mqt/qecc/code_switching/code_switching_compiler.py (1)
src/mqt/qecc/circuit_synthesis/circuits.py (2)
depth(333-344)num_qubits(250-257)
🪛 LanguageTool
docs/CodeSwitching.md
[grammar] ~106-~106: Please add a punctuation mark at the end of paragraph.
Context: ...de and the target qubit in the 2D color code To account for this, we can can pass a...
(PUNCTUATION_PARAGRAPH_END)
[grammar] ~108-~108: Ensure spelling is correct
Context: ...g gates that can be implemented one-way transverally together with their direction. To see h...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
[grammar] ~153-~153: Ensure spelling is correct
Context: ...ch that switching operations are placed preferribly on idling qubits while keeping the tota...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
🪛 Ruff (0.14.7)
tests/code_switching/test_code_switching_compilation.py
45-45: Unused noqa directive (non-enabled: N806)
Remove unused noqa directive
(RUF100)
65-65: Unused noqa directive (non-enabled: SLF001)
Remove unused noqa directive
(RUF100)
75-75: Unused noqa directive (non-enabled: N806)
Remove unused noqa directive
(RUF100)
src/mqt/qecc/code_switching/code_switching_compiler.py
327-327: Boolean-typed positional argument in function definition
(FBT001)
328-328: Boolean-typed positional argument in function definition
(FBT001)
367-367: Boolean-typed positional argument in function definition
(FBT001)
427-427: Unused noqa directive (non-enabled: N806)
Remove unused noqa directive
(RUF100)
431-431: Unused noqa directive (non-enabled: N803)
Remove unused noqa directive
(RUF100)
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: 🐍 Test (ubuntu-24.04-arm) / 🐍 ubuntu-24.04-arm
🔇 Additional comments (10)
tests/code_switching/test_code_switching_compilation.py (7)
1-16: Imports and license header look correct.The imports properly reference the public API surface (
MinimalCodeSwitchingCompilerfrommqt.qecc.code_switching) andCompilerConfigfrom the internal module.
19-24: Fixture is well-designed.The
simple_graphfixture provides a reusable compiler instance with gate sets matching the documented 2D/3D color code example.
31-38: LGTM!Good coverage testing both valid parsing and the error case for invalid node IDs.
87-103: Good integration test for mandatory switching.Tests the fundamental case where H (source-only) followed by T (sink-only) requires exactly one switch.
105-118: LGTM!Correctly verifies that circuits staying within a single code (H, CX) require no switches.
121-150: Comprehensive one-way transversal testing.Good coverage of:
- Default behavior requiring a switch
- One-way gate enabling zero switches
- Invariance when swapping source/sink definitions
153-175: Code bias test is well-structured.Verifies that changing
biased_codefrom "SRC" to "SNK" shifts the switch position as expected.src/mqt/qecc/code_switching/code_switching_compiler.py (3)
1-23: Imports and module setup look good.Clean separation of runtime imports and TYPE_CHECKING-only imports. The regex pattern is appropriately compiled at module level for performance.
69-86: Constructor is well-structured.Proper initialization of the graph with source/sink nodes and computation of base capacity from configuration.
36-67: **Class docstring and structure are well-designed.**The comprehensive docstring explains the graph model well. "For each edge (u, v) in R, R[u][v]['capacity'] is equal to the capacity of (u, v) in G if it exists in G or zero otherwise." The implementation correctly ensures non-negative capacities viamax(0.0, ...)in_edge_capacity_with_idle_bonus(line 265), which aligns with NetworkX's expectations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (7)
docs/CodeSwitching.md (7)
104-108: Fix grammar, punctuation, and spelling issues.Three issues flagged by static analysis:
- Line 106: Missing period at end of paragraph
- Line 108: Duplicated word "can can"
- Line 108: Spelling error "transverally" → "transversally"
Under specific conditions, CNOT operations can be implemented transversally even when the control and target qubits are encoded in different codes. This property, however, is directional. In the 2D-3D color code scheme, it holds only when the -control qubit is encoded in the 3D color code and the target qubit in the 2D color code +control qubit is encoded in the 3D color code and the target qubit in the 2D color code. -To account for this, we can can pass a dictionary specifying gates that can be implemented one-way transverally together with their direction. +To account for this, we can pass a dictionary specifying gates that can be implemented one-way transversally together with their direction.
137-145: Fix undefined variable in loop (second of 6 occurrences).Same issue as lines 125-133: iterate over
switch_posinstead ofpositions.mcsc = MinimalCodeSwitchingCompiler({"H", "CX"}, {"T", "CX"}) mcsc.build_from_qiskit(qc, one_way_gates={"CX": ("SNK", "SRC")}) num_switches, switch_pos, _, _ = mcsc.compute_min_cut() print(f"Total switches required (without one-way CNOT): {num_switches}") print("Switch locations (qubit, depth):") -for pos in positions: +for pos in switch_pos: print(f" - Qubit {pos[0]} after operation depth {pos[1]}")
151-154: Fix spelling error "preferribly" → "preferably".-- **Depth Optimization:** Choosing the positions of the switching positions such that switching operations are placed preferribly on idling qubits while keeping the total number of switches minimal. This has the potential to reduce the overall circuit depth increase caused by the switching operations. +- **Depth Optimization:** Choosing the positions of the switching positions such that switching operations are placed preferably on idling qubits while keeping the total number of switches minimal. This has the potential to reduce the overall circuit depth increase caused by the switching operations.
176-184: Fix undefined variable in loop (third of 6 occurrences).Same issue: iterate over
switch_posinstead ofpositions.mcsc = MinimalCodeSwitchingCompiler({"H", "CX"}, {"T", "CX"}) mcsc.build_from_qiskit(qc, one_way_gates={"CX": ("SNK", "SRC")}) num_switches, switch_pos, _, _ = mcsc.compute_min_cut() print(f"Total switches required (without one-way CNOT): {num_switches}") print("Switch locations (qubit, depth):") -for pos in positions: +for pos in switch_pos: print(f" - Qubit {pos[0]} after operation depth {pos[1]}")
188-196: Fix undefined variable in loop (fourth of 6 occurrences).Same issue: iterate over
switch_posinstead ofpositions.mcsc = MinimalCodeSwitchingCompiler({"H", "CX"}, {"T", "CX"}) mcsc.build_from_qiskit(qc, one_way_gates={"CX": ("SNK", "SRC")}, idle_bonus=True) num_switches, switch_pos, _, _ = mcsc.compute_min_cut() print(f"Total switches required (without one-way CNOT): {num_switches}") print("Switch locations (qubit, depth):") -for pos in positions: +for pos in switch_pos: print(f" - Qubit {pos[0]} after operation depth {pos[1]}")
216-224: Fix undefined variable in loop (fifth of 6 occurrences).Same issue: iterate over
switch_posinstead ofpositions.mcsc = MinimalCodeSwitchingCompiler({"H", "CX"}, {"T", "CX"}) mcsc.build_from_qiskit(qc, one_way_gates={"CX": ("SNK", "SRC")}) num_switches, switch_pos, _, _ = mcsc.compute_min_cut() print(f"Total switches required (without one-way CNOT): {num_switches}") print("Switch locations (qubit, depth):") -for pos in positions: +for pos in switch_pos: print(f" - Qubit {pos[0]} after operation depth {pos[1]}")
228-237: Fix undefined variable in loop (sixth of 6 occurrences).Same issue: iterate over
switch_posinstead ofpositions.config = CompilerConfig(biased_code="SNK") mcsc = MinimalCodeSwitchingCompiler({"H", "CX"}, {"T", "CX"}, config=config) mcsc.build_from_qiskit(qc, one_way_gates={"CX": ("SNK", "SRC")}, code_bias=True) num_switches, switch_pos, _, _ = mcsc.compute_min_cut() print(f"Total switches required (without one-way CNOT): {num_switches}") print("Switch locations (qubit, depth):") -for pos in positions: +for pos in switch_pos: print(f" - Qubit {pos[0]} after operation depth {pos[1]}")
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (1)
docs/CodeSwitching.md(1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-12-02T07:37:46.860Z
Learnt from: MatthiasReumann
Repo: munich-quantum-toolkit/core PR: 1301
File: mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/NaiveRoutingPass.cpp:144-151
Timestamp: 2025-12-02T07:37:46.860Z
Learning: In MLIR transformation code (mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/NaiveRoutingPass.cpp and similar), when inserting operations before a target operation, prefer `rewriter.setInsertionPoint(op)` over `rewriter.setInsertionPointAfter(op->getPrevNode())`. The former is cleaner, avoids null pointer edge cases (when op is first in block), and is semantically clearer.
Applied to files:
docs/CodeSwitching.md
🪛 LanguageTool
docs/CodeSwitching.md
[grammar] ~106-~106: Please add a punctuation mark at the end of paragraph.
Context: ...de and the target qubit in the 2D color code To account for this, we can can pass a...
(PUNCTUATION_PARAGRAPH_END)
[grammar] ~108-~108: Ensure spelling is correct
Context: ...g gates that can be implemented one-way transverally together with their direction. To see h...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
[grammar] ~153-~153: Ensure spelling is correct
Context: ...ch that switching operations are placed preferribly on idling qubits while keeping the tota...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: 🐍 Test (ubuntu-24.04-arm) / 🐍 ubuntu-24.04-arm
- GitHub Check: 🐍 Test (windows-2022) / 🐍 windows-2022
- GitHub Check: 🐍 Test (ubuntu-24.04) / 🐍 ubuntu-24.04
🔇 Additional comments (1)
docs/CodeSwitching.md (1)
125-133: Fix undefined variable in loop (first of 6 occurrences).The code unpacks the min-cut result into
switch_pos(line 128) but the loop iterates overpositions(undefined variable), which will cause aNameErrorat runtime. This same bug appears 5 more times in this file (lines 143, 182, 194, 222, 235).mcsc = MinimalCodeSwitchingCompiler({"H", "CX"}, {"T", "CX"}) mcsc.build_from_qiskit(qc) num_switches, switch_pos, _, _ = mcsc.compute_min_cut() print(f"Total switches required (without one-way CNOT): {num_switches}") print("Switch locations (qubit, depth):") -for pos in positions: +for pos in switch_pos: print(f" - Qubit {pos[0]} after operation depth {pos[1]}")Likely an incorrect or invalid review comment.
pehamTom
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, gonna approve already but would be great if you could look at my comments for the docs.
Overall, nice work!
Co-authored-by: Tom Peham <[email protected]> Signed-off-by: Erik Weilandt <[email protected]>
Co-authored-by: Tom Peham <[email protected]> Signed-off-by: Erik Weilandt <[email protected]>
Co-authored-by: Tom Peham <[email protected]> Signed-off-by: Erik Weilandt <[email protected]>
…uantum-toolkit/qecc into code-switching-compiler
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (7)
docs/CodeSwitching.md (2)
104-105: Fix typo: "transverally" → "transversally".-To account for this, we can pass a dictionary specifying gates that can be implemented one-way transverally together with their direction. +To account for this, we can pass a dictionary specifying gates that can be implemented one-way transversally together with their direction.
154-154: Fix typo: "preferribly" → "preferably".-- **Depth Optimization:** Choosing the placing of the switching positions such that switching operations are placed preferribly on idling qubits while keeping the total number of switches minimal. This has the potential to reduce the overall circuit depth increase caused by the switching operations. +- **Depth Optimization:** Choosing the placement of the switching positions such that switching operations are placed preferably on idling qubits while keeping the total number of switches minimal. This has the potential to reduce the overall circuit depth increase caused by the switching operations.src/mqt/qecc/code_switching/code_switching_compiler.py (5)
26-34: Consider adding validation forbiased_code.The
biased_codefield accepts any string, but only"SRC"or"SNK"are valid values. Invalid values are silently ignored in_add_bias_edges, which could mask configuration errors.@dataclass class CompilerConfig: """Holds all configuration parameters for the MinimalCodeSwitchingCompiler.""" edge_capacity_ratio: float = 0.001 default_temporal_edge_capacity: float = 1.0 switching_time: int = 2 biased_code: str = "SRC" + + def __post_init__(self) -> None: + """Validate configuration parameters.""" + if self.biased_code not in ("SRC", "SNK"): + msg = f"Invalid biased_code: {self.biased_code}. Must be 'SRC' or 'SNK'." + raise ValueError(msg)
187-205: Fix incorrect parameter type in docstring.The docstring states
biased_code : floatbut the parameter type is actuallystr | None.def _add_bias_edges(self, node_id: str, biased_code: str | None = None) -> None: """Add biased_code bias edges to the terminal nodes slightly preferring one code over the other. Parameters ---------- - biased_code : float - Capacity of the biased_code edges to be added. + biased_code : str | None, optional + Which code to bias towards ("SRC" or "SNK"). Defaults to config.biased_code. """
334-342: Incomplete docstring for private helper.The docstring only documents
nodeanddepthbut the method has 10 parameters. Consider either documenting all parameters or simplifying to a single-line docstring for this private helper.def _process_gate_operation( self, node: DAGOpNode, depth: int, circuit: QuantumCircuit, qubit_activity: dict[int, list[int]], qubit_last_node: list[str | None], one_way_gates: dict[str, tuple[str, str]], code_bias: bool, idle_bonus: bool, total_temporal_edges: int, ) -> None: - """Handle node creation, temporal edges, and code constraints for a single gate. - - Parameters. - ---------- - node : DAGOpNode - The gate operation node from the DAG. - depth : int - The depth (layer index) of the operation in the circuit. - """ + """Handle node creation, temporal edges, and code constraints for a single gate."""
454-466: Always extract the earlier node when a temporal edge crosses the cut.The code unconditionally takes node
u(line 464), but when(v in S and u in T),uis the later node in time. This violates the comment's intent to "take the earlier node in time as the insertion point" (line 463). Since bidirectional edges exist and iteration order is not guaranteed, the code can select the wrong node.Extract depths from both endpoints and use the one with lower depth:
if (u in S and v in T) or (v in S and u in T): - # We can take e.g. the 'earlier' node in time as the insertion point - qubit, depth = self.parse_node_id(u) - switch_positions.append((qubit, depth)) + # Take the earlier node (lower depth) as the insertion point + q_u, d_u = self.parse_node_id(u) + q_v, d_v = self.parse_node_id(v) + if d_u <= d_v: + switch_positions.append((q_u, d_u)) + else: + switch_positions.append((q_v, d_v))
430-434: Remove unusednoqadirectives.Ruff flags these
noqadirectives as unused (RUF100) because the N806/N803 rules are not enabled.- _, (S, T) = nx.minimum_cut(self.G, self.source, self.sink, capacity="capacity") # noqa: N806 + _, (S, T) = nx.minimum_cut(self.G, self.source, self.sink, capacity="capacity") num_switches, switch_positions = self._extract_switch_locations(S, T) return num_switches, switch_positions, S, T - def _extract_switch_locations(self, S: set[str], T: set[str]) -> tuple[int, list[tuple[int, int]]]: # noqa: N803 + def _extract_switch_locations(self, S: set[str], T: set[str]) -> tuple[int, list[tuple[int, int]]]:
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (3)
CHANGELOG.md(1 hunks)docs/CodeSwitching.md(1 hunks)src/mqt/qecc/code_switching/code_switching_compiler.py(1 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-12-02T07:37:46.860Z
Learnt from: MatthiasReumann
Repo: munich-quantum-toolkit/core PR: 1301
File: mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/NaiveRoutingPass.cpp:144-151
Timestamp: 2025-12-02T07:37:46.860Z
Learning: In MLIR transformation code (mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/NaiveRoutingPass.cpp and similar), when inserting operations before a target operation, prefer `rewriter.setInsertionPoint(op)` over `rewriter.setInsertionPointAfter(op->getPrevNode())`. The former is cleaner, avoids null pointer edge cases (when op is first in block), and is semantically clearer.
Applied to files:
docs/CodeSwitching.mdsrc/mqt/qecc/code_switching/code_switching_compiler.py
📚 Learning: 2025-11-27T21:26:39.677Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/qmap PR: 846
File: python/mqt/qmap/plugins/qiskit/sc/load_calibration.py:34-34
Timestamp: 2025-11-27T21:26:39.677Z
Learning: In the qmap project, the Ruff linter has the "PL" (pylint) rule category enabled, which includes PLC0415 (import-outside-top-level). Therefore, `# noqa: PLC0415` directives on lazy imports are appropriate and necessary, not unused.
Applied to files:
src/mqt/qecc/code_switching/code_switching_compiler.py
📚 Learning: 2025-11-24T10:19:41.147Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/core PR: 1326
File: python/mqt/core/__init__.py:22-22
Timestamp: 2025-11-24T10:19:41.147Z
Learning: In the munich-quantum-toolkit/core repository, Ruff is configured with 'ALL' rules enabled by default, and only specific rules are selectively disabled. When reviewing changes that enable previously-disabled rules (like PLC0415), noqa directives for those rules become necessary and should be retained.
Applied to files:
src/mqt/qecc/code_switching/code_switching_compiler.py
🧬 Code graph analysis (1)
src/mqt/qecc/code_switching/code_switching_compiler.py (1)
src/mqt/qecc/circuit_synthesis/circuits.py (2)
depth(333-344)num_qubits(250-257)
🪛 LanguageTool
docs/CodeSwitching.md
[grammar] ~104-~104: Ensure spelling is correct
Context: ...g gates that can be implemented one-way transverally together with their direction. To see h...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
[grammar] ~154-~154: Ensure spelling is correct
Context: ...ch that switching operations are placed preferribly on idling qubits while keeping the tota...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
🪛 Ruff (0.14.8)
src/mqt/qecc/code_switching/code_switching_compiler.py
330-330: Boolean-typed positional argument in function definition
(FBT001)
331-331: Boolean-typed positional argument in function definition
(FBT001)
370-370: Boolean-typed positional argument in function definition
(FBT001)
430-430: Unused noqa directive (non-enabled: N806)
Remove unused noqa directive
(RUF100)
434-434: Unused noqa directive (non-enabled: N803)
Remove unused noqa directive
(RUF100)
🔇 Additional comments (1)
src/mqt/qecc/code_switching/code_switching_compiler.py (1)
36-91: LGTM on the class structure and initialization.The
MinimalCodeSwitchingCompilerclass is well-structured with clear separation between graph construction (build_from_qiskit), constraint application (_apply_code_constraints), and analysis (compute_min_cut). The docstring provides comprehensive documentation of the graph model and attributes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 6
🤖 Fix all issues with AI agents
In `@scripts/cs_compiler/run_performance_simulations.sh`:
- Line 9: Remove the leftover commented-out array declaration to reduce clutter:
delete the line containing the commented declaration "# declare -a
n_values=(\"64\" \"128\" \"256\" \"512\")" from the script so the file no longer
contains that unused commented code.
- Around line 1-8: Add shell safety options to the top of
run_performance_simulations.sh: after the shebang (#!/bin/bash) enable strict
error handling by inserting set -euo pipefail and, if needed for portability,
ensure IFS is set (e.g., IFS=$'\n\t') so the script behaves consistently with
run_generate_circuits.sh and fails fast on unset variables, pipeline failures,
or command errors.
- Line 41: The parallel invocation in run_performance_simulations.sh uses $(seq
0 99) which can break under strict shells (set -u) and is less idiomatic;
replace that subshell expansion with a safe, quoted source such as a brace
expansion or a pre-built array and ensure the expansion is quoted in the
parallel command so the third argument list is robust (update the line using
parallel --jobs 5 run_and_simulate ::: "${n_values[@]}" ::: "${distr_types[@]}"
::: $(seq 0 99) to use {0..99} or an explicitly declared array variable instead
of unquoted $(seq ...)).
In `@scripts/cs_compiler/simulate_circuit_performance.py`:
- Around line 98-99: Add a brief inline comment explaining the rationale for the
depth calculation where depth = 2 * args.n (e.g., why the benchmark uses twice
the number of qubits as circuit depth—such as mapping to two layers per qubit,
matched gate layers, or a target entangling + single-qubit layer per qubit);
place the comment next to the assignment of depth (referencing the variables
depth and args.n) so future readers know the performance model assumption behind
the multiplier.
In `@src/mqt/qecc/code_switching/code_switching_compiler.py`:
- Around line 330-331: The parameters code_bias and idle_bonus on the
CodeSwitchingCompiler (or the function where they appear) should be made
keyword-only to avoid boolean positional args; change the signature to place
them after a bare * (or use *, code_bias: bool, idle_bonus: bool) so callers
must use keywords, and update the build_from_qiskit function call site to pass
code_bias=... and idle_bonus=... when invoking the compiler/constructor; ensure
all other call sites use the new keyword form.
In `@src/mqt/qecc/code_switching/compilation_utils.py`:
- Around line 119-124: Validate qubit indices from switch_positions before
grouping: ensure each qidx is an integer within 0 <= qidx < len(circuit.qubits)
and raise a clear ValueError if not (e.g. "Invalid qubit index X; circuit has N
qubits") instead of allowing an IndexError later when accessing circuit.qubits;
perform the same check where you later iterate over placeholders_by_qubit (the
loop that uses q_index to index circuit.qubits) so both the grouping step
(placeholders_by_qubit population) and the subsequent usage validate indices and
fail with a helpful message.
♻️ Duplicate comments (9)
scripts/cs_compiler/generate_random_circuits.py (1)
57-59: Remove unusedlast_gatetracking.
last_gateis assigned on lines 58, 103, and 116 but never read. Onlylast_non_id_gateis used for the back-to-back restriction logic.♻️ Proposed cleanup
- # Track last gate and last non-id single-qubit gate - last_gate = ["id"] * num_qubits + # Track last non-id single-qubit gate to avoid back-to-back repeats last_non_id_gate = ["id"] * num_qubitsAlso remove assignments at lines 103 and 116:
- last_gate[q] = last_gate[target] = "cx"- last_gate[q] = gatescripts/cs_compiler/run_generate_circuits.sh (1)
25-25: Usepython3explicitly for portability.On some systems,
pythonmay not exist or may point to Python 2.- python "${SCRIPT_DIR}/generate_random_circuits.py" --n "$n" --num_circuits "$num_circuits" --distr_type "$distr_type" + python3 "${SCRIPT_DIR}/generate_random_circuits.py" --n "$n" --num_circuits "$num_circuits" --distr_type "$distr_type"scripts/cs_compiler/run_performance_simulations.sh (1)
22-36: Make Python script path independent of working directory.The relative path
simulate_circuit_performance.pyon line 30 will fail if the script is invoked from the repository root rather than thescripts/cs_compiler/directory.🐛 Proposed fix
Add
SCRIPT_DIRresolution after exports and use absolute path:export base_dir export results_dir + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +export SCRIPT_DIR run_and_simulate() { local n=$1 local distr_type=$2 local seed=$3 local qasm_path="${base_dir}/${distr_type}/${n}/${n}_${seed}.qasm" local csv_path="${results_dir}/${distr_type}/results_${n}.csv" - python simulate_circuit_performance.py \ + python3 "${SCRIPT_DIR}/simulate_circuit_performance.py" \ --qasm_path "$qasm_path" \ --n "$n" \ --seed "$seed" \ --output_csv "$csv_path" \ --distr_type "$distr_type" }src/mqt/qecc/code_switching/compilation_utils.py (2)
23-26: Docstring still saysdictbut return type islist[str | None].The Returns section documents
dict: final code assignment per qubit, but the type annotation and implementation returnlist[str | None].📝 Suggested fix
Returns: - int: total number of code switches - dict: final code assignment per qubit + ------- + tuple[int, list[str | None]] + A tuple containing: + - int: total number of code switches + - list[str | None]: final code assignment per qubit (index -> "A", "B", or None)
103-108: Remove staleexpand_placeholderparameter from docstring.The docstring documents
expand_placeholder : bool, optionalat lines 105-108, but this parameter doesn't exist in the function signature.📝 Suggested fix
placeholder_depth : int, optional Virtual depth (single-qubit layers) the placeholder should represent. - expand_placeholder : bool, optional - If True, expand each placeholder into `placeholder_depth` calls to - `QuantumCircuit.id(qubit)` so that `QuantumCircuit.depth()` increases. - If False, append a single `SwitchGate` marker (informational only). Returns:src/mqt/qecc/code_switching/code_switching_compiler.py (4)
187-194: Docstring incorrectly typesbiased_codeasfloat.The docstring says
biased_code : floatbut the parameter is actuallystr | None. The description also doesn't match the parameter's purpose.📝 Suggested fix
def _add_bias_edges(self, node_id: str, biased_code: str | None = None) -> None: """Add biased_code bias edges to the terminal nodes slightly preferring one code over the other. Parameters ---------- - biased_code : float - Capacity of the biased_code edges to be added. + biased_code : str | None, optional + Which code to bias towards ("SRC" or "SNK"). Defaults to config.biased_code. """
462-465: Always extract the earlier node when a temporal edge crosses the cut.The code always takes node
u(line 464), but when(v in S and u in T),uis the later node in time. This contradicts the comment on line 463. Since bidirectional edges exist and iteration order is non-deterministic, the code may select the wrong node.🐛 Proposed fix
if (u in S and v in T) or (v in S and u in T): - # We can take e.g. the 'earlier' node in time as the insertion point - qubit, depth = self.parse_node_id(u) - switch_positions.append((qubit, depth)) + # Take the earlier node (lower depth) as the insertion point + q_u, d_u = self.parse_node_id(u) + q_v, d_v = self.parse_node_id(v) + if d_u <= d_v: + switch_positions.append((q_u, d_u)) + else: + switch_positions.append((q_v, d_v))
26-34: Consider validatingbiased_codeinCompilerConfig.The
biased_codefield only accepts"SRC"or"SNK", but invalid values would be silently ignored in_add_bias_edges. Adding validation provides earlier, clearer error feedback.💡 Suggested validation
`@dataclass` class CompilerConfig: """Holds all configuration parameters for the MinimalCodeSwitchingCompiler.""" edge_capacity_ratio: float = 0.001 default_temporal_edge_capacity: float = 1.0 switching_time: int = 2 biased_code: str = "SRC" + + def __post_init__(self) -> None: + """Validate configuration parameters.""" + if self.biased_code not in ("SRC", "SNK"): + msg = f"Invalid biased_code: {self.biased_code}. Must be 'SRC' or 'SNK'." + raise ValueError(msg)
430-434: Remove unusednoqadirectives.Ruff reports
# noqa: N806(line 430) and# noqa: N803(line 434) as unused since these rules aren't enabled. Based on static analysis hints.📝 Suggested fix
- _, (S, T) = nx.minimum_cut(self.G, self.source, self.sink, capacity="capacity") # noqa: N806 + _, (S, T) = nx.minimum_cut(self.G, self.source, self.sink, capacity="capacity") num_switches, switch_positions = self._extract_switch_locations(S, T) return num_switches, switch_positions, S, T - def _extract_switch_locations(self, S: set[str], T: set[str]) -> tuple[int, list[tuple[int, int]]]: # noqa: N803 + def _extract_switch_locations(self, S: set[str], T: set[str]) -> tuple[int, list[tuple[int, int]]]:
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (9)
CHANGELOG.mdpyproject.tomlscripts/cs_compiler/generate_random_circuits.pyscripts/cs_compiler/run_generate_circuits.shscripts/cs_compiler/run_performance_simulations.shscripts/cs_compiler/simulate_circuit_performance.pysrc/mqt/qecc/code_switching/__init__.pysrc/mqt/qecc/code_switching/code_switching_compiler.pysrc/mqt/qecc/code_switching/compilation_utils.py
🧰 Additional context used
🧠 Learnings (12)
📚 Learning: 2025-10-14T14:37:38.047Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/yaqs PR: 212
File: CHANGELOG.md:12-15
Timestamp: 2025-10-14T14:37:38.047Z
Learning: In the munich-quantum-toolkit/yaqs project, changelog entries follow the template: "- $TITLE ([#$NUMBER]($URL)) ([**AUTHOR**](https://github.com/$AUTHOR))". Issue references should not be included in changelog entries; the PR number is sufficient for traceability.
Applied to files:
CHANGELOG.md
📚 Learning: 2025-12-05T17:45:37.602Z
Learnt from: denialhaag
Repo: munich-quantum-toolkit/core PR: 1360
File: .github/workflows/reusable-mlir-tests.yml:40-43
Timestamp: 2025-12-05T17:45:37.602Z
Learning: In the munich-quantum-toolkit/core repository, patch releases of LLVM dependencies don't require documentation updates, changelog entries, or additional tests beyond what's validated by passing CI checks.
Applied to files:
CHANGELOG.md
📚 Learning: 2025-11-04T15:22:19.558Z
Learnt from: marcelwa
Repo: munich-quantum-toolkit/core PR: 1243
File: test/python/qdmi/qiskit/conftest.py:155-157
Timestamp: 2025-11-04T15:22:19.558Z
Learning: The munich-quantum-toolkit/core repository requires Python 3.10 or later, so Python 3.10+ features (such as `zip(..., strict=...)`, pattern matching, etc.) are acceptable and should not be flagged as compatibility issues.
Applied to files:
pyproject.toml
📚 Learning: 2025-12-13T20:08:45.549Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/qmap PR: 862
File: pyproject.toml:65-66
Timestamp: 2025-12-13T20:08:45.549Z
Learning: In the qmap project (pyproject.toml), maintain broad compatibility with dependencies across supported Python versions. Avoid artificially raising minimum version requirements unless there's a specific need (e.g., to guarantee binary wheel availability for certain Python versions, or to access required features). The goal is to keep the software as broadly compatible as possible with the rest of the ecosystem.
Applied to files:
pyproject.toml
📚 Learning: 2025-11-04T14:26:25.420Z
Learnt from: marcelwa
Repo: munich-quantum-toolkit/core PR: 1243
File: test/python/qdmi/qiskit/conftest.py:11-19
Timestamp: 2025-11-04T14:26:25.420Z
Learning: In the munich-quantum-toolkit/core repository, Qiskit is always available as a dependency during testing, so import guards for qiskit-dependent imports in test files (e.g., test/python/qdmi/qiskit/*.py) are not necessary.
Applied to files:
pyproject.toml
📚 Learning: 2025-12-25T13:28:25.619Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/predictor PR: 526
File: src/mqt/predictor/rl/predictorenv.py:271-271
Timestamp: 2025-12-25T13:28:25.619Z
Learning: In the munich-quantum-toolkit/predictor repository, Ruff is configured with an extensive set of rules including SLF (flake8-self) in the extend-select list. The `# noqa: SLF001` directive for private member access (e.g., `self.state._layout = self.layout` in src/mqt/predictor/rl/predictorenv.py) is necessary and appropriate, even if Ruff reports RUF100 warnings suggesting the directive is unused.
Applied to files:
src/mqt/qecc/code_switching/code_switching_compiler.py
📚 Learning: 2026-01-08T10:07:32.871Z
Learnt from: flowerthrower
Repo: munich-quantum-toolkit/core-plugins-catalyst PR: 20
File: python/mqt/core/plugins/catalyst/device.py:69-69
Timestamp: 2026-01-08T10:07:32.871Z
Learning: In the munich-quantum-toolkit/core-plugins-catalyst repository, Ruff is configured with select = ["ALL"] and only specific rules are disabled. SLF001 (flake8-self - private member access) is enabled, so `# noqa: SLF001` directives are necessary when accessing private attributes like `device._to_matrix_ops` in python/mqt/core/plugins/catalyst/device.py, even if Ruff reports RUF100 warnings suggesting the directive is unused.
Applied to files:
src/mqt/qecc/code_switching/code_switching_compiler.py
📚 Learning: 2026-01-09T16:51:20.555Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/qcec PR: 816
File: python/mqt/qcec/__init__.py:20-20
Timestamp: 2026-01-09T16:51:20.555Z
Learning: In the munich-quantum-toolkit/qcec repository, RUF067 (non-empty-init-module) is a Ruff preview rule introduced in version 0.14.11 that flags non-empty __init__.py files. The `# noqa: RUF067` directive in python/mqt/qcec/__init__.py is necessary and correct to suppress warnings for legitimate code (like the Windows DLL patch).
Applied to files:
src/mqt/qecc/code_switching/code_switching_compiler.py
📚 Learning: 2025-11-27T21:26:39.677Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/qmap PR: 846
File: python/mqt/qmap/plugins/qiskit/sc/load_calibration.py:34-34
Timestamp: 2025-11-27T21:26:39.677Z
Learning: In the qmap project, the Ruff linter has the "PL" (pylint) rule category enabled, which includes PLC0415 (import-outside-top-level). Therefore, `# noqa: PLC0415` directives on lazy imports are appropriate and necessary, not unused.
Applied to files:
src/mqt/qecc/code_switching/code_switching_compiler.py
📚 Learning: 2025-11-24T10:19:41.147Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/core PR: 1326
File: python/mqt/core/__init__.py:22-22
Timestamp: 2025-11-24T10:19:41.147Z
Learning: In the munich-quantum-toolkit/core repository, Ruff is configured with 'ALL' rules enabled by default, and only specific rules are selectively disabled. When reviewing changes that enable previously-disabled rules (like PLC0415), noqa directives for those rules become necessary and should be retained.
Applied to files:
src/mqt/qecc/code_switching/code_switching_compiler.py
📚 Learning: 2025-12-25T13:28:10.402Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/predictor PR: 526
File: tests/compilation/test_predictor_rl.py:225-225
Timestamp: 2025-12-25T13:28:10.402Z
Learning: In the munich-quantum-toolkit/predictor repository, Ruff is configured with the "SLF" (flake8-self) rule category enabled in extend-select. SLF001 (private member access) is active, so `# noqa: SLF001` directives are necessary when accessing private methods/attributes (e.g., `_ensure_device_averages_cached()`), even if Ruff reports RUF100 warnings suggesting the directive is unused.
Applied to files:
src/mqt/qecc/code_switching/code_switching_compiler.py
📚 Learning: 2025-12-14T15:23:54.712Z
Learnt from: flowerthrower
Repo: munich-quantum-toolkit/core-plugins-catalyst PR: 23
File: docs/conf.py:110-130
Timestamp: 2025-12-14T15:23:54.712Z
Learning: In the munich-quantum-toolkit/core-plugins-catalyst repository, the Ruff configuration has 'ALL' rules enabled with only specific rules disabled. PLR6301 (no-self-use) is active, so `# noqa: PLR6301` directives are necessary for methods that don't use self, even if Ruff reports RUF100 warnings suggesting the directive is unused.
Applied to files:
src/mqt/qecc/code_switching/code_switching_compiler.py
🧬 Code graph analysis (4)
scripts/cs_compiler/simulate_circuit_performance.py (3)
src/mqt/qecc/code_switching/code_switching_compiler.py (2)
MinimalCodeSwitchingCompiler(36-476)compute_min_cut(418-432)src/mqt/qecc/code_switching/compilation_utils.py (1)
naive_switching(15-81)src/mqt/qecc/circuit_synthesis/circuits.py (1)
depth(333-344)
src/mqt/qecc/code_switching/compilation_utils.py (1)
src/mqt/qecc/circuit_synthesis/circuits.py (1)
num_qubits(250-257)
src/mqt/qecc/code_switching/__init__.py (2)
src/mqt/qecc/code_switching/code_switching_compiler.py (2)
CompilerConfig(27-33)MinimalCodeSwitchingCompiler(36-476)src/mqt/qecc/code_switching/compilation_utils.py (2)
insert_switch_placeholders(84-170)naive_switching(15-81)
src/mqt/qecc/code_switching/code_switching_compiler.py (1)
src/mqt/qecc/circuit_synthesis/circuits.py (2)
depth(333-344)num_qubits(250-257)
🪛 Ruff (0.14.11)
src/mqt/qecc/code_switching/code_switching_compiler.py
330-330: Boolean-typed positional argument in function definition
(FBT001)
331-331: Boolean-typed positional argument in function definition
(FBT001)
370-370: Boolean-typed positional argument in function definition
(FBT001)
430-430: Unused noqa directive (non-enabled: N806)
Remove unused noqa directive
(RUF100)
434-434: Unused noqa directive (non-enabled: N803)
Remove unused noqa directive
(RUF100)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: 🐍 Test (windows-2022) / 🐍 windows-2022
- GitHub Check: 🐍 Test (macos-14) / 🐍 macos-14
- GitHub Check: 🐍 Test (ubuntu-24.04-arm) / 🐍 ubuntu-24.04-arm
- GitHub Check: 🐍 Test (ubuntu-24.04) / 🐍 ubuntu-24.04
🔇 Additional comments (19)
CHANGELOG.md (2)
50-50: LGTM! Link definitions correctly added.The PR link definition for
[#524](line 50) and the contributor link definition for[**@inctechs**](line 66) have been properly added, resolving the previously identified issue. Both follow the established format and correctly resolve the references in the changelog entry.Also applies to: 66-66
14-14: arXiv link is valid and accessible.The changelog entry includes an inline arXiv reference
[arXiv:2512.04170](https://arxiv.org/abs/2512.04170), which is a novel addition—no other entries in this changelog cite academic papers. The link resolves correctly and provides valuable scholarly context for the new compiler feature.pyproject.toml (2)
67-68: LGTM! NetworkX dependency properly added.The missing runtime dependency has been addressed. The version constraint
>=3.4.2is appropriate for the project's Python 3.10+ requirement.
153-156: Mypy override correctly updated for networkx.The
networkx.*addition to the ignore list aligns with the new dependency and ensures type-checking passes without stub packages.scripts/cs_compiler/generate_random_circuits.py (4)
27-46: LGTM on core function structure.The function signature, docstring, and parameter handling are well-designed. Gate probabilities are properly normalized.
84-105: CX fallback now respects back-to-back restriction.The fix properly filters
fallback_gatesto exclude the last non-ID gate, maintaining the constraint documented in the docstring.
136-144: Gate distribution validation properly implemented.The validation at lines 142-144 provides a clear error message for invalid
gate_distr_typevalues.
174-191: CLI entry point is well-structured.Arguments are clearly documented with sensible defaults. The script correctly wires CLI args to
generate_circuits.scripts/cs_compiler/run_generate_circuits.sh (3)
9-9: Good addition of shell safety options.
set -euo pipefailensures the script fails fast on errors, undefined variables, or pipeline failures.
22-26: Function correctly passes all required arguments.The
distr_typeis now properly forwarded to the Python script, addressing the previous issue.
30-31: Parallel invocation is correctly structured.Array expansion is properly quoted and the Cartesian product of n_values × distr_types is correctly passed to GNU parallel.
src/mqt/qecc/code_switching/__init__.py (1)
1-20: Clean module structure with well-defined public API.The module properly re-exports the compiler and utility functions, with
__all__correctly listing all public symbols. The rename fromcircuit_compilationtocode_switchingaddresses the previous naming concern.scripts/cs_compiler/simulate_circuit_performance.py (3)
1-32: LGTM!The module docstring correctly describes the CLI usage, and imports are properly organized with
TYPE_CHECKINGfor runtime-only imports.
35-43: LGTM!The function correctly creates parent directories before writing (addressing the prior concern) and handles header creation appropriately.
46-56: LGTM!The deduplication logic is correct and handles the non-existent file case appropriately.
src/mqt/qecc/code_switching/compilation_utils.py (1)
143-170: LGTM!The layer iteration, operation copying, and placeholder insertion logic is correct. The handling of out-of-range layer indices by appending at the end is a reasonable fallback.
src/mqt/qecc/code_switching/code_switching_compiler.py (3)
36-91: LGTM!The
MinimalCodeSwitchingCompilerclass is well-documented with clear attribute descriptions. The initialization correctly sets up the graph structure with source/sink nodes.
206-267: LGTM!The idle bonus computation and edge capacity adjustment logic is well-designed. The normalization formula ensures bonuses act as tie-breakers without dominating the min-cut decision.
365-417: LGTM!The
_apply_code_constraintsmethod correctly handles source-unique, sink-unique, and common gates with appropriate infinite edge additions. The one-way direction parsing provides clear validation.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
✅ Actions performedReviews paused. |
|
@coderabbitai pause |
✅ Actions performedReviews paused. |
errors with comments that are resolved but still keep the review from going thorugh
…uantum-toolkit/qecc into code-switching-compiler
Description
Compiler for determining the minimum number of code switching operations.
Checklist: