Skip to content

Commit 24beeda

Browse files
lsschmidburgholzer
andauthored
Neutral Atom hybrid compilation extension (#1293)
## Description This PR add functionality needed for an upcoming version of the hybrid mapper in QMAP. In particular, it adds new types of operations: the "bridge" gate and the "passby" operation (a kind of bridge but with shuttling). ## 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] The changes follow the project's style guidelines and introduce no new warnings. - [x] The changes are fully tested and pass the CI checks. - [x] I have reviewed my own code changes. --------- Signed-off-by: Ludwig Schmid <117631861+lsschmid@users.noreply.github.com> Co-authored-by: Lukas Burgholzer <burgholzer@me.com>
1 parent a5885a5 commit 24beeda

7 files changed

Lines changed: 70 additions & 14 deletions

File tree

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ This project adheres to [Semantic Versioning], with the exception that minor rel
99

1010
## [Unreleased]
1111

12+
### Added
13+
14+
- ✨ Add support for bridge gates for the neutral atom hybrid mapper ([#1293]) ([**@lsschmid**])
15+
1216
## [3.3.2] - 2025-11-04
1317

1418
### Added
@@ -227,6 +231,7 @@ _📚 Refer to the [GitHub Release Notes](https://github.com/munich-quantum-tool
227231

228232
<!-- PR links -->
229233

234+
[#1293]: https://github.com/munich-quantum-toolkit/core/pull/1293
230235
[#1287]: https://github.com/munich-quantum-toolkit/core/pull/1287
231236
[#1283]: https://github.com/munich-quantum-toolkit/core/pull/1283
232237
[#1279]: https://github.com/munich-quantum-toolkit/core/pull/1279
@@ -351,6 +356,7 @@ _📚 Refer to the [GitHub Release Notes](https://github.com/munich-quantum-tool
351356
[**@lavanya-m-k**]: https://github.com/lavanya-m-k
352357
[**@taminob**]: https://github.com/taminob
353358
[**@jannikpflieger**]: https://github.com/jannikpflieger
359+
[**@lsschmid**]: https://github.com/lsschmid
354360

355361
<!-- General links -->
356362

include/mqt-core/ir/QuantumComputation.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,8 @@ class QuantumComputation {
328328
*/
329329
void measureAll(bool addBits = true);
330330

331+
void bridge(const Targets& targets);
332+
331333
void reset(Qubit target);
332334
void reset(const Targets& targets);
333335

include/mqt-core/ir/operations/OpType.inc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,12 @@ HANDLE_OP_TYPE(36, MultiAFalse, 0, "multi_a_false")
6565

6666
// Neutral atom shuttling operations
6767
HANDLE_OP_TYPE(37, Move, 0, "move")
68+
HANDLE_OP_TYPE(42, Bridge, 0, "bridge")
6869
HANDLE_OP_TYPE(38, AodActivate, 0, "aod_activate")
6970
HANDLE_OP_TYPE(39, AodDeactivate, 0, "aod_deactivate")
7071
HANDLE_OP_TYPE(40, AodMove, 0, "aod_move")
7172

72-
LAST_OP_TYPE(42)
73+
LAST_OP_TYPE(43)
7374

7475

7576
#undef OpTypeInv

src/ir/QuantumComputation.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1566,6 +1566,11 @@ void QuantumComputation::measureAll(const bool addBits) {
15661566
}
15671567
}
15681568

1569+
void QuantumComputation::bridge(const Targets& targets) {
1570+
checkQubitRange(targets);
1571+
emplace_back<StandardOperation>(targets, Bridge);
1572+
}
1573+
15691574
void QuantumComputation::reset(const Qubit target) {
15701575
checkQubitRange(target);
15711576
emplace_back<NonUnitaryOperation>(std::vector<Qubit>{target}, Reset);

src/ir/operations/AodOperation.cpp

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
#include <cstddef>
2121
#include <cstdint>
2222
#include <iomanip>
23-
#include <ios>
2423
#include <limits>
2524
#include <ostream>
2625
#include <sstream>
@@ -42,6 +41,7 @@ std::string SingleOperation::toQASMString() const {
4241
ss << static_cast<std::size_t>(dir) << ", " << start << ", " << end << "; ";
4342
return ss.str();
4443
}
44+
4545
std::vector<Dimension>
4646
AodOperation::convertToDimension(const std::vector<uint32_t>& dirs) {
4747
std::vector<Dimension> dirsEnum(dirs.size());
@@ -102,6 +102,7 @@ std::vector<qc::fp> AodOperation::getEnds(const Dimension dir) const {
102102
}
103103
return ends;
104104
}
105+
105106
std::vector<qc::fp> AodOperation::getStarts(const Dimension dir) const {
106107
std::vector<qc::fp> starts;
107108
for (const auto& op : operations) {
@@ -111,13 +112,15 @@ std::vector<qc::fp> AodOperation::getStarts(const Dimension dir) const {
111112
}
112113
return starts;
113114
}
115+
114116
qc::fp AodOperation::getMaxDistance(const Dimension dir) const {
115117
const auto distances = getDistances(dir);
116118
if (distances.empty()) {
117119
return 0;
118120
}
119121
return *std::ranges::max_element(distances);
120122
}
123+
121124
std::vector<qc::fp> AodOperation::getDistances(const Dimension dir) const {
122125
std::vector<qc::fp> params;
123126
for (const auto& op : operations) {
@@ -127,26 +130,35 @@ std::vector<qc::fp> AodOperation::getDistances(const Dimension dir) const {
127130
}
128131
return params;
129132
}
133+
130134
void AodOperation::dumpOpenQASM(
131135
std::ostream& of, const qc::QubitIndexToRegisterMap& qubitMap,
132136
[[maybe_unused]] const qc::BitIndexToRegisterMap& bitMap,
133137
const size_t indent, bool /*openQASM3*/) const {
134138
of << std::setprecision(std::numeric_limits<qc::fp>::digits10);
135-
of << std::string(indent * OUTPUT_INDENT_SIZE, ' ');
136-
of << name;
137-
// write AOD operations
138-
of << " (";
139+
of << std::string(indent * OUTPUT_INDENT_SIZE, ' ') << name << " (";
140+
141+
// Write AOD operations with separator logic
142+
bool first = true;
139143
for (const auto& op : operations) {
140-
of << op.toQASMString();
144+
if (!first) {
145+
of << "; ";
146+
}
147+
first = false;
148+
of << static_cast<std::size_t>(op.dir) << ", " << op.start << ", "
149+
<< op.end;
141150
}
142-
// remove last semicolon
143-
of.seekp(-1, std::ios_base::end);
144151
of << ")";
145-
// write qubit start
152+
153+
// Write qubits with separator logic
154+
bool firstQubit = true;
146155
for (const auto& qubit : targets) {
147-
of << " " << qubitMap.at(qubit).second << ",";
156+
if (!firstQubit) {
157+
of << ",";
158+
}
159+
firstQubit = false;
160+
of << " " << qubitMap.at(qubit).second;
148161
}
149-
of.seekp(-1, std::ios_base::end);
150162
of << ";\n";
151163
}
152164

@@ -161,5 +173,4 @@ void AodOperation::invert() {
161173
type = qc::OpType::AodActivate;
162174
}
163175
}
164-
165176
} // namespace na

src/ir/operations/StandardOperation.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,9 @@ void StandardOperation::dumpGateType(
457457
case iSWAPdg:
458458
op << "iswapdg";
459459
break;
460+
case Bridge:
461+
op << "bridge";
462+
break;
460463
case Move:
461464
op << "move";
462465
break;

test/ir/test_operation.cpp

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,34 @@ TEST(StandardOperation, Move) {
257257
const qc::StandardOperation moveOp({0, 1}, qc::OpType::Move);
258258
EXPECT_EQ(moveOp.getTargets().size(), 2);
259259
EXPECT_EQ(moveOp.getNqubits(), 2);
260+
261+
// QASM dump verification
262+
std::stringstream ss;
263+
qc::QuantumRegister qreg(0, 2, "q");
264+
qc::QubitIndexToRegisterMap qubitToReg{};
265+
qubitToReg.try_emplace(0, qreg, qreg.toString(0));
266+
qubitToReg.try_emplace(1, qreg, qreg.toString(1));
267+
moveOp.dumpOpenQASM(ss, qubitToReg, {}, 0, false);
268+
EXPECT_EQ(ss.str(), "move q[0], q[1];\n");
269+
}
270+
271+
TEST(StandardOperation, Bridge) {
272+
const qc::StandardOperation bridgeOp({0, 1, 2}, qc::OpType::Bridge);
273+
EXPECT_EQ(bridgeOp.getTargets().size(), 3);
274+
EXPECT_EQ(bridgeOp.getNqubits(), 3);
275+
276+
// QASM dump verification
277+
std::stringstream ss;
278+
qc::QuantumRegister qreg(0, 3, "q");
279+
qc::QubitIndexToRegisterMap qubitToReg{};
280+
qubitToReg.try_emplace(0, qreg, qreg.toString(0));
281+
qubitToReg.try_emplace(1, qreg, qreg.toString(1));
282+
qubitToReg.try_emplace(2, qreg, qreg.toString(2));
283+
bridgeOp.dumpOpenQASM(ss, qubitToReg, {}, 0, false);
284+
EXPECT_EQ(ss.str(), "bridge q[0], q[1], q[2];\n");
285+
286+
qc::QuantumComputation qc(3);
287+
EXPECT_NO_THROW(qc.bridge({0, 1, 2}));
260288
}
261289

262290
TEST(AodOperation, Activate) {
@@ -309,7 +337,7 @@ TEST(AodOperation, Qasm) {
309337
qubitToReg.try_emplace(1, qreg, qreg.toString(1));
310338
move.dumpOpenQASM(ss, qubitToReg, {}, 0, false);
311339

312-
EXPECT_EQ(ss.str(), "aod_move (0, 0, 1; 1, 1, 3;) q[0], q[1];\n");
340+
EXPECT_EQ(ss.str(), "aod_move (0, 0, 1; 1, 1, 3) q[0], q[1];\n");
313341
}
314342

315343
TEST(AodOperation, Constructors) {

0 commit comments

Comments
 (0)