-
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
Merged
Merged
Changes from 97 commits
Commits
Show all changes
98 commits
Select commit
Hold shift + click to select a range
fe606c4
update git_ignore
inctechs ad9e877
Merge remote-tracking branch 'origin/main' into code-switching-compiler
inctechs 892cba3
add networkx to mypy ignore
inctechs 9d5fdb8
implement first version of min-cut solution
inctechs e5e16fc
add one way transveral CNOTs to be allowed
inctechs bdb5b9b
add edge_type keyword to edges
inctechs 0e9b3cf
change default order of magnitude for temporal edges
inctechs bb33537
add code bias functionality
inctechs 91df0eb
clear/ reorder code
inctechs eee407a
read in QC as dag to support depth and prepare idle switching
inctechs c1d3f52
change qubit activity collection to list instead of set
inctechs adc87f5
make Global default temporal edge weight
inctechs 3bf1bff
add idle bonus calculation and idle switching funcitonality
inctechs 1c7684e
update docstrings and comments
inctechs 73ffd1c
fix counting of switches
inctechs 5b08d68
Revert "fix counting of switches"
inctechs ad6ff67
fix counting of switching operations
inctechs c63e2aa
add placeholder switch operations to qiskit circuit
inctechs 9b5bb38
add extraction of switching position
inctechs 4317cd4
add feature that idle bonus only considered for certain length
inctechs 2c58f77
change return of min-cut function
inctechs 38d1304
add scripts for generating ciruits
inctechs 1914d5b
add function to generate universal random qiskit circuit
inctechs 4b40503
add edge ration
inctechs 796e032
change default folder name of circuit output
inctechs 926fb01
update default number of seeds
inctechs e330bca
add lookahead function
inctechs 4689579
add scripts for performance analysis
inctechs f07cc68
change default number of generated cicuits
inctechs ef3dfd4
remove raw data return form min_cut
inctechs 0ec634d
make lookahead deterministic
inctechs 63c982d
add lookahead to init file
inctechs a5c02dd
change simulations to be gate distribution sensitive
inctechs f99ee41
add feature to avoid generating circuits twice
inctechs 6d9e3ac
add script to generate array with steps of 64
inctechs 1436eb8
add all qubits numbers to performance bash
inctechs 80fbb09
add intermediate results
inctechs a82e97d
add new results
inctechs c0c39ca
update simulations
inctechs d37f0ab
move utils functions to utils file
inctechs a785748
set up code switching compilation test
inctechs 595ecba
Merge remote-tracking branch 'origin/main' into code-switching-compiler
inctechs 4d7b7a1
repair test for idle bonus
inctechs a333e5d
redefine api by making functions private
inctechs 1d90c17
add full function docstring extract switch locations
inctechs 1af4cd8
add one way transversal test
inctechs 82fdcf1
add CompilerConfig for different settings and keep it tidy
inctechs e73f6fc
add CompilerConfig to init
inctechs 5c8f2ec
connect biased code to CompilerConfig
inctechs ffc1375
add code bias test
inctechs 42ae8cf
add test for compilation utils
inctechs 2e4e588
remove dag layer visualization used for debugging previously
inctechs 9f75e39
Merge remote-tracking branch 'origin/main' into code-switching-compiler
inctechs 76a2649
work in CodeRabbitAI code review
inctechs 3c23ca5
fix more CodeRabbitAIs comments
inctechs 0ffd8f1
rename variables in scripts
inctechs 6cb8917
rename class to MinimalCodeSwitchingCompiler
inctechs 2defa2d
generalise Graph construction
inctechs 648fe47
remove unused methods to connect to terminals and connecting CNOTs
inctechs 7e2dd98
fix typo with parameter names
inctechs c8e66ca
add idle bonus calcualtion from the paper
inctechs 2dfb57d
move random circuit generation from utils to scripts
inctechs fe44822
rename naive code switching method and adjust collaterals
inctechs 364550b
remove unnecessary comments
inctechs 85b2d35
move node parser back to graph class
inctechs d9fe652
remove redundancy
inctechs 4afedfb
rename tests for naive switching
inctechs 45a3a97
remove stress test, adapt parsing node test, fix num_switches typo
inctechs 24793dd
improve placeholder test
inctechs ec589b7
remove personal playground folder
inctechs 7415903
add networkx to pyproject.toml
inctechs e5b3beb
automatic reordering by uv
inctechs 30509e0
fix logical error where same back to back gates are allowed
inctechs 85fc4b6
rabbit edits
inctechs e458dae
rename package to code_switching
inctechs 5b529a0
add safe guard for non negative bonus
inctechs a8d3ca2
save uv.lock
inctechs b92b2f7
Merge remote-tracking branch 'origin/main' into code-switching-compiler
inctechs 27060ce
add CodeSwitching docs
inctechs 518d63e
rename unary edges to bias edges
inctechs 364b621
generalise one-way transversal gate definition.
inctechs bd00389
sketch doc structure
inctechs 13d38b8
fix bug in docs
inctechs b71d9b4
fix bug in code cells
inctechs f63fec2
fix typos in the docs
inctechs 3b38882
Merge remote-tracking branch 'origin/main' into code-switching-compiler
inctechs 909c3c6
Update docs/CodeSwitching.md
inctechs dff65bc
Apply suggestions from code review for docs
inctechs e81fe16
Apply suggestions from code review: fix naming of class in docstrings
inctechs 5674e4f
edit Changelog.md
inctechs 9adb064
Merge branch 'code-switching-compiler' of https://github.com/munich-q…
inctechs ed674dc
fix latest coderabbit feedback
inctechs e901ac5
add missing references to changelog
inctechs 2908247
Merge remote-tracking branch 'origin' into code-switching-compiler
inctechs 94f31ea
🎨 pre-commit fixes
pre-commit-ci[bot] 1eb3f39
fix last coderabbit changes
inctechs 7f5b1e5
Merge branch 'code-switching-compiler' of https://github.com/munich-q…
inctechs a43628c
remove note from README and add key feature description
inctechs 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
Some comments aren't visible on the classic Files Changed page.
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -174,3 +174,5 @@ out/build | |
|
|
||
| node_modules/ | ||
| wheelhouse/ | ||
|
|
||
| pytest.ini | ||
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
inctechs marked this conversation as resolved.
Show resolved
Hide resolved
|
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,254 @@ | ||
| --- | ||
| file_format: mystnb | ||
| kernelspec: | ||
| name: python3 | ||
| mystnb: | ||
| number_source_lines: true | ||
| --- | ||
|
|
||
| # Code Switching Optimization | ||
|
|
||
| Different Quantum Error Correction Codes (QECCs) support distinct sets of gates that can be implemented transversally. Transversal | ||
| gates, which act on individual physical qubits of different logical code blocks, are inherently fault-tolerant as they do not spread | ||
| errors uncontrollably through a quantum circuit. Code switching has been proposed as a technique that employs multiple QECCs | ||
| whose respective sets of transversal gates complement each other to achieve universality. Logical qubits are dynamically transferred | ||
| between these codes depending on which gate needs to be applied; in other words, the logical information is switched from one code | ||
| to the other. | ||
|
|
||
| However, code switching is a costly operation in terms of space and time overhead. Therefore, given a quantum circuit, we want to find the **minimum number of switches** required to execute it. | ||
|
|
||
| QECC has functionality to automatically determine the minimum number of switching operations required to perform a circuit using two complementary gate sets. | ||
| The problem can be modelled as a **Min-Cut / Max-Flow** problem on a directed graph. The graph is constructed such that: | ||
|
|
||
| - **Source (SRC):** Represents the first code (e.g., 2D Color Code). | ||
| - **Sink (SNK):** Represents the second code (e.g., 3D Color Code). | ||
| - **Nodes:** Quantum gates in the circuit. | ||
| - **Edges:** | ||
| - **Infinite Capacity:** Connect gates unique to one code (e.g., T gates) to their respective terminal (Sink). | ||
| - **Temporal Edges:** Finite capacity edges connecting sequential operations on the same qubit. A "cut" here represents a code switch. | ||
|
|
||
| The minimum cut separating the Source from the Sink corresponds to the optimal switching strategy. | ||
|
|
||
| ## Basic Usage | ||
|
|
||
| Let's look at how to use the `MinimalCodeSwitchingCompiler` to analyze a simple quantum circuit. Assume the two codes in question are the 2D and 3D color codes, which have transversal gate sets $\{H, CX\}$ and $\{T, CX\}$, respectively. | ||
|
|
||
| ```{code-cell} ipython3 | ||
| from qiskit import QuantumCircuit | ||
| from mqt.qecc.code_switching import MinimalCodeSwitchingCompiler, CompilerConfig | ||
|
|
||
| # Define the transversal gate sets: | ||
| # Code A (Source): 2D Color Code | ||
| SOURCE_GATES = {"H", "CX"} | ||
|
|
||
| # Code B (Sink): 3D Color Code | ||
| SINK_GATES = {"T", "CX"} | ||
|
|
||
| # Initialize the compiler | ||
| mcsc = MinimalCodeSwitchingCompiler( | ||
| gate_set_code_source=SOURCE_GATES, | ||
| gate_set_code_sink=SINK_GATES | ||
| ) | ||
| ``` | ||
|
|
||
| Next, we create a Qiskit circuit that forces the compiler to make decisions. We will interleave Hadamard gates (Source-favored) and T gates (Sink-favored), separated by CNOTs (Common to both). | ||
|
|
||
| ```{code-cell} ipython3 | ||
| qc = QuantumCircuit(6) | ||
|
|
||
| qc.h(range(3)) | ||
| qc.t(range(3,6)) | ||
|
|
||
| qc.barrier() | ||
|
|
||
| qc.cx(1, 4) | ||
| qc.cx(3, 4) | ||
| qc.cx(2, 3) | ||
| qc.cx(2, 4) | ||
| qc.cx(0, 4) | ||
| qc.cx(5, 3) | ||
|
|
||
| qc.barrier() | ||
|
|
||
| qc.h(range(3)) | ||
| qc.t(range(3,6)) | ||
| ``` | ||
|
|
||
| ```{code-cell} ipython3 | ||
| :tags: [hide-input] | ||
| qc.draw('mpl') | ||
| ``` | ||
|
|
||
| The only optimization potential lies in the middle for the CNOT portion of the circuit, as the initial and final layers of single qubit gates force us to be in specific codes. | ||
| We can now build the graph from the circuit and compute the minimum cut. | ||
|
|
||
| ```{code-cell} ipython3 | ||
| # Build the graph representation of the circuit | ||
| mcsc.build_from_qiskit(qc) | ||
|
|
||
| # Compute Min-Cut | ||
| num_switches, switch_pos, set_S, set_T = mcsc.compute_min_cut() | ||
|
|
||
| print(f"Total switches required: {num_switches}") | ||
| print("Switch locations (qubit, depth):") | ||
| for pos in switch_pos: | ||
| print(f" - Qubit {pos[0]} after operation depth {pos[1]}") | ||
| ``` | ||
inctechs marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| The output positions provide the exact locations (qubit, depth) where a code switch operation must be inserted into the circuit. | ||
|
|
||
| Note that 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. | ||
|
|
||
| To account for this, we can pass a dictionary specifying gates that can be implemented one-way transverally together with their direction. | ||
| To see how this affect the optimization, consider the following circuit: | ||
|
|
||
| ```{code-cell} ipython3 | ||
| qc = QuantumCircuit(2) | ||
| qc.t(0) | ||
| qc.h(1) | ||
| qc.cx(0, 1) | ||
| ``` | ||
|
|
||
| ```{code-cell} ipython3 | ||
| :tags: [hide-input] | ||
| qc.draw('mpl') | ||
| ``` | ||
|
|
||
| Calculating the minimum number of switches without considering the one-way transversal CNOT property yields: | ||
|
|
||
| ```{code-cell} ipython3 | ||
| mcsc = MinimalCodeSwitchingCompiler({"H", "CX"}, {"T", "CX"}) | ||
| mcsc.build_from_qiskit(qc) | ||
| num_switches, switch_pos, _, _ = mcsc.compute_min_cut() | ||
| ``` | ||
|
|
||
| ```{code-cell} ipython3 | ||
| :tags: [hide-input] | ||
| print(f"Total switches required (without one-way CNOT): {num_switches}") | ||
| print("Switch locations (qubit, depth):") | ||
| for pos in switch_pos: | ||
| print(f" - Qubit {pos[0]} after operation depth {pos[1]}") | ||
| ``` | ||
|
|
||
| Hence, a single switch right after the T gate on qubit 0 is required. However, if we consider the one-way transversal CNOT property, we can avoid this switch: | ||
|
|
||
| ```{code-cell} ipython3 | ||
| 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() | ||
| ``` | ||
|
|
||
| ```{code-cell} ipython3 | ||
| :tags: [hide-input] | ||
| print(f"Total switches required: {num_switches}") | ||
| ``` | ||
|
|
||
| We specify in the graph-construction method `build_from_qiskit` that CNOTs (`CX`) are implemented transversally when the control qubit is encoded in the Sink code (3D color code) and the target qubit is encoded in the Source code (2D color code), i.e., `(control, target) <=> ("SNK", "SRC")`. | ||
|
|
||
| ## Extensions to the Min-Cut Model | ||
|
|
||
| Finding the minimum number of switches is a good starting point, but in practice, we might want to consider additional factors such as: | ||
|
|
||
| - **Depth Optimization:** Choosing the placing 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. | ||
| - **Code Bias:** If one of the codes has a significantly higher overhead for switching operations, we might want to minimize switches into that code specifically. | ||
|
|
||
| ### Depth Optimization | ||
|
|
||
| To incorporate depth optimization, we can assign an idle bonus to weights of the temporal edges based on whether the qubit is idling or active. For example, we can assign a lower weight to edges corresponding to idling qubits, encouraging the min-cut algorithm to place switches there. | ||
|
|
||
| ```{code-cell} ipython3 | ||
| qc = QuantumCircuit(3) | ||
| qc.h(0) | ||
| qc.t(1) | ||
| qc.t(2) | ||
| qc.cx(1, 2) | ||
| qc.cx(0, 2) | ||
| ``` | ||
|
|
||
| ```{code-cell} ipython3 | ||
| :tags: [hide-input] | ||
| qc.draw('mpl') | ||
| ``` | ||
|
|
||
| Running the regular min-cut computation yields a switch on qubit 2 after the T gate (we allow one-way CNOTs here): | ||
|
|
||
| ```{code-cell} ipython3 | ||
| 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() | ||
| ``` | ||
|
|
||
| ```{code-cell} ipython3 | ||
| :tags: [hide-input] | ||
| print(f"Total switches required (with one-way CNOT): {num_switches}") | ||
| print("Switch locations (qubit, depth):") | ||
| for pos in switch_pos: | ||
| print(f" - Qubit {pos[0]} after operation depth {pos[1]}") | ||
| ``` | ||
|
|
||
| However, if we assign a lower weight to the temporal edge of qubit 0 (which is idling), the algorithm chooses to place the switch there instead: | ||
|
|
||
| ```{code-cell} ipython3 | ||
| 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() | ||
| ``` | ||
|
|
||
| ```{code-cell} ipython3 | ||
| :tags: [hide-input] | ||
| print(f"Total switches required (with one-way CNOT): {num_switches}") | ||
| print("Switch locations (qubit, depth):") | ||
| for pos in switch_pos: | ||
| print(f" - Qubit {pos[0]} after operation depth {pos[1]}") | ||
| ``` | ||
|
|
||
| ### Code Bias | ||
|
|
||
| To minimize switches into a specific code, we can add a certain code bias. The implementation already has a bias towards the source code. | ||
|
|
||
| ```{code-cell} ipython3 | ||
| qc = QuantumCircuit(2) | ||
| qc.h(1) | ||
| qc.t(0) | ||
| qc.cx(0, 1) | ||
| ``` | ||
|
|
||
| ```{code-cell} ipython3 | ||
| :tags: [hide-input] | ||
| qc.draw('mpl') | ||
| ``` | ||
|
|
||
| The default behavior with a bias towards the source code yields that the switch is placed after the T gate on qubit 0 such that the CNOT is in the source code: | ||
|
|
||
| ```{code-cell} ipython3 | ||
| 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() | ||
| ``` | ||
|
|
||
| ```{code-cell} ipython3 | ||
| :tags: [hide-input] | ||
| print(f"Total switches required (with one-way CNOT): {num_switches}") | ||
| print("Switch locations (qubit, depth):") | ||
| for pos in switch_pos: | ||
| print(f" - Qubit {pos[0]} after operation depth {pos[1]}") | ||
| ``` | ||
|
|
||
| However, if we wanted to instead bias towards the sink code, we could adjust the compiler configuration as follows: | ||
|
|
||
| ```{code-cell} ipython3 | ||
| 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() | ||
| ``` | ||
|
|
||
| ```{code-cell} ipython3 | ||
| :tags: [hide-input] | ||
| print(f"Total switches required (with one-way CNOT): {num_switches}") | ||
| print("Switch locations (qubit, depth):") | ||
| for pos in switch_pos: | ||
| print(f" - Qubit {pos[0]} after operation depth {pos[1]}") | ||
| ``` | ||
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 |
|---|---|---|
|
|
@@ -29,6 +29,7 @@ installation | |
| LightsOutDecoder | ||
| StatePrep | ||
| CatStates | ||
| CodeSwitching | ||
| Encoders | ||
| AnalogInfo | ||
| references | ||
|
|
||
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
Oops, something went wrong.
Oops, something went wrong.
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.