From 82a30928caaff5989c840b2667563a60dd297fed Mon Sep 17 00:00:00 2001 From: Ryo Wakizaka Date: Thu, 11 Dec 2025 00:27:33 +0900 Subject: [PATCH 1/5] Output specified register names to QASM3 --- src/circuit/quantumcircuit_impl.hpp | 31 ++++++++++++++++++++++------- src/circuit/register.hpp | 6 +++++- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/src/circuit/quantumcircuit_impl.hpp b/src/circuit/quantumcircuit_impl.hpp index 55d7dc6..baff8a6 100644 --- a/src/circuit/quantumcircuit_impl.hpp +++ b/src/circuit/quantumcircuit_impl.hpp @@ -1506,11 +1506,25 @@ std::string QuantumCircuit::to_qasm3(void) } qk_opcounts_clear(&opcounts); - // registers - std::string creg_name = "c"; - std::string qreg_name = "q"; - qasm3 << "bit[" << num_clbits() << "] " << creg_name << ";" << std::endl; - qasm3 << "qubit[" << num_qubits() << "] " << qreg_name << ";" << std::endl; + // Maps a base index to the pointer to the corresponding register + std::map qreg_table; + std::map creg_table; + for(auto& qreg : this->qregs_) + { + qasm3 << "qubit[" << qreg.size() << "] " << qreg.name() << ";" << std::endl; + qreg_table[qreg.base_index()] = &qreg; + } + for(auto& creg : this->cregs_) + { + qasm3 << "bit[" << creg.size() << "] " << creg.name() << ";" << std::endl; + creg_table[creg.base_index()] = &creg; + } + auto recover_reg_data = [](std::map const& table, uint32_t index) + -> std::pair + { + const auto it = std::prev(table.upper_bound(static_cast(index))); + return std::make_pair(it->second->name(), index - it->first); + }; // save ops uint_t nops; @@ -1526,7 +1540,9 @@ std::string QuantumCircuit::to_qasm3(void) { for (uint_t j = 0; j < op->num_qubits; j++) { - qasm3 << creg_name << "[" << op->clbits[j] << "] = " << op->name << " " << qreg_name << "[" << op->qubits[j] << "];" << std::endl; + const auto creg_data = recover_reg_data(creg_table, op->clbits[j]); + const auto qreg_data = recover_reg_data(qreg_table, op->qubits[j]); + qasm3 << creg_data.first << "[" << creg_data.second << "] = " << op->name << " " << qreg_data.first << "[" << qreg_data.second << "];" << std::endl; } } } @@ -1556,7 +1572,8 @@ std::string QuantumCircuit::to_qasm3(void) qasm3 << " "; for (uint_t j = 0; j < op->num_qubits; j++) { - qasm3 << qreg_name << "[" << op->qubits[j] << "]"; + const auto qreg_data = recover_reg_data(qreg_table, op->qubits[j]); + qasm3 << qreg_data.first << "[" << qreg_data.second << "]"; if (j != op->num_qubits - 1) qasm3 << ", "; } diff --git a/src/circuit/register.hpp b/src/circuit/register.hpp index 3189e9d..b0b2b92 100644 --- a/src/circuit/register.hpp +++ b/src/circuit/register.hpp @@ -146,7 +146,7 @@ class Register /// @brief Return the size of this register /// @return the size of this register - uint_t size(void) { return size_; } + uint_t size(void) const { return size_; } /// @brief Return the name of this register /// @return the name of this register @@ -157,6 +157,10 @@ class Register base_index_ = base; } + /// @brief Return the base index of this register + /// @return the base index of this register + uint_t base_index() const { return base_index_; } + Bit &operator[](const uint_t i) { return bits_[i]; } protected: From 093a40ec5daa0bcea5cf3a4d27d26e580c84d518 Mon Sep 17 00:00:00 2001 From: Ryo Wakizaka Date: Thu, 11 Dec 2025 00:54:54 +0900 Subject: [PATCH 2/5] Add test --- test/test_circuit.cpp | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/test/test_circuit.cpp b/test/test_circuit.cpp index 53182e2..d4f7c82 100644 --- a/test/test_circuit.cpp +++ b/test/test_circuit.cpp @@ -614,6 +614,36 @@ static int test_compose(void) { return Ok; } +static int test_to_qasm3_multi_regs(void) { + auto qreg1 = QuantumRegister(2, std::string("q1")); + auto qreg2 = QuantumRegister(1, std::string("q2")); + auto creg1 = ClassicalRegister(2, std::string("c1")); + auto creg2 = ClassicalRegister(1, std::string("c2")); + QuantumCircuit circ(std::vector({qreg1, qreg2}), std::vector({creg1, creg2})); + + circ.measure(qreg2, creg2); + circ.measure(qreg1, creg1); + + const auto actual = circ.to_qasm3(); + const std::string expected = + "OPENQASM 3.0;\n" + "include \"stdgates.inc\";\n" + "qubit[2] q1;\n" + "qubit[1] q2;\n" + "bit[2] c1;\n" + "bit[1] c2;\n" + "c2[0] = measure q2[0];\n" + "c1[0] = measure q1[0];\n" + "c1[1] = measure q1[1];\n"; + if (actual != expected) { + std::cerr << " to_qasm3_multi_regs test : \n expected" << expected + << "\n actual:\n" << actual << std::endl; + return EqualityError; + } + + return Ok; +} + extern "C" int test_circuit(void) { int num_failed = 0; @@ -621,6 +651,7 @@ extern "C" int test_circuit(void) { num_failed += RUN_TEST(test_measure); num_failed += RUN_TEST(test_append); num_failed += RUN_TEST(test_compose); + num_failed += RUN_TEST(test_to_qasm3_multi_regs); std::cerr << "=== Number of failed subtests: " << num_failed << std::endl; return num_failed; From 1dbd829d5455c64a8db7e9e3d4ec1c04691467d7 Mon Sep 17 00:00:00 2001 From: Ryo Wakizaka Date: Thu, 11 Dec 2025 16:08:42 +0900 Subject: [PATCH 3/5] Remove unnecessary casts --- src/circuit/quantumcircuit_impl.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/circuit/quantumcircuit_impl.hpp b/src/circuit/quantumcircuit_impl.hpp index baff8a6..7a7d5f4 100644 --- a/src/circuit/quantumcircuit_impl.hpp +++ b/src/circuit/quantumcircuit_impl.hpp @@ -1519,10 +1519,10 @@ std::string QuantumCircuit::to_qasm3(void) qasm3 << "bit[" << creg.size() << "] " << creg.name() << ";" << std::endl; creg_table[creg.base_index()] = &creg; } - auto recover_reg_data = [](std::map const& table, uint32_t index) + auto recover_reg_data = [](std::map const& table, uint_t index) -> std::pair { - const auto it = std::prev(table.upper_bound(static_cast(index))); + const auto it = std::prev(table.upper_bound(index)); return std::make_pair(it->second->name(), index - it->first); }; From f63f08dd4f4bc63fa95bcdb7977a7d69e4320e45 Mon Sep 17 00:00:00 2001 From: Ryo Wakizaka Date: Thu, 11 Dec 2025 17:02:53 +0900 Subject: [PATCH 4/5] Fix quantum register output --- src/circuit/quantumcircuit_impl.hpp | 45 ++++++++++++++--------------- test/test_circuit.cpp | 11 ++++--- 2 files changed, 27 insertions(+), 29 deletions(-) diff --git a/src/circuit/quantumcircuit_impl.hpp b/src/circuit/quantumcircuit_impl.hpp index 7a7d5f4..1a79af0 100644 --- a/src/circuit/quantumcircuit_impl.hpp +++ b/src/circuit/quantumcircuit_impl.hpp @@ -1209,6 +1209,8 @@ void QuantumCircuit::print(void) const } } + + std::string QuantumCircuit::to_qasm3(void) { add_pending_control_flow_op(); @@ -1506,30 +1508,29 @@ std::string QuantumCircuit::to_qasm3(void) } qk_opcounts_clear(&opcounts); - // Maps a base index to the pointer to the corresponding register - std::map qreg_table; - std::map creg_table; - for(auto& qreg : this->qregs_) - { - qasm3 << "qubit[" << qreg.size() << "] " << qreg.name() << ";" << std::endl; - qreg_table[qreg.base_index()] = &qreg; - } - for(auto& creg : this->cregs_) + // save ops + uint_t nops; + nops = qk_circuit_num_instructions(rust_circuit_.get()); + + // Declare registers + // After transpilation, qubit registers will be mapped to physical registers, + // so we need to combined them in a single quantum register "q"; + const std::string qreg_name = "q"; + qasm3 << "qubit[" << num_qubits() << "] " << qreg_name << ";" << std::endl; + for(const auto& creg : cregs_) { qasm3 << "bit[" << creg.size() << "] " << creg.name() << ";" << std::endl; - creg_table[creg.base_index()] = &creg; } - auto recover_reg_data = [](std::map const& table, uint_t index) - -> std::pair + + auto recover_reg_data = [this](uint_t index) -> std::pair { - const auto it = std::prev(table.upper_bound(index)); - return std::make_pair(it->second->name(), index - it->first); + auto it = std::upper_bound(cregs_.begin(), cregs_.end(), index, + [](uint_t v, const ClassicalRegister& reg) { return v < reg.base_index(); }); + assert(it != cregs_.begin()); + it = std::prev(it); + return std::make_pair(it->name(), index - it->base_index()); }; - // save ops - uint_t nops; - nops = qk_circuit_num_instructions(rust_circuit_.get()); - for (uint_t i = 0; i < nops; i++) { QkCircuitInstruction *op = new QkCircuitInstruction; @@ -1540,9 +1541,8 @@ std::string QuantumCircuit::to_qasm3(void) { for (uint_t j = 0; j < op->num_qubits; j++) { - const auto creg_data = recover_reg_data(creg_table, op->clbits[j]); - const auto qreg_data = recover_reg_data(qreg_table, op->qubits[j]); - qasm3 << creg_data.first << "[" << creg_data.second << "] = " << op->name << " " << qreg_data.first << "[" << qreg_data.second << "];" << std::endl; + const auto creg_data = recover_reg_data(op->clbits[j]); + qasm3 << creg_data.first << "[" << creg_data.second << "] = " << op->name << " " << qreg_name << "[" << op->qubits[j] << "];" << std::endl; } } } @@ -1572,8 +1572,7 @@ std::string QuantumCircuit::to_qasm3(void) qasm3 << " "; for (uint_t j = 0; j < op->num_qubits; j++) { - const auto qreg_data = recover_reg_data(qreg_table, op->qubits[j]); - qasm3 << qreg_data.first << "[" << qreg_data.second << "]"; + qasm3 << qreg_name << "[" << op->qubits[j] << "]"; if (j != op->num_qubits - 1) qasm3 << ", "; } diff --git a/test/test_circuit.cpp b/test/test_circuit.cpp index d4f7c82..8f402de 100644 --- a/test/test_circuit.cpp +++ b/test/test_circuit.cpp @@ -628,15 +628,14 @@ static int test_to_qasm3_multi_regs(void) { const std::string expected = "OPENQASM 3.0;\n" "include \"stdgates.inc\";\n" - "qubit[2] q1;\n" - "qubit[1] q2;\n" + "qubit[3] q;\n" "bit[2] c1;\n" "bit[1] c2;\n" - "c2[0] = measure q2[0];\n" - "c1[0] = measure q1[0];\n" - "c1[1] = measure q1[1];\n"; + "c2[0] = measure q[2];\n" + "c1[0] = measure q[0];\n" + "c1[1] = measure q[1];\n"; if (actual != expected) { - std::cerr << " to_qasm3_multi_regs test : \n expected" << expected + std::cerr << " to_qasm3_multi_regs test : \n expected:\n" << expected << "\n actual:\n" << actual << std::endl; return EqualityError; } From 764245ac0c5d3d03235daa4b0156a38340f3bf58 Mon Sep 17 00:00:00 2001 From: Ryo Wakizaka Date: Thu, 11 Dec 2025 17:05:51 +0900 Subject: [PATCH 5/5] Remove redundant newlines --- src/circuit/quantumcircuit_impl.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/circuit/quantumcircuit_impl.hpp b/src/circuit/quantumcircuit_impl.hpp index 1a79af0..9f9fca2 100644 --- a/src/circuit/quantumcircuit_impl.hpp +++ b/src/circuit/quantumcircuit_impl.hpp @@ -1209,8 +1209,6 @@ void QuantumCircuit::print(void) const } } - - std::string QuantumCircuit::to_qasm3(void) { add_pending_control_flow_op();