Skip to content

Commit a6ab6e8

Browse files
authored
✨ Add Hybrid Mapping Extension + Hybrid Synthesis (#832)
## Description Thir PR extends the Hybrid Mapper within QMAP. In particular in includes the following features: 1. Extended Hybrid Mapping - added support for Bridge Gates - added initial Mapping strategies - added support for more atom moves (passby and flying ancillas [limited for now]) - general bugfixes and improvements 2. Hybrid Synthesis - a variant of the Hybrid Mapper which can evaluate multiple possible circuits, map them all end then chooses the best option to map (used for the ZX paper) - also includes PyBindings to use it from qiskit 3. NaViz support - The routed circuit can now be exported to `.naviz` and `.namachine` which can then be fed into [NaViz](https://github.com/munich-quantum-toolkit/naviz) 4. Added missing documentation on both mappers above. 5. Some general bugfixes and improvements Fixes #466 ## Checklist: - [x] The pull request only contains commits that are focused and relevant to this change. - [x] I have added appropriate tests that cover the new/changed functionality. - [x] I have updated the documentation to reflect these changes. - [ ] I have added entries to the changelog for any noteworthy additions, changes, fixes, or removals. - [x] I have added migration instructions to the upgrade guide (if needed). - [x] The changes follow the project's style guidelines and introduce no new warnings. - [ ] The changes are fully tested and pass the CI checks. - [x] I have reviewed my own code changes.
1 parent 0fd2d90 commit a6ab6e8

44 files changed

Lines changed: 6095 additions & 2225 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ _If you are upgrading: please see [`UPGRADING.md`](UPGRADING.md#unreleased)._
1515

1616
- ✨ Enable code generation for relaxed routing constraints ([#848]) ([**@ystade**])
1717
- ✨ Add `max_filling_factor` to scheduler in Zoned Neutral Atom Compiler ([#847]) ([**@ystade**])
18+
- ✨ Added extension to the hybrid routing mapper to also support Bridge gates, Passby moves and Flying ancillas ([#832]) ([**@lsschmid**])
19+
- ✨ Added hybrid synthesis routing for iterative circuit constructions ([#832]) ([**@lsschmid**])
1820

1921
## [3.4.0] - 2025-10-15
2022

@@ -160,6 +162,7 @@ _📚 Refer to the [GitHub Release Notes] for previous changelogs._
160162

161163
[#848]: https://github.com/munich-quantum-toolkit/qmap/pull/848
162164
[#847]: https://github.com/munich-quantum-toolkit/qmap/pull/847
165+
[#832]: https://github.com/munich-quantum-toolkit/qmap/pull/832
163166
[#804]: https://github.com/munich-quantum-toolkit/qmap/pull/804
164167
[#803]: https://github.com/munich-quantum-toolkit/qmap/pull/803
165168
[#796]: https://github.com/munich-quantum-toolkit/qmap/pull/796
@@ -192,6 +195,7 @@ _📚 Refer to the [GitHub Release Notes] for previous changelogs._
192195
[**@burgholzer**]: https://github.com/burgholzer
193196
[**@ystade**]: https://github.com/ystade
194197
[**@denialhaag**]: https://github.com/denialhaag
198+
[**@lsschmid**]: https://github.com/lsschmid
195199

196200
<!-- General links -->
197201

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ It builds upon [MQT Core](https://github.com/munich-quantum-toolkit/core), which
3232
- Clifford circuit synthesis and optimization: SAT-based depth/gate-optimal Clifford synthesis with optional destabilizer preservation, plus a fast heuristic splitter for larger circuits. [Guide](https://mqt.readthedocs.io/projects/qmap/en/latest/synthesis.html)
3333
- Zoned neutral-atom compilers: routing-agnostic and routing-aware flows that place, route, and schedule atom transfers between storage/entanglement zones. [Guide](https://mqt.readthedocs.io/projects/qmap/en/latest/na_zoned_compiler.html)
3434
- Neutral-atom logical state preparation (NASP): SMT-based generator for optimal preparation schedules of logical graph states on zoned architectures. [Guide](https://mqt.readthedocs.io/projects/qmap/en/latest/na_state_prep.html)
35-
- Hybrid circuit mapper for neutral atom quantum computers: a hybrid approach combining superconducting mapping techniques with atom shuttling.
35+
- Hybrid circuit mapper for neutral atom quantum computers: a hybrid approach combining superconducting mapping techniques with atom shuttling. [Guide](https://mqt.readthedocs.io/projects/qmap/en/latest/na_hybrid.html)
3636
- Python-first API with Qiskit integration: pass `QuantumCircuit` or OpenQASM; one-call `compile()` or `optimize_clifford()` via plugin wrappers. [API](https://mqt.readthedocs.io/projects/qmap/en/latest/api/mqt/qmap/index.html)
3737
- Efficient and portable: C++20 core with Z3-backed solvers, prebuilt wheels for Linux/macOS/Windows via [PyPI](https://pypi.org/project/mqt.qmap/).
3838

UPGRADING.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,14 @@ The code generator of the zoned neutral atom compiler is updated to also handle
1212
In contrast to the strict routing, a relaxed routing can change the relative order of atoms.
1313
The constraint that remains is that atoms previously in one row (column) must remain in the same row (column) after the routing.
1414

15+
Additionally, we also introduce an extension to the Hybrid Neutral Atom Mapper (HyRoNA), which unifies gate-based routing (SWAP/BRIDGE) with atom shuttling, pass-by, and an optional flying ancilla to find the most suitable routing.
16+
17+
Existing workflows should continue to function.
18+
The optionally new parameters are `usePassBy=False`, `numFlyingAncillas=0`, and `maxBridgeDistance=0` which can all be disabled with the above values to recover the previous behavior.
19+
Enabling/increasing the corresponding parameters allows enabling individually single routing strategies.
20+
21+
The hybrid mapper now also optionally yields a `.naviz` output which can be handled similarly to the zoned architecture compiler.
22+
1523
## [3.4.0]
1624

1725
### End of support for Python 3.9

bindings/hybrid_mapper/hybrid_mapper.cpp

Lines changed: 208 additions & 93 deletions
Large diffs are not rendered by default.

docs/images/hybrid_shuttling.gif

357 KB
Loading

docs/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ mapping
4444
synthesis
4545
na_state_prep
4646
na_zoned_compiler
47+
na_hybrid
4748
references
4849
CHANGELOG
4950
UPGRADING

docs/na_hybrid.md

Lines changed: 287 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
1+
---
2+
file_format: mystnb
3+
kernelspec:
4+
name: python3
5+
number_source_lines: true
6+
---
7+
8+
```{code-cell} ipython3
9+
:tags: [remove-cell]
10+
%config InlineBackend.figure_formats = ['svg']
11+
```
12+
13+
<style>.widget-subarea{display:none;} /*hide widgets as they do not work with sphinx*/</style>
14+
15+
# Hybrid Neutral Atom Routing and Mapping
16+
17+
Neutral-atom (NA) processors combine long-range, native multi-qubit interactions with high-fidelity atom transport.
18+
HyRoNA, the hybrid mapper in MQT QMAP, exploits both capabilities: it adaptively mixes gate-based routing (SWAP/BRIDGE)
19+
with atom transport to minimize latency and error. It pairs interaction-aware initial placement with fast,
20+
capability-specific cost models and an ASAP scheduler that respects hardware constraints, and it emits hardware-native
21+
programs plus optional animation files for visualization.
22+
23+
Below, we show how to use the Hybrid NA Mapper from Python on a small GHZ example and how to tune a few key parameters.
24+
25+
## Example: GHZ state on a hybrid NA architecture
26+
27+
In this example, we prepare an 8-qubit GHZ state (similar to the [zoned compiler](na_zoned_compiler.md)) and map it to a hybrid NA architecture.
28+
29+
```{code-cell} ipython3
30+
31+
from qiskit import QuantumCircuit
32+
# Build a compact GHZ(8) circuit (tree-like to keep depth small)
33+
34+
qc = QuantumCircuit(8)
35+
qc.h(0)
36+
qc.cx(0, 4)
37+
qc.cx(0, 2)
38+
qc.cx(4, 6)
39+
qc.cx(0, 1)
40+
qc.cx(2, 3)
41+
qc.cx(4, 5)
42+
qc.cx(6, 7)
43+
44+
qc.draw(output="mpl")
45+
46+
```
47+
48+
### Load a hybrid NA architecture
49+
50+
The hybrid mapper expects an architecture specification in JSON.
51+
This repository ships several ready-to-use examples.
52+
53+
```{code-cell} ipython3
54+
55+
from pathlib import Path
56+
import tempfile
57+
import os
58+
from mqt.qmap.hybrid_mapper import NeutralAtomHybridArchitecture
59+
60+
# Create a minimal architecture from an in-code JSON string and instantiate
61+
# the NeutralAtomHybridArchitecture using a temporary file. The mapper's
62+
# constructor expects a filename, so we write the JSON to a temp file first.
63+
arch_json = '''{
64+
"name": "example arch",
65+
"properties": {
66+
"nRows": 5,
67+
"nColumns": 5,
68+
"nAods": 1,
69+
"nAodCoordinates": 1,
70+
"interQubitDistance": 10,
71+
"minimalAodDistance": 0.1,
72+
"interactionRadius": 1,
73+
"blockingFactor": 1
74+
},
75+
"parameters": {
76+
"nQubits": 10,
77+
"gateTimes": {
78+
"none": 0.5
79+
},
80+
"gateAverageFidelities": {
81+
"none": 0.999
82+
},
83+
"decoherenceTimes": {
84+
"t1": 100000000,
85+
"t2": 1500000
86+
},
87+
"shuttlingTimes": {
88+
"move": 0.55,
89+
"aod_move": 0.55,
90+
"aod_activate": 20,
91+
"aod_deactivate": 20
92+
},
93+
"shuttlingAverageFidelities": {
94+
"move": 1,
95+
"aod_move": 1,
96+
"aod_activate": 1,
97+
"aod_deactivate": 1
98+
}
99+
}
100+
}'''
101+
102+
with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".json") as _tmp:
103+
_tmp.write(arch_json)
104+
tmp_name = _tmp.name
105+
106+
arch = NeutralAtomHybridArchitecture(tmp_name)
107+
# Clean up the temporary file
108+
os.unlink(tmp_name)
109+
110+
print(f"Loaded architecture: {arch.name} with {arch.num_qubits} qubits.")
111+
112+
```
113+
114+
### Map with HyRoNA
115+
116+
Mapping translates the algorithm to hardware-native operations using a combination of routing with SWAP/BRIDGE gates and
117+
atom moves. What combination is used depends on the architecture capabilities and the mapper parameters.
118+
Here, we show two examples: first, we only use gate-based routing, then we let the mapper decide freely.
119+
120+
```{code-cell} ipython3
121+
from mqt.core import load
122+
from mqt.qmap.hybrid_mapper import HybridNAMapper, MapperParameters
123+
124+
# Optional: tweak parameters (defaults are sensible for most cases)
125+
params_shuttling = MapperParameters()
126+
params_shuttling.gate_weight = 1.0
127+
params_shuttling.shuttling_weight = 0.0 # disables atom moves
128+
129+
130+
mapper = HybridNAMapper(arch, params=params_shuttling)
131+
132+
# Convert the Qiskit circuit to an MQT QuantumComputation and map it
133+
circ = load(qc)
134+
mapper.map(circ) # optionally: mapper.map(circ, initial_mapping=InitialCircuitMapping.identity)
135+
136+
# Retrieve mapping statistics
137+
mapper.get_stats()
138+
```
139+
140+
Note, how we set `shuttling_weight` zero to disallow atom moves and only use SWAP gates for routing.
141+
142+
The idea of the hybrid mapper is to mix both capabilities or to automatically select the best one.
143+
We now re-run the mapping with default parameters that allow both SWAPs and atom moves.
144+
145+
```{code-cell} ipython3
146+
params_default = MapperParameters()
147+
148+
mapper.set_parameters(params_default)
149+
150+
mapper.map(circ)
151+
mapper.get_stats()
152+
```
153+
154+
Now the mapper uses atom moves only as they are the better option on this architecture where moves are unit fidelity and
155+
gates are noisy.
156+
157+
### Schedule the mapped circuit
158+
159+
Scheduling orders the mapped operations as-soon-as-possible while respecting hardware constraints.
160+
161+
```{code-cell} ipython3
162+
# Schedule; set create_animation_csv=True to generate visualization data
163+
results = mapper.schedule(verbose=False, create_animation_csv=False)
164+
165+
results
166+
```
167+
168+
You can retrieve the mapped scheduled circuit (extended QASM2) and, if desired, the variant with explicit AOD movements equivalent to the operations done on the hardware.
169+
170+
```{code-cell} ipython3
171+
172+
mapped_qasm = mapper.get_mapped_qc_qasm()
173+
# Print a snippet of the mapped QASM
174+
print("\n... Mapped QASM snippet ...\n" +
175+
"\n".join(mapped_qasm.splitlines()[:30]))
176+
177+
# AOD-annotated variant (hardware-native moves)
178+
mapped_aod_qasm = mapper.get_mapped_qc_aod_qasm()
179+
print("\n... AOD (converted) snippet ...\n" + "\n".join(mapped_aod_qasm.splitlines()[:30]) + "\n...")
180+
```
181+
182+
Here, the `q` register corresponds to the 5x5=25 coordinates of the architecture and no longer to the circuit qubits.
183+
The other registers are used for temporary storage and AOD control.
184+
185+
The second variant shows explicit AOD movements that correspond to the atom moves done on hardware.
186+
Here, the AODs can be activated, moved, and deactivated to shuttle atoms around.
187+
The first entry corresponds to the x-direction and the second to the y-direction; in each pair, the two numbers denote start and end coordinates.
188+
189+
### Export animation files (optional)
190+
191+
HyRoNA can write animation output files that can be visualized with [MQT NAViz](https://github.com/munich-quantum-toolkit/naviz).
192+
Typically one has to accelerate the shuttling speed for better visualization by setting `shuttling_speed_factor`.
193+
194+
```{code-cell} ipython3
195+
# Re-run scheduling with animation output enabled
196+
_ = mapper.schedule(verbose=False, create_animation_csv=True, shuttling_speed_factor=100)
197+
198+
# Save the files; the method writes `.naviz` and `.namachine` files
199+
# next to the given base name
200+
mapper.save_animation_files("ghz8_hyrona_animation")
201+
```
202+
203+
This creates `.namachine` and `.naviz` files which can then be imported into
204+
MQT NAViz for visualization.
205+
206+
![Animation](images/hybrid_shuttling.gif)
207+
208+
## Tuning the mapper
209+
210+
HyRoNA exposes a concise set of parameters via `MapperParameters`:
211+
212+
- lookahead_depth: limited lookahead to peek at near-future layers
213+
- lookahead_weight_swaps / lookahead_weight_moves: balance gate-routing vs. atom motion during lookahead
214+
- decay: decreases the incentive for repeatedly blocking the same qubits
215+
- gate_weight / shuttling_weight / shuttling_time_weight: cost-model weights for gates vs. transport
216+
- dynamic_mapping_weight: bias for enabling dynamic re-mapping (SWAP/MOVE) when beneficial
217+
- max_bridge_distance: limit for BRIDGE operations; use to avoid long-range chains
218+
- initial_coord_mapping: strategy for hardware coordinate initialization
219+
220+
For more details, please check the source code documentation of `MapperParameters`.
221+
222+
## Tips
223+
224+
- Initial mapping: you can explicitly select the initial circuit-to-hardware mapping for `map` or `map_qasm_file` using
225+
`initial_mapping=InitialCircuitMapping.identity` or `InitialCircuitMapping.graph`.
226+
227+
- QASM input: instead of building a circuit in Qiskit, you can call `mapper.map_qasm_file("path/to/circuit.qasm")` and
228+
then `mapper.schedule(...)` as shown above.
229+
230+
- Architectures: the examples `rubidium_hybrid.json`, `rubidium_gate.json`, and `rubidium_shuttling.json` in
231+
`architectures/` cover different capability profiles and are a good starting point
232+
233+
## Hybrid Synthesis Mapper
234+
235+
The Hybrid Synthesis Mapper helps you compare and stitch together alternative circuit fragments while keeping track of the current mapping on the NA device.
236+
Below is a compact example that mirrors the unit test flow and shows how to:
237+
238+
- evaluate multiple candidate fragments and pick the best,
239+
- append fragments,
240+
- and retrieve mapped QASM as well as the AOD-annotated variant.
241+
242+
First, we create the `HybridSynthesisMapper` and evaluate two candidate fragments (here, both are the same GHZ circuit as above for simplicity).
243+
244+
```{code-cell} ipython3
245+
from mqt.qmap.hybrid_mapper import HybridSynthesisMapper
246+
247+
# Reuse the architecture `arch` and GHZ circuit `qc` defined above.
248+
synth = HybridSynthesisMapper(arch)
249+
synth.init_mapping(qc.num_qubits)
250+
251+
fidelities = synth.evaluate_synthesis_steps([circ, circ], also_map = False)
252+
print("Fidelities of subcircuits:", fidelities )
253+
```
254+
255+
The fidelity return indicates how well the subcircuit can be appended to the circuit mapped to the hardware.
256+
257+
You can then build up a larger program by appending fragments.
258+
259+
```{code-cell} ipython3
260+
synth.append_with_mapping(circ)
261+
```
262+
263+
This appends the circuit and maps it directly. This can be repeated for multiple fragments to always choose the best one.
264+
265+
Similar to the normal Hybrid Mapper, you can retrieve the mapped circuit and the AOD-annotated variant:
266+
267+
```{code-cell} ipython3
268+
269+
# Retrieve mapped circuit (extended QASM2)
270+
qasm_mapped = synth.get_mapped_qc_qasm()
271+
print("\n... Mapped QASM snippet ...\n" +
272+
"\n".join(qasm_mapped.splitlines()[:30]) +
273+
"\n...")
274+
```
275+
276+
One can also access the circuits which is constructed step-by-step in a unmapped state (e.g. to use a different mapper).
277+
278+
```{code-cell} ipython3
279+
qasm_synth = synth.get_synthesized_qc_qasm()
280+
print("\n... Synthesized QASM snippet ...\n" +
281+
"\n".join(qasm_synth.splitlines()[:30]) +
282+
"\n...")
283+
```
284+
285+
Here this corresponds simply to the input GHZ circuit.
286+
287+
This workflow lets you mix candidate-generation (synthesis) with hardware-aware mapping and scheduling, while keeping a single source of truth for mapping state across fragments.

0 commit comments

Comments
 (0)