From 792ac9a635884c4d7c64fda49658625a694f29ad Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Mon, 20 Apr 2026 17:19:24 +0900 Subject: [PATCH 1/5] Restore test to separate test codes --- test/CMakeLists.txt | 2 ++ test/{test_circuit.hpp => test_circuit.cpp} | 0 test/test_main.cpp | 25 ------------------- ...{test_parameter.hpp => test_parameter.cpp} | 8 +++--- ...est_transpiler.hpp => test_transpiler.cpp} | 0 5 files changed, 6 insertions(+), 29 deletions(-) rename test/{test_circuit.hpp => test_circuit.cpp} (100%) delete mode 100644 test/test_main.cpp rename test/{test_parameter.hpp => test_parameter.cpp} (98%) rename test/{test_transpiler.hpp => test_transpiler.cpp} (100%) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index ab0ed2f..f424d66 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -38,6 +38,8 @@ target_include_directories (test_driver PRIVATE ${CMAKE_SOURCE_DIR} nlohmann_jso # ...and linked with the qiskit library. target_link_libraries (test_driver ${qiskit} common nlohmann_json::nlohmann_json) +target_link_options(test_driver PRIVATE "-Wl,-z,muldefs") + # On MSVC we need to link the Python dll, we search it here and adjust the PATH in the tests below if (MSVC) # Store the directory where the qiskit_cext.dll is located. diff --git a/test/test_circuit.hpp b/test/test_circuit.cpp similarity index 100% rename from test/test_circuit.hpp rename to test/test_circuit.cpp diff --git a/test/test_main.cpp b/test/test_main.cpp deleted file mode 100644 index bd25a96..0000000 --- a/test/test_main.cpp +++ /dev/null @@ -1,25 +0,0 @@ -// This code is part of Qiskit. -// -// (C) Copyright IBM 2025. -// -// This code is licensed under the Apache License, Version 2.0. You may -// obtain a copy of this license in the LICENSE.txt file in the root directory -// of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. -// -// Any modifications or derivative works of this code must retain this -// copyright notice, and modified files need to carry a notice indicating -// that they have been altered from the originals. - -#include "test_circuit.hpp" -#include "test_parameter.hpp" -#include "test_transpiler.hpp" - -extern "C" int test_main(void) { - int num_failed = 0; - - num_failed += RUN_TEST(test_circuit); - num_failed += RUN_TEST(test_parameter); - num_failed += RUN_TEST(test_transpiler); - - return num_failed; -} diff --git a/test/test_parameter.hpp b/test/test_parameter.cpp similarity index 98% rename from test/test_parameter.hpp rename to test/test_parameter.cpp index 0de8040..d680c2c 100644 --- a/test/test_parameter.hpp +++ b/test/test_parameter.cpp @@ -25,7 +25,7 @@ extern "C" { /** * Test creating a new free symbol and check the name. */ -int test_parameter_new(void) { +static int test_parameter_new(void) { auto p = Parameter("a"); if (p.as_str() != "a") { @@ -38,7 +38,7 @@ int test_parameter_new(void) { /** * Test creating a new symbol from values. */ -int test_parameter_new_values(void) { +static int test_parameter_new_values(void) { auto real = Parameter(0.1); if (real.as_str() != "0.1") { std::cerr << "The parameter value " << real.as_str() << " is not 0.1" << std::endl; @@ -50,7 +50,7 @@ int test_parameter_new_values(void) { /** * Test casting to real values. */ -int test_parameter_to_real(void) { +static int test_parameter_to_real(void) { auto x = Parameter("x"); auto cmplx = Parameter(std::complex(1.0, 2.0)); auto val = Parameter(10.0); @@ -81,7 +81,7 @@ int test_parameter_to_real(void) { /** * Test calling all binary operations and verify their string representation. */ -int test_parameter_binary_ops(void) { +static int test_parameter_binary_ops(void) { auto a = Parameter("a"); auto b = Parameter("b"); auto ret = Parameter(); diff --git a/test/test_transpiler.hpp b/test/test_transpiler.cpp similarity index 100% rename from test/test_transpiler.hpp rename to test/test_transpiler.cpp From 4de6391883997ee5ad9214b4debcdedcfc6e0509 Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Tue, 21 Apr 2026 16:11:32 +0900 Subject: [PATCH 2/5] remove all multi definition errors --- samples/circuit_test.cpp | 2 +- src/circuit/classicalregister.hpp | 13 +- src/circuit/controlflow/control_flow.hpp | 1 - src/circuit/controlflow/if_else.hpp | 49 +- .../library/standard_gates/standard_gates.hpp | 2 +- src/circuit/parameter.hpp | 94 +- src/circuit/quantumcircuit.hpp | 1 - src/circuit/quantumcircuit_def.hpp | 1559 ++++++++++++++-- src/circuit/quantumcircuit_impl.hpp | 1585 +---------------- src/circuit/quantumregister.hpp | 15 +- src/circuit/register.hpp | 83 +- src/compiler/transpiler.hpp | 2 +- src/primitives/containers/bit_array.hpp | 270 ++- src/providers/sqc_backend.hpp | 37 +- src/quantum_info/sparse_observable.hpp | 344 ++-- src/transpiler/passmanager.hpp | 189 +- .../generate_preset_pass_manager.hpp | 8 +- src/transpiler/target.hpp | 444 +++-- src/utils/bitvector.hpp | 327 ++-- src/utils/utils.hpp | 2 +- test/CMakeLists.txt | 5 +- test/{common.c => common.cpp} | 15 +- test/{common.h => common.hpp} | 2 - test/test_circuit.cpp | 8 +- test/test_parameter.cpp | 8 +- test/test_transpiler.cpp | 6 +- 26 files changed, 2359 insertions(+), 2712 deletions(-) rename test/{common.c => common.cpp} (79%) rename test/{common.h => common.hpp} (98%) diff --git a/samples/circuit_test.cpp b/samples/circuit_test.cpp index 2ffd269..80f6f29 100644 --- a/samples/circuit_test.cpp +++ b/samples/circuit_test.cpp @@ -70,7 +70,7 @@ int main() circ.barrier(0); circ.measure(qr, cr); - circ.print(); + circ.draw(); std::cout << circ.to_qasm3(); return 0; diff --git a/src/circuit/classicalregister.hpp b/src/circuit/classicalregister.hpp index 674d120..bdcc146 100644 --- a/src/circuit/classicalregister.hpp +++ b/src/circuit/classicalregister.hpp @@ -17,9 +17,16 @@ #ifndef __qiskitcpp_circuit_classical_register_hpp__ #define __qiskitcpp_circuit_classical_register_hpp__ +#include + #include "circuit/register.hpp" #include "qiskit.h" + +namespace { + std::atomic CR_counter(0ull); +} + namespace Qiskit { namespace circuit @@ -38,7 +45,7 @@ class ClassicalRegister : public Register { protected: std::shared_ptr rust_register_ = nullptr; - static uint_t instances_counter_; +// static uint_t instances_counter_; public: /// @brief Create a new ClassicalRegister @@ -78,7 +85,7 @@ class ClassicalRegister : public Register std::string prefix(void) override { std::string ret = "c"; - ret += std::to_string(instances_counter_++); + ret += std::to_string(CR_counter++); return ret; } @@ -120,7 +127,7 @@ class ClassicalRegister : public Register Binary operator>=(Expr &right); }; -uint_t ClassicalRegister::instances_counter_ = 0; +//inline uint_t ClassicalRegister::instances_counter_ = 0; } // namespace circuit } // namespace Qiskit diff --git a/src/circuit/controlflow/control_flow.hpp b/src/circuit/controlflow/control_flow.hpp index 689a173..5e18184 100644 --- a/src/circuit/controlflow/control_flow.hpp +++ b/src/circuit/controlflow/control_flow.hpp @@ -17,7 +17,6 @@ #ifndef __qiskitcpp_circuit_control_flow_hpp__ #define __qiskitcpp_circuit_control_flow_hpp__ -#include "circuit/quantumcircuit_def.hpp" namespace Qiskit { namespace circuit { diff --git a/src/circuit/controlflow/if_else.hpp b/src/circuit/controlflow/if_else.hpp index 95132e0..38141ca 100644 --- a/src/circuit/controlflow/if_else.hpp +++ b/src/circuit/controlflow/if_else.hpp @@ -49,36 +49,31 @@ class IfElseOp : public ControlFlowOp // add false body /// @brief add false body - void else_(std::function body); - - void add_control_flow_op(QuantumCircuit& circ) override; -}; - -void IfElseOp::else_(std::function body) -{ - body(false_body_); - test_else_ = true; -} - -void IfElseOp::add_control_flow_op(QuantumCircuit& circ) -{ - if(test_else_){ - // if_else - std::shared_ptr true_circ = true_body_.get_rust_circuit(); - std::shared_ptr false_circ = false_body_.get_rust_circuit(); - - // TO DO : Add if_else support in Qiskit C-API (maybe in the future?) -// qc_if_else(circ.get_rust_circuit(false), clbit_, value_, true_circ, false_circ); + void else_(std::function body) + { + body(false_body_); + test_else_ = true; } - else{ - // if_test - std::shared_ptr true_circ = true_body_.get_rust_circuit(); - // TO DO : Add if_else support in Qiskit C-API (maybe in the future?) - //qc_if_test(circ.get_rust_circuit(false), clbit_, value_, true_circ); + void add_control_flow_op(QuantumCircuit& circ) override + { + if(test_else_){ + // if_else + std::shared_ptr true_circ = true_body_.get_rust_circuit(); + std::shared_ptr false_circ = false_body_.get_rust_circuit(); + + // TO DO : Add if_else support in Qiskit C-API (maybe in the future?) + // qc_if_else(circ.get_rust_circuit(false), clbit_, value_, true_circ, false_circ); + } + else{ + // if_test + std::shared_ptr true_circ = true_body_.get_rust_circuit(); + + // TO DO : Add if_else support in Qiskit C-API (maybe in the future?) + //qc_if_test(circ.get_rust_circuit(false), clbit_, value_, true_circ); + } } -} - +}; } // namespace circuit diff --git a/src/circuit/library/standard_gates/standard_gates.hpp b/src/circuit/library/standard_gates/standard_gates.hpp index 75f799e..112a23b 100644 --- a/src/circuit/library/standard_gates/standard_gates.hpp +++ b/src/circuit/library/standard_gates/standard_gates.hpp @@ -51,7 +51,7 @@ namespace Qiskit { namespace circuit { -std::unordered_map get_standard_gate_name_mapping(void) +inline std::unordered_map get_standard_gate_name_mapping(void) { // mapping of gate string and QkGate std::unordered_map name_mapping; diff --git a/src/circuit/parameter.hpp b/src/circuit/parameter.hpp index 1164599..de40654 100644 --- a/src/circuit/parameter.hpp +++ b/src/circuit/parameter.hpp @@ -452,79 +452,69 @@ class Parameter /// @param symbol a symbol to be bound /// @param value a value to be set /// @return a new bound Parameter - Parameter bind(const Parameter& symbol, const double value); + Parameter bind(const Parameter& symbol, const double value) + { + Parameter ret; + + qk_param_bind(ret.qiskit_param_.get(), qiskit_param_.get(), &symbol.qiskit_param_.get(), &value, 1); + return ret; + } /// @brief bind values to symbols /// @param symbols a list symbols to be bound /// @param value a list of values to be set /// @return a new bound Parameter - Parameter bind(const std::vector& symbols, const std::vector values); + Parameter bind(const std::vector& symbols, const std::vector values) + { + size_t size = std::min(symbols.size(), values.size()); + Parameter ret; + std::vector list(size); + for (uint_t i = 0; i < size; i++) { + list[i] = symbols[i].qiskit_param_.get(); + } + + qk_param_bind(ret.qiskit_param_.get(), qiskit_param_.get(), list.data(), values.data(), size); + return ret; + + } /// @brief substitute a symbol to other symbol /// @param symbol a symbol to be bound /// @param other a symbol to be set /// @return a new substituted Parameter - Parameter subs(const Parameter& symbol, const Parameter& other); + Parameter subs(const Parameter& symbol, const Parameter& other) + { + Parameter ret; + + qk_param_subs(ret.qiskit_param_.get(), qiskit_param_.get(), &symbol.qiskit_param_.get(), &other.qiskit_param_.get(), 1); + return ret; + } /// @brief substitute symbols to other symbols /// @param symbols a list of symbols to be bound /// @param others a list of symbols to be set /// @return a new substituted Parameter - Parameter subs(const std::vector& symbols, const std::vector& others); + Parameter subs(const std::vector& symbols, const std::vector& others) + { + size_t size = std::min(symbols.size(), values.size()); + Parameter ret; + std::vector slist(size); + std::vector olist(size); + for (uint_t i = 0; i < size; i++) { + slist[i] = symbols[i].qiskit_param_.get(); + olist[i] = others[i].qiskit_param_.get(); + } + + qk_param_bind(ret.qiskit_param_.get(), qiskit_param_.get(), slist.data(), olist.data(), size); + return ret; + } #endif friend std::ostream& operator<<(std::ostream& os, const Parameter& p); }; -#ifdef QISKIT_CAPI_HAS_SUBS -Parameter Parameter::bind(const Parameter& symbol, const double value) -{ - Parameter ret; - - qk_param_bind(ret.qiskit_param_.get(), qiskit_param_.get(), &symbol.qiskit_param_.get(), &value, 1); - return ret; -} - -Parameter Parameter::bind(const std::vector& symbols, const std::vector values) -{ - size_t size = std::min(symbols.size(), values.size()); - Parameter ret; - std::vector list(size); - for (uint_t i = 0; i < size; i++) { - list[i] = symbols[i].qiskit_param_.get(); - } - - qk_param_bind(ret.qiskit_param_.get(), qiskit_param_.get(), list.data(), values.data(), size); - return ret; - -} - -Parameter Parameter::subs(const Parameter& symbol, const Parameter& other) -{ - Parameter ret; - - qk_param_subs(ret.qiskit_param_.get(), qiskit_param_.get(), &symbol.qiskit_param_.get(), &other.qiskit_param_.get(), 1); - return ret; -} - -Parameter Parameter::subs(const std::vector& symbol, const std::vector& others) -{ - size_t size = std::min(symbols.size(), values.size()); - Parameter ret; - std::vector slist(size); - std::vector olist(size); - for (uint_t i = 0; i < size; i++) { - slist[i] = symbols[i].qiskit_param_.get(); - olist[i] = others[i].qiskit_param_.get(); - } - - qk_param_bind(ret.qiskit_param_.get(), qiskit_param_.get(), slist.data(), olist.data(), size); - return ret; -} -#endif - -std::ostream& operator<<(std::ostream& os, const Parameter& p) +inline std::ostream& operator<<(std::ostream& os, const Parameter& p) { os << p.as_str(); return os; diff --git a/src/circuit/quantumcircuit.hpp b/src/circuit/quantumcircuit.hpp index 6a81a35..f1b6ebf 100644 --- a/src/circuit/quantumcircuit.hpp +++ b/src/circuit/quantumcircuit.hpp @@ -22,4 +22,3 @@ #include "circuit/quantumcircuit_impl.hpp" #endif // __qiskitcpp_circuit_quantum_circuit_hpp__ - diff --git a/src/circuit/quantumcircuit_def.hpp b/src/circuit/quantumcircuit_def.hpp index e08cf96..d8add04 100644 --- a/src/circuit/quantumcircuit_def.hpp +++ b/src/circuit/quantumcircuit_def.hpp @@ -19,7 +19,12 @@ #include #include -#include +#include +#include +#include +#include +#include +#include #include "utils/types.hpp" #include "circuit/parameter.hpp" @@ -29,6 +34,10 @@ #include "circuit/library/standard_gates/standard_gates.hpp" #include "circuit/circuitinstruction.hpp" +#include "circuit/barrier.hpp" +#include "circuit/measure.hpp" +#include "circuit/reset.hpp" + #include #include "qiskit.h" @@ -38,6 +47,10 @@ // qiskit C-API circuit data using rust_circuit = ::QkCircuit; + +#define QC_COMPARE_EPS (1e-15) + + namespace Qiskit { namespace circuit @@ -74,19 +87,95 @@ class QuantumCircuit /// @param num_qubits The number of qubits in the circuit /// @param num_clbits The number of clbits in the circuit /// @param global_phase The global phase of the circuit, measured in radians - QuantumCircuit(const uint_t num_qubits, const uint_t num_clbits, const double global_phase = 0.0); + QuantumCircuit(const uint_t num_qubits, const uint_t num_clbits, const double global_phase = 0.0) + { + num_qubits_ = num_qubits; + num_clbits_ = num_clbits; + global_phase_ = global_phase; + + qregs_.resize(1); + cregs_.resize(1); + + QuantumRegister qr(num_qubits_); + ClassicalRegister cr(num_clbits_); + qregs_[0] = qr; + cregs_[0] = cr; + + rust_circuit_ = std::shared_ptr(qk_circuit_new(0, 0), qk_circuit_free); + qk_circuit_add_quantum_register(rust_circuit_.get(), qregs_[0].get_register().get()); + qk_circuit_add_classical_register(rust_circuit_.get(), cregs_[0].get_register().get()); + + if (global_phase != 0.0) { + qk_circuit_gate(rust_circuit_.get(), QkGate_GlobalPhase, nullptr, &global_phase_); + } + } /// @brief Create a new QuantumCircuit /// @param qreg A QuantumRegister /// @param creg A ClassicalRegister /// @param global_phase The global phase of the circuit, measured in radians - QuantumCircuit(QuantumRegister &qreg, ClassicalRegister &creg, const double global_phase = 0.0); + QuantumCircuit(QuantumRegister &qreg, ClassicalRegister &creg, const double global_phase = 0.0) + { + num_qubits_ = qreg.size(); + num_clbits_ = creg.size(); + global_phase_ = global_phase; + + qregs_.resize(1); + cregs_.resize(1); + + qregs_[0] = qreg; + cregs_[0] = creg; + + rust_circuit_ = std::shared_ptr(qk_circuit_new(0, 0), qk_circuit_free); + + qk_circuit_add_quantum_register(rust_circuit_.get(), qregs_[0].get_register().get()); + qk_circuit_add_classical_register(rust_circuit_.get(), cregs_[0].get_register().get()); + + if (global_phase != 0.0) { + qk_circuit_gate(rust_circuit_.get(), QkGate_GlobalPhase, nullptr, &global_phase_); + } + } /// @brief Create a new QuantumCircuit /// @param qregs A list of QuantumRegister /// @param cregs A list of ClassicalRegister /// @param global_phase The global phase of the circuit, measured in radians - QuantumCircuit(std::vector qregs, std::vector cregs, const double global_phase = 0.0); + QuantumCircuit(std::vector qregs, std::vector cregs, const double global_phase = 0.0) + { + num_qubits_ = 0; + num_clbits_ = 0; + global_phase_ = global_phase; + + qregs_.resize(qregs.size()); + cregs_.resize(cregs.size()); + + for (uint_t i = 0; i < qregs.size(); i++) { + qregs_[i] = qregs[i]; + qregs[i][0].get_register()->set_base_index(num_qubits_); + qregs_[i].set_base_index(num_qubits_); + num_qubits_ += qregs[i].size(); + } + + for (uint_t i = 0; i < cregs.size(); i++) { + cregs_[i] = cregs[i]; + cregs[i][0].get_register()->set_base_index(num_clbits_); + cregs_[i].set_base_index(num_clbits_); + num_clbits_ += cregs[i].size(); + } + + rust_circuit_ = std::shared_ptr(qk_circuit_new(0, 0), qk_circuit_free); + + for (uint_t i = 0; i < qregs_.size(); i++) { + qk_circuit_add_quantum_register(rust_circuit_.get(), qregs_[i].get_register().get()); + } + for (uint_t i = 0; i < cregs_.size(); i++) { + qk_circuit_add_classical_register(rust_circuit_.get(), cregs_[i].get_register().get()); + } + + if (global_phase != 0.0) { + qk_circuit_gate(rust_circuit_.get(), QkGate_GlobalPhase, nullptr, &global_phase_); + } + } /// @brief Create a new reference to Quantum Circuit /// @details Copy constructor of QuantumCircuit does not copy the circuit, @@ -94,9 +183,31 @@ class QuantumCircuit /// If you want to make a copy of the circuit, /// please call QuantumCircuit::copy explicitly. /// @param circ a Quantum Circuit to be copied the refrence in the new object - QuantumCircuit(const QuantumCircuit &circ); + QuantumCircuit(const QuantumCircuit &circ) + { + num_qubits_ = circ.num_qubits_; + num_clbits_ = circ.num_clbits_; + global_phase_ = circ.global_phase_; - ~QuantumCircuit(); + qregs_ = circ.qregs_; + cregs_ = circ.cregs_; + + rust_circuit_ = circ.rust_circuit_; + + measure_map_ = circ.measure_map_; + qubit_map_ = circ.qubit_map_; + } + + ~QuantumCircuit() + { + if (pending_control_flow_op_) { + pending_control_flow_op_.reset(); + } + + if (rust_circuit_) { + rust_circuit_.reset(); + } + } /// @brief Return number of qubits /// @return number of qubits @@ -149,12 +260,53 @@ class QuantumCircuit /// @brief Copy Quantum Circuit /// @return copied circuit - QuantumCircuit copy(void); + QuantumCircuit copy(void) + { + QuantumCircuit copied; + copied.rust_circuit_ = std::shared_ptr(qk_circuit_copy(rust_circuit_.get()), qk_circuit_free); + + copied.num_qubits_ = num_qubits_; + copied.num_clbits_ = num_clbits_; + copied.global_phase_ = global_phase_; + + copied.qregs_ = qregs_; + copied.cregs_ = cregs_; + + copied.measure_map_ = measure_map_; + copied.qubit_map_ = qubit_map_; + return copied; + } /// @brief set circuit reference of Qiskit circuit /// @param circ smart pointer to RUst circuit /// @param map layout mapping - void set_qiskit_circuit(std::shared_ptr circ, const std::vector &map); + void set_qiskit_circuit(std::shared_ptr circ, const std::vector &map) + { + if (rust_circuit_) + rust_circuit_.reset(); + rust_circuit_ = circ; + num_qubits_ = qk_circuit_num_qubits(circ.get()); + num_clbits_ = qk_circuit_num_clbits(circ.get()); + + qubit_map_.resize(map.size()); + for (int i = 0; i < map.size(); i++) { + qubit_map_[i] = (uint_t)map[i]; + } + + // get measured qubits + uint_t nops; + nops = qk_circuit_num_instructions(rust_circuit_.get()); + + for (uint_t i = 0; i < nops; i++) { + QkOperationKind kind = qk_circuit_instruction_kind(rust_circuit_.get(), i); + if (kind == QkOperationKind_Measure) { + QkCircuitInstruction *op = new QkCircuitInstruction; + qk_circuit_get_instruction(rust_circuit_.get(), i, op); + measure_map_.push_back(std::pair((uint_t)op->qubits[0], (uint_t)op->clbits[0])); + qk_circuit_instruction_clear(op); + } + } + } /// @brief get qubit mapping /// @return qubit mapping @@ -172,260 +324,530 @@ class QuantumCircuit /// @brief set global phase /// @param phase global phase value - void global_phase(const double phase); + void global_phase(const double phase) + { + global_phase_ = phase; + qk_circuit_gate(rust_circuit_.get(), QkGate_GlobalPhase, nullptr, &global_phase_); + } /// @brief Apply HGate /// @param qubit The qubit to apply the gate to. - void h(const uint_t qubit); + void h(const uint_t qubit) + { + std::uint32_t qubits[] = {(std::uint32_t)qubit}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_H, qubits, nullptr); + } /// @brief Apply IGate /// @param qubit The qubit to apply the gate to. - void i(const uint_t qubit); + void i(const uint_t qubit) + { + std::uint32_t qubits[] = {(std::uint32_t)qubit}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_I, qubits, nullptr); + } /// @brief Apply XGate /// @param qubit The qubit to apply the gate to. - void x(const uint_t qubit); + void x(const uint_t qubit) + { + std::uint32_t qubits[] = {(std::uint32_t)qubit}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_X, qubits, nullptr); + } /// @brief Apply YGate /// @param qubit The qubit to apply the gate to. - void y(const uint_t qubit); + void y(const uint_t qubit) + { + std::uint32_t qubits[] = {(std::uint32_t)qubit}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_Y, qubits, nullptr); + } /// @brief Apply ZGate /// @param qubit The qubit to apply the gate to. - void z(const uint_t qubit); + void z(const uint_t qubit) + { + std::uint32_t qubits[] = {(std::uint32_t)qubit}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_Z, qubits, nullptr); + } /// @brief Apply PhaseGate /// @param phase Phase. /// @param qubit The qubit to apply the gate to. - void p(const double phase, const uint_t qubit); + void p(const double phase, const uint_t qubit) + { + std::uint32_t qubits[] = {(std::uint32_t)qubit}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_Phase, qubits, &phase); + } /// @brief Apply PhaseGate /// @param phase Phase. /// @param qubit The qubit to apply the gate to. - void p(const Parameter &phase, const uint_t qubit); + void p(const Parameter &phase, const uint_t qubit) + { + std::uint32_t qubits[] = {(std::uint32_t)qubit}; + QkParam* params[] = {phase.qiskit_param_.get()}; + pre_add_gate(); + qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_Phase, qubits, params); + } /// @brief Apply RGate /// @param theta The angle of the rotation. /// @param phi The angle of the axis of rotation in the x-y plane. /// @param qubit The qubit to apply the gate to. - void r(const double theta, const double phi, const uint_t qubit); + void r(const double theta, const double phi, const uint_t qubit) + { + std::uint32_t qubits[] = {(std::uint32_t)qubit}; + double params[] = {theta, phi}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_R, qubits, params); + } /// @brief Apply RGate /// @param theta The angle of the rotation /// @param phi The angle of the axis of rotation in the x-y plane /// @param qubit The qubit to apply the gate to - void r(const Parameter &theta, const Parameter &phi, const uint_t qubit); + void r(const Parameter &theta, const Parameter &phi, const uint_t qubit) + { + std::uint32_t qubits[] = {(std::uint32_t)qubit}; + QkParam* params[] = {theta.qiskit_param_.get(), phi.qiskit_param_.get()}; + pre_add_gate(); + qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_R, qubits, params); + } /// @brief Apply RXGate /// @param theta The angle of the rotation /// @param qubit The qubit to apply the gate to - void rx(const double theta, const uint_t qubit); + void rx(const double theta, const uint_t qubit) + { + std::uint32_t qubits[] = {(std::uint32_t)qubit}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_RX, qubits, &theta); + } /// @brief Apply RXGate /// @param theta The angle of the rotation /// @param qubit The qubit to apply the gate to - void rx(const Parameter &theta, const uint_t qubit); + void rx(const Parameter &theta, const uint_t qubit) + { + std::uint32_t qubits[] = {(std::uint32_t)qubit}; + QkParam* params[] = {theta.qiskit_param_.get()}; + pre_add_gate(); + qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_RX, qubits, params); + } /// @brief Apply RYGate /// @param theta The angle of the rotation /// @param qubit The qubit to apply the gate to - void ry(const double theta, const uint_t qubit); + void ry(const double theta, const uint_t qubit) + { + std::uint32_t qubits[] = {(std::uint32_t)qubit}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_RY, qubits, &theta); + } /// @brief Apply RYGate /// @param theta The angle of the rotation /// @param qubit The qubit to apply the gate to - void ry(const Parameter &theta, const uint_t qubit); + void ry(const Parameter &theta, const uint_t qubit) + { + std::uint32_t qubits[] = {(std::uint32_t)qubit}; + QkParam* params[] = {theta.qiskit_param_.get()}; + pre_add_gate(); + qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_RY, qubits, params); + } /// @brief Apply RZGate /// @param theta The angle of the rotation /// @param qubit The qubit to apply the gate to - void rz(const double theta, const uint_t qubit); + void rz(const double theta, const uint_t qubit) + { + std::uint32_t qubits[] = {(std::uint32_t)qubit}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_RZ, qubits, &theta); + } /// @brief Apply RZGate /// @param theta The angle of the rotation /// @param qubit The qubit to apply the gate to - void rz(const Parameter &theta, const uint_t qubit); + void rz(const Parameter &theta, const uint_t qubit) + { + std::uint32_t qubits[] = {(std::uint32_t)qubit}; + QkParam* params[] = {theta.qiskit_param_.get()}; + pre_add_gate(); + qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_RZ, qubits, params); + } /// @brief Apply SGate /// @param qubit The qubit to apply the gate to. - void s(const uint_t qubit); + void s(const uint_t qubit) + { + std::uint32_t qubits[] = {(std::uint32_t)qubit}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_S, qubits, nullptr); + } /// @brief Apply SdgGate /// @param qubit The qubit to apply the gate to. - void sdg(const uint_t qubit); + void sdg(const uint_t qubit) + { + std::uint32_t qubits[] = {(std::uint32_t)qubit}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_Sdg, qubits, nullptr); + } /// @brief Apply SXGate /// @param qubit The qubit to apply the gate to. - void sx(const uint_t qubit); + void sx(const uint_t qubit) + { + std::uint32_t qubits[] = {(std::uint32_t)qubit}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_SX, qubits, nullptr); + } /// @brief Apply SXdgGate /// @param qubit The qubit to apply the gate to. - void sxdg(const uint_t qubit); + void sxdg(const uint_t qubit) + { + std::uint32_t qubits[] = {(std::uint32_t)qubit}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_SXdg, qubits, nullptr); + } /// @brief Apply TGate /// @param qubit The qubit to apply the gate to. - void t(const uint_t qubit); + void t(const uint_t qubit) + { + std::uint32_t qubits[] = {(std::uint32_t)qubit}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_T, qubits, nullptr); + } /// @brief Apply TdgGate /// @param qubit The qubit to apply the gate to. - void tdg(const uint_t qubit); + void tdg(const uint_t qubit) + { + std::uint32_t qubits[] = {(std::uint32_t)qubit}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_Tdg, qubits, nullptr); + } /// @brief Apply UGate /// @param theta The theta rotation angle of the gate. /// @param phi The phi rotation angle of the gate. /// @param lam The lam rotation angle of the gate. /// @param qubit The qubit to apply the gate to. - void u(const double theta, const double phi, const double lam, const uint_t qubit); + void u(const double theta, const double phi, const double lam, const uint_t qubit) + { + std::uint32_t qubits[] = {(std::uint32_t)qubit}; + double params[] = {theta, phi, lam}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_U, qubits, params); + } /// @brief Apply UGate /// @param theta The theta rotation angle of the gate. /// @param phi The phi rotation angle of the gate. /// @param lam The lam rotation angle of the gate. /// @param qubit The qubit to apply the gate to. - void u(const Parameter &theta, const Parameter &phi, const Parameter &lam, const uint_t qubit); + void u(const Parameter &theta, const Parameter &phi, const Parameter &lam, const uint_t qubit) + { + std::uint32_t qubits[] = {(std::uint32_t)qubit}; + QkParam* params[] = {theta.qiskit_param_.get(), phi.qiskit_param_.get(), lam.qiskit_param_.get()}; + pre_add_gate(); + qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_U, qubits, params); + } /// @brief Apply U1Gate /// @param theta The theta rotation angle of the gate. - void u1(const double theta, const uint_t qubit); + void u1(const double theta, const uint_t qubit) + { + std::uint32_t qubits[] = {(std::uint32_t)qubit}; + double params[] = {theta}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_U1, qubits, params); + } /// @brief Apply U1Gate /// @param theta The theta rotation angle of the gate. /// @param qubit The qubit to apply the gate to. - void u1(const Parameter &theta, const uint_t qubit); + void u1(const Parameter &theta, const uint_t qubit) + { + std::uint32_t qubits[] = {(std::uint32_t)qubit}; + QkParam* params[] = {theta.qiskit_param_.get()}; + pre_add_gate(); + qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_U1, qubits, params); + } /// @brief Apply U2Gate /// @param phi The phi rotation angle of the gate. /// @param lam The lam rotation angle of the gate. /// @param qubit The qubit to apply the gate to. - void u2(const double phi, const double lam, const uint_t qubit); + void u2(const double phi, const double lam, const uint_t qubit) + { + std::uint32_t qubits[] = {(std::uint32_t)qubit}; + double params[] = {phi, lam}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_U2, qubits, params); + } /// @brief Apply U2Gate /// @param phi The phi rotation angle of the gate. /// @param lam The lam rotation angle of the gate. /// @param qubit The qubit to apply the gate to. - void u2(const Parameter &phi, const Parameter &lam, const uint_t qubit); + void u2(const Parameter &phi, const Parameter &lam, const uint_t qubit) + { + std::uint32_t qubits[] = {(std::uint32_t)qubit}; + QkParam* params[] = {phi.qiskit_param_.get(), lam.qiskit_param_.get()}; + pre_add_gate(); + qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_U2, qubits, params); + } /// @brief Apply U3Gate /// @param theta The theta rotation angle of the gate. /// @param phi The phi rotation angle of the gate. /// @param lam The lam rotation angle of the gate. /// @param qubit The qubit to apply the gate to. - void u3(const double theta, const double phi, const double lam, const uint_t qubit); + void u3(const double theta, const double phi, const double lam, const uint_t qubit) + { + std::uint32_t qubits[] = {(std::uint32_t)qubit}; + double params[] = {theta, phi, lam}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_U3, qubits, params); + } /// @brief Apply U3Gate /// @param theta The theta rotation angle of the gate. /// @param phi The phi rotation angle of the gate. /// @param lam The lam rotation angle of the gate. /// @param qubit The qubit to apply the gate to. - void u3(const Parameter &theta, const Parameter &phi, const Parameter &lam, const uint_t qubit); + void u3(const Parameter &theta, const Parameter &phi, const Parameter &lam, const uint_t qubit) + { + std::uint32_t qubits[] = {(std::uint32_t)qubit}; + QkParam* params[] = {theta.qiskit_param_.get(), phi.qiskit_param_.get(), lam.qiskit_param_.get()}; + pre_add_gate(); + qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_U3, qubits, params); + } /// @brief Apply unitary gate specified by unitary to qubits /// @param unitary Unitary operator /// @param qubits The circuit qubits to apply the transformation to - void unitary(const std::vector &unitary, const reg_t &qubits); + void unitary(const std::vector &unitary, const reg_t &qubits) + { + pre_add_gate(); + std::vector qubits32(qubits.size()); + for (uint_t i = 0; i < qubits.size(); i++) + qubits32[i] = (std::uint32_t)qubits[i]; + + qk_circuit_unitary(rust_circuit_.get(), (const QkComplex64 *)unitary.data(), qubits32.data(), (std::uint32_t)qubits.size(), true); + } /// @brief Apply CHGate /// @param cqubit The qubit used as the control /// @param tqubit The qubit targeted by the gate - void ch(const uint_t cqubit, const uint_t tqubit); + void ch(const uint_t cqubit, const uint_t tqubit) + { + std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_CH, qubits, nullptr); + } /// @brief Apply CXGate /// @param cqubit The qubit used as the control /// @param tqubit The qubit targeted by the gate - void cx(const uint_t cqubit, const uint_t tqubit); + void cx(const uint_t cqubit, const uint_t tqubit) + { + std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_CX, qubits, nullptr); + } /// @brief Apply CYGate /// @param cqubit The qubit used as the control /// @param tqubit The qubit targeted by the gate - void cy(const uint_t cqubit, const uint_t tqubit); + void cy(const uint_t cqubit, const uint_t tqubit) + { + std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_CY, qubits, nullptr); + } /// @brief Apply CZGate /// @param cqubit The qubit used as the control /// @param tqubit The qubit targeted by the gate - void cz(const uint_t cqubit, const uint_t tqubit); + void cz(const uint_t cqubit, const uint_t tqubit) + { + std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_CZ, qubits, nullptr); + } /// @brief Apply DCXGate /// @param qubit1 The qubit to apply the gate to /// @param qubit2 The qubit to apply the gate to - void dcx(const uint_t qubit1, const uint_t qubit2); + void dcx(const uint_t qubit1, const uint_t qubit2) + { + std::uint32_t qubits[] = {(std::uint32_t)qubit1, (std::uint32_t)qubit2}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_DCX, qubits, nullptr); + } /// @brief Apply ECRGate /// @param cqubit The qubit used as the control /// @param tqubit The qubit targeted by the gate - void ecr(const uint_t cqubit, const uint_t tqubit); + void ecr(const uint_t cqubit, const uint_t tqubit) + { + std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_ECR, qubits, nullptr); + } /// @brief Apply SwapGate /// @param qubit1 The qubit to apply the gate to /// @param qubit2 The qubit to apply the gate to - void swap(const uint_t qubit1, const uint_t qubit2); + void swap(const uint_t qubit1, const uint_t qubit2) + { + std::uint32_t qubits[] = {(std::uint32_t)qubit1, (std::uint32_t)qubit2}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_Swap, qubits, nullptr); + } /// @brief Apply iSwapGate /// @param qubit1 The qubit to apply the gate to /// @param qubit2 The qubit to apply the gate to - void iswap(const uint_t qubit1, const uint_t qubit2); + void iswap(const uint_t qubit1, const uint_t qubit2) + { + std::uint32_t qubits[] = {(std::uint32_t)qubit1, (std::uint32_t)qubit2}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_ISwap, qubits, nullptr); + } /// @brief Apply controlled PhaseGate /// @param phase Phase. /// @param cqubit The qubit used as the control /// @param tqubit The qubit targeted by the gate - void cp(const double phase, const uint_t cqubit, const uint_t tqubit); + void cp(const double phase, const uint_t cqubit, const uint_t tqubit) + { + std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_CPhase, qubits, &phase); + } /// @brief Apply controlled PhaseGate /// @param phase Phase. /// @param cqubit The qubit used as the control /// @param tqubit The qubit targeted by the gate - void cp(const Parameter &phase, const uint_t cqubit, const uint_t tqubit); + void cp(const Parameter &phase, const uint_t cqubit, const uint_t tqubit) + { + std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; + QkParam* params[] = {phase.qiskit_param_.get()}; + pre_add_gate(); + qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_CPhase, qubits, params); + } /// @brief Apply controlled RXGate /// @param theta The angle of the rotation /// @param cqubit The qubit used as the control /// @param tqubit The qubit targeted by the gate - void crx(const double theta, const uint_t cqubit, const uint_t tqubit); + void crx(const double theta, const uint_t cqubit, const uint_t tqubit) + { + std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_CRX, qubits, &theta); + } /// @brief Apply controlled RXGate /// @param theta The angle of the rotation /// @param cqubit The qubit used as the control /// @param tqubit The qubit targeted by the gate - void crx(const Parameter &theta, const uint_t cqubit, const uint_t tqubit); + void crx(const Parameter &theta, const uint_t cqubit, const uint_t tqubit) + { + std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; + QkParam* params[] = {theta.qiskit_param_.get()}; + pre_add_gate(); + qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_CRX, qubits, params); + } /// @brief Apply controlled RYGate /// @param theta The angle of the rotation /// @param cqubit The qubit used as the control /// @param tqubit The qubit targeted by the gate - void cry(const double theta, const uint_t cqubit, const uint_t tqubit); + void cry(const double theta, const uint_t cqubit, const uint_t tqubit) + { + std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_CRY, qubits, &theta); + } /// @brief Apply controlled RYGate /// @param theta The angle of the rotation /// @param cqubit The qubit used as the control /// @param tqubit The qubit targeted by the gate - void cry(const Parameter &theta, const uint_t cqubit, const uint_t tqubit); + void cry(const Parameter &theta, const uint_t cqubit, const uint_t tqubit) + { + std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; + QkParam* params[] = {theta.qiskit_param_.get()}; + pre_add_gate(); + qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_CRY, qubits, params); + } /// @brief Apply controlled RZGate /// @param theta The angle of the rotation /// @param cqubit The qubit used as the control /// @param tqubit The qubit targeted by the gate - void crz(const double theta, const uint_t cqubit, const uint_t tqubit); + void crz(const double theta, const uint_t cqubit, const uint_t tqubit) + { + std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_CRZ, qubits, &theta); + } /// @brief Apply controlled RZGate /// @param theta The angle of the rotation /// @param cqubit The qubit used as the control /// @param tqubit The qubit targeted by the gate - void crz(const Parameter &theta, const uint_t cqubit, const uint_t tqubit); + void crz(const Parameter &theta, const uint_t cqubit, const uint_t tqubit) + { + std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; + QkParam* params[] = {theta.qiskit_param_.get()}; + pre_add_gate(); + qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_CRZ, qubits, params); + } /// @brief Apply CSGate /// @param cqubit The qubit used as the control /// @param tqubit The qubit targeted by the gate - void cs(const uint_t cqubit, const uint_t tqubit); + void cs(const uint_t cqubit, const uint_t tqubit) + { + std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_CS, qubits, nullptr); + } /// @brief Apply CSdgGate /// @param cqubit The qubit used as the control /// @param tqubit The qubit targeted by the gate - void csdg(const uint_t cqubit, const uint_t tqubit); + void csdg(const uint_t cqubit, const uint_t tqubit) + { + std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_CSdg, qubits, nullptr); + } /// @brief Apply CSXGate /// @param cqubit The qubit used as the control /// @param tqubit The qubit targeted by the gate - void csx(const uint_t cqubit, const uint_t tqubit); + void csx(const uint_t cqubit, const uint_t tqubit) + { + std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_CSX, qubits, nullptr); + } /// @brief Apply CUGate /// @param theta The theta rotation angle of the gate. @@ -433,7 +855,13 @@ class QuantumCircuit /// @param lam The lam rotation angle of the gate. /// @param cqubit The qubit used as the control /// @param tqubit The qubit targeted by the gate - void cu(const double theta, const double phi, const double lam, const uint_t cqubit, const uint_t tqubit); + void cu(const double theta, const double phi, const double lam, const uint_t cqubit, const uint_t tqubit) + { + std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; + double params[] = {theta, phi, lam}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_CU, qubits, params); + } /// @brief Apply CUGate /// @param theta The theta rotation angle of the gate. @@ -441,19 +869,37 @@ class QuantumCircuit /// @param lam The lam rotation angle of the gate. /// @param cqubit The qubit used as the control /// @param tqubit The qubit targeted by the gate - void cu(const Parameter &theta, const Parameter &phi, const Parameter &lam, const uint_t cqubit, const uint_t tqubit); + void cu(const Parameter &theta, const Parameter &phi, const Parameter &lam, const uint_t cqubit, const uint_t tqubit) + { + std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; + QkParam* params[] = {theta.qiskit_param_.get(), phi.qiskit_param_.get(), lam.qiskit_param_.get()}; + pre_add_gate(); + qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_CU, qubits, params); + } /// @brief Apply CU1Gate /// @param theta The theta rotation angle of the gate. /// @param cqubit The qubit used as the control /// @param tqubit The qubit targeted by the gate - void cu1(const double theta, const uint_t cqubit, const uint_t tqubit); + void cu1(const double theta, const uint_t cqubit, const uint_t tqubit) + { + std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; + double params[] = {theta}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_CU1, qubits, params); + } /// @brief Apply CU1Gate /// @param theta The theta rotation angle of the gate. /// @param cqubit The qubit used as the control /// @param tqubit The qubit targeted by the gate - void cu1(const Parameter &theta, const uint_t cqubit, const uint_t tqubit); + void cu1(const Parameter &theta, const uint_t cqubit, const uint_t tqubit) + { + std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; + QkParam* params[] = {theta.qiskit_param_.get()}; + pre_add_gate(); + qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_CU1, qubits, params); + } /// @brief Apply CU3Gate /// @param theta The theta rotation angle of the gate. @@ -461,7 +907,13 @@ class QuantumCircuit /// @param lam The lam rotation angle of the gate. /// @param cqubit The qubit used as the control /// @param tqubit The qubit targeted by the gate - void cu3(const double theta, const double phi, const double lam, const uint_t cqubit, const uint_t tqubit); + void cu3(const double theta, const double phi, const double lam, const uint_t cqubit, const uint_t tqubit) + { + std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; + double params[] = {theta, phi, lam}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_CU3, qubits, params); + } /// @brief Apply CU3Gate /// @param theta The theta rotation angle of the gate. @@ -469,156 +921,306 @@ class QuantumCircuit /// @param lam The lam rotation angle of the gate. /// @param cqubit The qubit used as the control /// @param tqubit The qubit targeted by the gate - void cu3(const Parameter &theta, const Parameter &phi, const Parameter &lam, const uint_t cqubit, const uint_t tqubit); + void cu3(const Parameter &theta, const Parameter &phi, const Parameter &lam, const uint_t cqubit, const uint_t tqubit) + { + std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; + QkParam* params[] = {theta.qiskit_param_.get(), phi.qiskit_param_.get(), lam.qiskit_param_.get()}; + pre_add_gate(); + qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_CU3, qubits, params); + } /// @brief Apply RXXGate /// @param theta The rotation angle of the gate /// @param qubit1 The qubit to apply the gate to /// @param qubit2 The qubit to apply the gate to - void rxx(const double theta, const uint_t qubit1, const uint_t qubit2); + void rxx(const double theta, const uint_t qubit1, const uint_t qubit2) + { + std::uint32_t qubits[] = {(std::uint32_t)qubit1, (std::uint32_t)qubit2}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_RXX, qubits, &theta); + } /// @brief Apply RXXGate /// @param theta The rotation angle of the gate /// @param qubit1 The qubit to apply the gate to /// @param qubit2 The qubit to apply the gate to - void rxx(const Parameter &theta, const uint_t qubit1, const uint_t qubit2); + void rxx(const Parameter &theta, const uint_t qubit1, const uint_t qubit2) + { + std::uint32_t qubits[] = {(std::uint32_t)qubit1, (std::uint32_t)qubit2}; + QkParam* params[] = {theta.qiskit_param_.get()}; + pre_add_gate(); + qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_RXX, qubits, params); + } /// @brief Apply RYYGate /// @param theta The rotation angle of the gate /// @param qubit1 The qubit to apply the gate to /// @param qubit2 The qubit to apply the gate to - void ryy(const double theta, const uint_t qubit1, const uint_t qubit2); + void ryy(const double theta, const uint_t qubit1, const uint_t qubit2) + { + std::uint32_t qubits[] = {(std::uint32_t)qubit1, (std::uint32_t)qubit2}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_RYY, qubits, &theta); + } /// @brief Apply RYYGate /// @param theta The rotation angle of the gate /// @param qubit1 The qubit to apply the gate to /// @param qubit2 The qubit to apply the gate to - void ryy(const Parameter &theta, const uint_t qubit1, const uint_t qubit2); + void ryy(const Parameter &theta, const uint_t qubit1, const uint_t qubit2) + { + std::uint32_t qubits[] = {(std::uint32_t)qubit1, (std::uint32_t)qubit2}; + QkParam* params[] = {theta.qiskit_param_.get()}; + pre_add_gate(); + qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_RYY, qubits, params); + } /// @brief Apply RZZGate /// @param theta The rotation angle of the gate /// @param qubit1 The qubit to apply the gate to /// @param qubit2 The qubit to apply the gate to - void rzz(const double theta, const uint_t qubit1, const uint_t qubit2); + void rzz(const double theta, const uint_t qubit1, const uint_t qubit2) + { + std::uint32_t qubits[] = {(std::uint32_t)qubit1, (std::uint32_t)qubit2}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_RZZ, qubits, &theta); + } /// @brief Apply RZZGate /// @param theta The rotation angle of the gate /// @param qubit1 The qubit to apply the gate to /// @param qubit2 The qubit to apply the gate to - void rzz(const Parameter &theta, const uint_t qubit1, const uint_t qubit2); + void rzz(const Parameter &theta, const uint_t qubit1, const uint_t qubit2) + { + std::uint32_t qubits[] = {(std::uint32_t)qubit1, (std::uint32_t)qubit2}; + QkParam* params[] = {theta.qiskit_param_.get()}; + pre_add_gate(); + qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_RZZ, qubits, params); + } /// @brief Apply RZXGate /// @param theta The rotation angle of the gate /// @param qubit1 The qubit to apply the gate to /// @param qubit2 The qubit to apply the gate to - void rzx(const double theta, const uint_t qubit1, const uint_t qubit2); + void rzx(const double theta, const uint_t qubit1, const uint_t qubit2) + { + std::uint32_t qubits[] = {(std::uint32_t)qubit1, (std::uint32_t)qubit2}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_RZX, qubits, &theta); + } /// @brief Apply RZXGate /// @param theta The rotation angle of the gate /// @param qubit1 The qubit to apply the gate to /// @param qubit2 The qubit to apply the gate to - void rzx(const Parameter &theta, const uint_t qubit1, const uint_t qubit2); + void rzx(const Parameter &theta, const uint_t qubit1, const uint_t qubit2) + { + std::uint32_t qubits[] = {(std::uint32_t)qubit1, (std::uint32_t)qubit2}; + QkParam* params[] = {theta.qiskit_param_.get()}; + pre_add_gate(); + qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_RZX, qubits, params); + } /// @brief Apply XXminusYY /// @param theta The rotation angle of the gate /// @param beta The phase angle of the gate /// @param qubit1 The qubit to apply the gate to /// @param qubit2 The qubit to apply the gate to - void xx_minus_yy(const double theta, const double beta, const uint_t qubit1, const uint_t qubit2); + void xx_minus_yy(const double theta, const double beta, const uint_t qubit1, const uint_t qubit2) + { + std::uint32_t qubits[] = {(std::uint32_t)qubit1, (std::uint32_t)qubit2}; + double params[] = {theta, beta}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_XXMinusYY, qubits, params); + } /// @brief Apply XXminusYY /// @param theta The rotation angle of the gate /// @param beta The phase angle of the gate /// @param qubit1 The qubit to apply the gate to /// @param qubit2 The qubit to apply the gate to - void xx_minus_yy(const Parameter &theta, const Parameter &beta, const uint_t qubit1, const uint_t qubit2); + void xx_minus_yy(const Parameter &theta, const Parameter &beta, const uint_t qubit1, const uint_t qubit2) + { + std::uint32_t qubits[] = {(std::uint32_t)qubit1, (std::uint32_t)qubit2}; + QkParam* params[] = {theta.qiskit_param_.get(), beta.qiskit_param_.get()}; + pre_add_gate(); + qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_XXMinusYY, qubits, params); + } /// @brief Apply XXplusYY /// @param theta The rotation angle of the gate /// @param beta The phase angle of the gate /// @param qubit1 The qubit to apply the gate to /// @param qubit2 The qubit to apply the gate to - void xx_plus_yy(const double theta, const double beta, const uint_t qubit1, const uint_t qubit2); + void xx_plus_yy(const double theta, const double beta, const uint_t qubit1, const uint_t qubit2) + { + std::uint32_t qubits[] = {(std::uint32_t)qubit1, (std::uint32_t)qubit2}; + double params[] = {theta, beta}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_XXPlusYY, qubits, params); + } /// @brief Apply XXplusYY /// @param theta The rotation angle of the gate /// @param beta The phase angle of the gate /// @param qubit1 The qubit to apply the gate to /// @param qubit2 The qubit to apply the gate to - void xx_plus_yy(const Parameter &theta, const Parameter &beta, const uint_t qubit1, const uint_t qubit2); + void xx_plus_yy(const Parameter &theta, const Parameter &beta, const uint_t qubit1, const uint_t qubit2) + { + std::uint32_t qubits[] = {(std::uint32_t)qubit1, (std::uint32_t)qubit2}; + QkParam* params[] = {theta.qiskit_param_.get(), beta.qiskit_param_.get()}; + pre_add_gate(); + qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_XXPlusYY, qubits, params); + } /// @brief Apply CCXGate /// @param cqubit1 The qubit used as the first control /// @param cqubit2 The qubit used as the second control /// @param tqubit The qubit targeted by the gate - void ccx(const uint_t cqubit1, const uint_t cqubit2, const uint_t tqubit); + void ccx(const uint_t cqubit1, const uint_t cqubit2, const uint_t tqubit) + { + std::uint32_t qubits[] = {(std::uint32_t)cqubit1, (std::uint32_t)cqubit2, (std::uint32_t)tqubit}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_CCX, qubits, nullptr); + } /// @brief Apply CCZGate /// @param cqubit1 The qubit used as the first control /// @param cqubit2 The qubit used as the second control /// @param tqubit The qubit targeted by the gate - void ccz(const uint_t cqubit1, const uint_t cqubit2, const uint_t tqubit); + void ccz(const uint_t cqubit1, const uint_t cqubit2, const uint_t tqubit) + { + std::uint32_t qubits[] = {(std::uint32_t)cqubit1, (std::uint32_t)cqubit2, (std::uint32_t)tqubit}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_CCZ, qubits, nullptr); + } /// @brief Apply CSwapGate /// @param cqubit The qubit used as the control /// @param qubit1 The qubit to apply the gate to /// @param qubit2 The qubit to apply the gate to - void cswap(const uint_t cqubit, const uint_t qubit1, const uint_t qubit2); + void cswap(const uint_t cqubit, const uint_t qubit1, const uint_t qubit2) + { + std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)qubit1, (std::uint32_t)qubit2}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_CSwap, qubits, nullptr); + } /// @brief Apply RCCXGate /// @param cqubit1 The qubit used as the first control /// @param cqubit2 The qubit used as the second control /// @param tqubit The qubit targeted by the gate - void rccx(const uint_t cqubit1, const uint_t cqubit2, const uint_t tqubit); + void rccx(const uint_t cqubit1, const uint_t cqubit2, const uint_t tqubit) + { + std::uint32_t qubits[] = {(std::uint32_t)cqubit1, (std::uint32_t)cqubit2, (std::uint32_t)tqubit}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_RCCX, qubits, nullptr); + } /// @brief Apply C3XGate /// @param cqubit1 The qubit used as the first control /// @param cqubit2 The qubit used as the second control /// @param cqubit3 The qubit used as the third control /// @param tqubit The qubit targeted by the gate - void cccx(const uint_t cqubit1, const uint_t cqubit2, const uint_t cqubit3, const uint_t tqubit); + void cccx(const uint_t cqubit1, const uint_t cqubit2, const uint_t cqubit3, const uint_t tqubit) + { + std::uint32_t qubits[] = {(std::uint32_t)cqubit1, (std::uint32_t)cqubit2, (std::uint32_t)cqubit3, (std::uint32_t)tqubit}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_C3X, qubits, nullptr); + } /// @brief Apply C3SXGate /// @param cqubit1 The qubit used as the first control /// @param cqubit2 The qubit used as the second control /// @param cqubit3 The qubit used as the third control /// @param tqubit The qubit targeted by the gate - void cccsx(const uint_t cqubit1, const uint_t cqubit2, const uint_t cqubit3, const uint_t tqubit); + void cccsx(const uint_t cqubit1, const uint_t cqubit2, const uint_t cqubit3, const uint_t tqubit) + { + std::uint32_t qubits[] = {(std::uint32_t)cqubit1, (std::uint32_t)cqubit2, (std::uint32_t)cqubit3, (std::uint32_t)tqubit}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_C3SX, qubits, nullptr); + } /// @brief Apply RC3XGate /// @param cqubit1 The qubit used as the first control /// @param cqubit2 The qubit used as the second control /// @param cqubit3 The qubit used as the third control /// @param tqubit The qubit targeted by the gate - void rcccx(const uint_t cqubit1, const uint_t cqubit2, const uint_t cqubit3, const uint_t tqubit); + void rcccx(const uint_t cqubit1, const uint_t cqubit2, const uint_t cqubit3, const uint_t tqubit) + { + std::uint32_t qubits[] = {(std::uint32_t)cqubit1, (std::uint32_t)cqubit2, (std::uint32_t)cqubit3, (std::uint32_t)tqubit}; + pre_add_gate(); + qk_circuit_gate(rust_circuit_.get(), QkGate_RC3X, qubits, nullptr); + } // other operations /// @brief Measure a quantum bit(qubit) in the Z basis into a classical bit(cbit) /// @param qubit The qubit to measure /// @param cbit The classical bit to place the measurement result in. - void measure(const uint_t qubit, const uint_t cbit); + void measure(const uint_t qubit, const uint_t cbit) + { + pre_add_gate(); + qk_circuit_measure(rust_circuit_.get(), (std::uint32_t)qubit, (std::uint32_t)cbit); + measure_map_.push_back(std::pair(qubit, cbit)); + } /// @brief Measure a quantum bit(qreg) in the Z basis into a classical bit(creg) /// @param qreg The qubit to measure /// @param creg The classical bit to place the measurement result in. - void measure(QuantumRegister &qreg, ClassicalRegister &creg); + void measure(QuantumRegister &qreg, ClassicalRegister &creg) + { + pre_add_gate(); + uint_t size = qreg.size(); + if (size > creg.size()) + size = creg.size(); + // TO DO implement multi-bits measure in C-API + for (uint_t i = 0; i < size; i++) { + qk_circuit_measure(rust_circuit_.get(), (std::uint32_t)qreg[i], (std::uint32_t)creg[i]); + measure_map_.push_back(std::pair(qreg[i], creg[i])); + } + } /// @brief Reset the quantum bit to their default state /// @param qubit The qubit to reset - void reset(const uint_t qubit); + void reset(const uint_t qubit) + { + pre_add_gate(); + qk_circuit_reset(rust_circuit_.get(), (std::uint32_t)qubit); + } /// @brief Reset the quantum bit to their default state /// @param qreg The qubit to reset - void reset(QuantumRegister &qreg); + void reset(QuantumRegister &qreg) + { + pre_add_gate(); + // TO DO implement multi-bits rest in C-API + for (uint_t i = 0; i < qreg.size(); i++) { + qk_circuit_reset(rust_circuit_.get(), (std::uint32_t)qreg[i]); + } + } /// @brief Insert barrier on specified qubit /// @param qubit The qubit to put a barrier - void barrier(const uint_t qubit); + void barrier(const uint_t qubit) + { + pre_add_gate(); + std::uint32_t q = (std::uint32_t)qubit; + qk_circuit_barrier(rust_circuit_.get(), &q, 1); + } /// @brief Insert barrier on multiple qubits /// @param qubits The qubits to put barrier - void barrier(const reg_t &qubits); + void barrier(const reg_t &qubits) + { + pre_add_gate(); + std::vector qubits32(qubits.size()); + for (uint_t i = 0; i < qubits.size(); i++) { + qubits32[i] = (std::uint32_t)qubits[i]; + } + qk_circuit_barrier(rust_circuit_.get(), qubits32.data(), (uint32_t)qubits32.size()); + } + // control flow ops @@ -633,37 +1235,234 @@ class QuantumCircuit /// @brief Return the number of parameter objects in the circuit /// @return the number of parameter objects in the circuit - uint_t num_parameters(void) const; + uint_t num_parameters(void) const + { + return qk_circuit_num_param_symbols(rust_circuit_.get()); + } /// @brief Assign parameters to new parameters or values. /// @param keys a list of keys /// @param values a list of values - void assign_parameters(const std::vector keys, const std::vector values); + void assign_parameters(const std::vector keys, const std::vector values) + { + std::vector c_keys; + for (uint_t i = 0; i < keys.size(); i++) { + c_keys.push_back((char *)keys[i].c_str()); + } + add_pending_control_flow_op(); + + // TO DO : add support for Parameter in Qiskit C-API + // qc_assign_parameters(rust_circuit_.get(), c_keys.data(), c_keys.size(), values.data(), values.size()); + } /// @brief Assign parameter to new parameter or value. /// @param key key /// @param value value - void assign_parameter(const std::string key, const double val); + void assign_parameter(const std::string key, const double val) + { + add_pending_control_flow_op(); + + // TO DO : add support for Parameter in Qiskit C-API + // qc_assign_parameter(rust_circuit_.get(), (char*)key.c_str(), val); + } + + QuantumCircuit &operator+=(QuantumCircuit &rhs) + { + compose(rhs); + return *this; + } + + QuantumCircuit operator+(QuantumCircuit &rhs) + { + QuantumCircuit new_circ(*this); + if (num_qubits_ >= rhs.num_qubits_ && num_clbits_ >= rhs.num_clbits_) + { + reg_t qubits; + reg_t clbits; + rhs.get_qubits(qubits); + rhs.get_clbits(clbits); + uint_t size = std::min(qubits.size(), clbits.size()); + std::vector vqubits(size); + for (uint_t i = 0; i < size; i++) + { + vqubits[i] = (std::uint32_t)qubits[i]; + } + std::vector vclbits(size); + for (uint_t i = 0; i < size; i++) + { + vclbits[i] = (std::uint32_t)clbits[i]; + } + new_circ.compose(rhs); + } + return new_circ; + } + + void compose(QuantumCircuit &rhs) + { + if (num_qubits_ >= rhs.num_qubits_ && num_clbits_ >= rhs.num_clbits_) + { + reg_t qubits; + reg_t clbits; + rhs.get_qubits(qubits); + rhs.get_clbits(clbits); + compose(rhs, qubits, clbits); + } + } /// @brief Add other circuit at the end of this circuit - /// @param rhs circuit to be added + /// @param circ circuit to be added /// @param qubits a list of qubits to be mapped /// @param clits a list of clbits to be mapped - QuantumCircuit &operator+=(QuantumCircuit &rhs); - QuantumCircuit operator+(QuantumCircuit &rhs); - void compose(QuantumCircuit &circ); - void compose(QuantumCircuit &circ, const reg_t &qubits, const reg_t &clbits); + void compose(QuantumCircuit &circ, const reg_t &qubits, const reg_t &clbits) + { + pre_add_gate(); + uint_t size = std::min(qubits.size(), clbits.size()); + std::vector vqubits(size); + for (uint_t i = 0; i < size; i++) { + vqubits[i] = (std::uint32_t)qubits[i]; + } + std::vector vclbits(size); + for (uint_t i = 0; i < size; i++) { + vclbits[i] = (std::uint32_t)clbits[i]; + } + + uint_t nops; + nops = qk_circuit_num_instructions(circ.rust_circuit_.get()); + + auto name_map = get_standard_gate_name_mapping(); + for (uint_t i = 0; i < nops; i++) { + QkCircuitInstruction *op = new QkCircuitInstruction; + qk_circuit_get_instruction(circ.rust_circuit_.get(), i, op); + + std::vector vqubits(op->num_qubits); + std::vector vclbits; + for (uint_t j = 0; j < op->num_qubits; j++) { + vqubits[j] = (std::uint32_t)qubits[op->qubits[j]]; + } + if (op->num_clbits > 0) { + vclbits.resize(op->num_clbits); + for (uint_t j = 0; j < op->num_clbits; j++) { + vclbits[j] = (std::uint32_t)clbits[op->clbits[j]]; + } + } + QkOperationKind kind = qk_circuit_instruction_kind(rust_circuit_.get(), i); + if (kind == QkOperationKind_Measure) { + qk_circuit_measure(rust_circuit_.get(), vqubits[0], vclbits[0]); + } else if (kind == QkOperationKind_Reset) { + qk_circuit_reset(rust_circuit_.get(), vqubits[0]); + } else if (kind == QkOperationKind_Barrier) { + qk_circuit_barrier(rust_circuit_.get(), vqubits.data(), (uint32_t)vqubits.size()); + } else if (kind == QkOperationKind_Gate) { + qk_circuit_parameterized_gate(rust_circuit_.get(), name_map[op->name].gate_map(), vqubits.data(), op->params); + } else if (kind == QkOperationKind_Unitary) { + // TO DO : how we can get unitary matrix from Rust ? + } + qk_circuit_instruction_clear(op); + } + + for (auto m : circ.measure_map_) { + measure_map_.push_back(m); + } + } /// @brief append a gate at the end of the circuit /// @param op a gate to be added /// @param qubits a list of qubits to be mapped /// @param params a list of parameters - void append(const Instruction &op, const reg_t &qubits); - void append(const Instruction &op, const std::vector &qubits); + void append(const Instruction &op, const reg_t &qubits) + { + if (op.num_qubits() == qubits.size()) { + std::vector vqubits(qubits.size()); + for (uint_t i = 0; i < qubits.size(); i++) { + vqubits[i] = (std::uint32_t)qubits[i]; + } + pre_add_gate(); + if (op.is_standard_gate()) { + if (op.num_params() > 0) { + std::vector params; + for (auto &p : op.params()) { + params.push_back(p.qiskit_param_.get()); + } + qk_circuit_parameterized_gate(rust_circuit_.get(), op.gate_map(), vqubits.data(), params.data()); + } + else + qk_circuit_gate(rust_circuit_.get(), op.gate_map(), vqubits.data(), nullptr); + } else { + if (std::string("reset") == op.name()) { + qk_circuit_reset(rust_circuit_.get(), vqubits[0]); + } + else if (std::string("barrier") == op.name()) { + qk_circuit_barrier(rust_circuit_.get(), vqubits.data(), (uint32_t)vqubits.size()); + } + else if (std::string("measure") == op.name()) { + qk_circuit_measure(rust_circuit_.get(), vqubits[0], vqubits[0]); + measure_map_.push_back(std::pair(qubits[0], qubits[0])); + } + } + } + } + + void append(const Instruction &op, const std::vector &qubits) + { + if (op.num_qubits() == qubits.size()) { + pre_add_gate(); + if (op.is_standard_gate()) { + if (op.num_params() > 0) { + std::vector params; + for (auto &p : op.params()) { + params.push_back(p.qiskit_param_.get()); + } + qk_circuit_parameterized_gate(rust_circuit_.get(), op.gate_map(), qubits.data(), params.data()); + } + else + qk_circuit_gate(rust_circuit_.get(), op.gate_map(), qubits.data(), nullptr); + } else { + if (std::string("reset") == op.name()) { + qk_circuit_reset(rust_circuit_.get(), qubits[0]); + } + else if (std::string("barrier") == op.name()) { + qk_circuit_barrier(rust_circuit_.get(), qubits.data(), (uint32_t)qubits.size()); + } + else if (std::string("measure") == op.name()) { + qk_circuit_measure(rust_circuit_.get(), qubits[0], qubits[0]); + measure_map_.push_back(std::pair((uint_t)qubits[0], (uint_t)qubits[0])); + } + } + } + } /// @brief append a gate at the end of the circuit /// @param inst an instruction to be added - void append(const CircuitInstruction &inst); + void append(const CircuitInstruction &inst) + { + std::vector vqubits(inst.qubits().size()); + for (uint_t i = 0; i < inst.qubits().size(); i++) { + vqubits[i] = (std::uint32_t)inst.qubits()[i]; + } + pre_add_gate(); + if (inst.instruction().is_standard_gate()) { + if (inst.instruction().num_params() > 0) { + std::vector params; + for (auto &p : inst.instruction().params()) { + params.push_back(p.qiskit_param_.get()); + } + qk_circuit_parameterized_gate(rust_circuit_.get(), inst.instruction().gate_map(), vqubits.data(), params.data()); + } + else + qk_circuit_gate(rust_circuit_.get(), inst.instruction().gate_map(), vqubits.data(), nullptr); + } else { + if (std::string("reset") == inst.instruction().name()) { + qk_circuit_reset(rust_circuit_.get(), vqubits[0]); + } + else if (std::string("barrier") == inst.instruction().name()) { + qk_circuit_barrier(rust_circuit_.get(), vqubits.data(), (uint32_t)vqubits.size()); + } + else if (std::string("measure") == inst.instruction().name()) { + qk_circuit_measure(rust_circuit_.get(), vqubits[0], (std::uint32_t)inst.clbits()[0]); + measure_map_.push_back(std::pair(inst.qubits()[0], inst.clbits()[0])); + } + } + } void append(const Instruction &op, const uint_t qubit) { @@ -673,29 +1472,554 @@ class QuantumCircuit /// @brief get number og instructions /// @return number of instructions in the circuit - uint_t num_instructions(void); + uint_t num_instructions(void) + { + return qk_circuit_num_instructions(rust_circuit_.get()); + } /// @brief get instruction /// @param i an index to the instruction /// @return the instruction at index i - CircuitInstruction operator[](uint_t i); + CircuitInstruction operator[](uint_t i) + { + if (i < qk_circuit_num_instructions(rust_circuit_.get())) { + auto name_map = get_standard_gate_name_mapping(); + + QkOperationKind kind = qk_circuit_instruction_kind(rust_circuit_.get(), i); + QkCircuitInstruction *op = new QkCircuitInstruction; + qk_circuit_get_instruction(rust_circuit_.get(), i, op); + reg_t qubits; + if (op->num_qubits > 0) { + qubits.resize(op->num_qubits); + for (int i = 0; i < op->num_qubits; i++) + qubits[i] = op->qubits[i]; + } + + reg_t clbits; + if (op->num_clbits > 0) { + clbits.resize(op->num_clbits); + for (int i = 0; i < op->num_clbits; i++) + clbits[i] = op->clbits[i]; + } + + std::vector params; + if (op->num_params > 0) { + params.resize(op->num_params); + for (int i = 0; i < op->num_params; i++) + params[i] = Parameter(qk_param_copy(op->params[i])); + } + std::string name = op->name; + qk_circuit_instruction_clear(op); + + if (kind == QkOperationKind_Measure) { + auto inst = Measure(); + return CircuitInstruction(inst, qubits, clbits); + } else if (kind == QkOperationKind_Reset) { + auto inst = Reset(); + return CircuitInstruction(inst, qubits, clbits); + } else if (kind == QkOperationKind_Barrier) { + auto inst = Barrier(); + return CircuitInstruction(inst, qubits, clbits); + } + + // standard gates + auto gate = name_map.find(name); + if (gate != name_map.end()) { + auto inst = gate->second; + if (params.size() > 0) { + inst.set_params(params); + } + return CircuitInstruction(inst, qubits); + } + } + return CircuitInstruction(); + } // qasm3 /// @brief Serialize a QuantumCircuit object as an OpenQASM3 string. /// @return An OpenQASM3 string. - std::string to_qasm3(void); + std::string to_qasm3(void) + { + add_pending_control_flow_op(); + + std::stringstream qasm3; + qasm3 << std::setprecision(18); + qasm3 << "OPENQASM 3.0;" << std::endl; + qasm3 << "include \"stdgates.inc\";" << std::endl; + + auto name_map = get_standard_gate_name_mapping(); + // add header for non-standard gates + bool cs = false; + bool sxdg = false; + QkOpCounts opcounts = qk_circuit_count_ops(rust_circuit_.get()); + for (int i = 0; i < opcounts.len; i++) { + if (opcounts.data[i].count != 0) { + auto op = name_map[opcounts.data[i].name].gate_map(); + switch (op) + { + case QkGate_R: + qasm3 << "gate r(p0, p1) _gate_q_0 {" << std::endl; + qasm3 << " U(p0, -pi/2 + p1, pi/2 - p1) _gate_q_0;" << std::endl; + qasm3 << "}" << std::endl; + break; + case QkGate_SXdg: + case QkGate_RYY: + case QkGate_XXPlusYY: + case QkGate_XXMinusYY: + if (!sxdg) + { + qasm3 << "gate sxdg _gate_q_0 {" << std::endl; + qasm3 << " s _gate_q_0;" << std::endl; + qasm3 << " h _gate_q_0;" << std::endl; + qasm3 << " s _gate_q_0;" << std::endl; + qasm3 << "}" << std::endl; + sxdg = true; + } + if (op == QkGate_RYY) + { + qasm3 << "gate ryy(p0) _gate_q_0, _gate_q_1 {" << std::endl; + qasm3 << " sxdg _gate_q_0;" << std::endl; + qasm3 << " sxdg _gate_q_1;" << std::endl; + qasm3 << " cx _gate_q_0, _gate_q_1;" << std::endl; + qasm3 << " rz(p0) _gate_q_1;" << std::endl; + qasm3 << " cx _gate_q_0, _gate_q_1;" << std::endl; + qasm3 << " sx _gate_q_0;" << std::endl; + qasm3 << " sx _gate_q_1;" << std::endl; + qasm3 << "}" << std::endl; + } + if (op == QkGate_XXPlusYY) + { + qasm3 << "gate xx_plus_yy(p0, p1) _gate_q_0, _gate_q_1 {" << std::endl; + qasm3 << " rz(p1) _gate_q_0;" << std::endl; + qasm3 << " sdg _gate_q_1;" << std::endl; + qasm3 << " sx _gate_q_1;" << std::endl; + qasm3 << " s _gate_q_1;" << std::endl; + qasm3 << " s _gate_q_0;" << std::endl; + qasm3 << " cx _gate_q_1, _gate_q_0;" << std::endl; + qasm3 << " ry((-0.5)*p0) _gate_q_1;" << std::endl; + qasm3 << " ry((-0.5)*p0) _gate_q_0;" << std::endl; + qasm3 << " cx _gate_q_1, _gate_q_0;" << std::endl; + qasm3 << " sdg _gate_q_0;" << std::endl; + qasm3 << " sdg _gate_q_1;" << std::endl; + qasm3 << " sxdg _gate_q_1;" << std::endl; + qasm3 << " s _gate_q_1;" << std::endl; + qasm3 << " rz(-p1) _gate_q_0;" << std::endl; + qasm3 << "}" << std::endl; + } + if (op == QkGate_XXMinusYY) + { + qasm3 << "gate xx_minus_yy(p0, p1) _gate_q_0, _gate_q_1 {" << std::endl; + qasm3 << " rz(-p1) _gate_q_1;" << std::endl; + qasm3 << " sdg _gate_q_0;" << std::endl; + qasm3 << " sx _gate_q_0;" << std::endl; + qasm3 << " s _gate_q_0;" << std::endl; + qasm3 << " s _gate_q_1;" << std::endl; + qasm3 << " cx _gate_q_0, _gate_q_1;" << std::endl; + qasm3 << " ry(0.5*p0) _gate_q_0;" << std::endl; + qasm3 << " ry((-0.5)*p0) _gate_q_1;" << std::endl; + qasm3 << " cx _gate_q_0, _gate_q_1;" << std::endl; + qasm3 << " sdg _gate_q_1;" << std::endl; + qasm3 << " sdg _gate_q_0;" << std::endl; + qasm3 << " sxdg _gate_q_0;" << std::endl; + qasm3 << " s _gate_q_0;" << std::endl; + qasm3 << " rz(p1) _gate_q_1;" << std::endl; + qasm3 << "}" << std::endl; + } + break; + case QkGate_DCX: + qasm3 << "gate dcx _gate_q_0, _gate_q_1 {" << std::endl; + qasm3 << " cx _gate_q_0, _gate_q_1;" << std::endl; + qasm3 << " cx _gate_q_1, _gate_q_0;" << std::endl; + qasm3 << "}" << std::endl; + break; + case QkGate_ECR: + qasm3 << "gate ecr _gate_q_0, _gate_q_1 {" << std::endl; + qasm3 << " s _gate_q_0;" << std::endl; + qasm3 << " sx _gate_q_1;" << std::endl; + qasm3 << " cx _gate_q_0, _gate_q_1;" << std::endl; + qasm3 << " x _gate_q_0;" << std::endl; + qasm3 << "}" << std::endl; + break; + case QkGate_ISwap: + qasm3 << "gate iswap _gate_q_0, _gate_q_1 {" << std::endl; + qasm3 << " s _gate_q_0;" << std::endl; + qasm3 << " s _gate_q_1;" << std::endl; + qasm3 << " h _gate_q_0;" << std::endl; + qasm3 << " cx _gate_q_0, _gate_q_1;" << std::endl; + qasm3 << " cx _gate_q_1, _gate_q_0;" << std::endl; + qasm3 << " h _gate_q_1;" << std::endl; + qasm3 << "}" << std::endl; + break; + case QkGate_CSX: + case QkGate_CS: + if (!cs) + { + qasm3 << "gate cs _gate_q_0, _gate_q_1 {" << std::endl; + qasm3 << " t _gate_q_0;" << std::endl; + qasm3 << " cx _gate_q_0, _gate_q_1;" << std::endl; + qasm3 << " tdg _gate_q_1;" << std::endl; + qasm3 << " cx _gate_q_0, _gate_q_1;" << std::endl; + qasm3 << " t _gate_q_1;" << std::endl; + qasm3 << "}" << std::endl; + cs = true; + } + if (op == QkGate_CSX) + { + qasm3 << "gate csx _gate_q_0, _gate_q_1 {" << std::endl; + qasm3 << " h _gate_q_1;" << std::endl; + qasm3 << " cs _gate_q_0, _gate_q_1;" << std::endl; + qasm3 << " h _gate_q_1;" << std::endl; + qasm3 << "}" << std::endl; + } + break; + case QkGate_CSdg: + qasm3 << "gate csdg _gate_q_0, _gate_q_1 {" << std::endl; + qasm3 << " tdg _gate_q_0;" << std::endl; + qasm3 << " cx _gate_q_0, _gate_q_1;" << std::endl; + qasm3 << " t _gate_q_1;" << std::endl; + qasm3 << " cx _gate_q_0, _gate_q_1;" << std::endl; + qasm3 << " tdg _gate_q_1;" << std::endl; + qasm3 << "}" << std::endl; + break; + case QkGate_CCZ: + qasm3 << "gate ccz _gate_q_0, _gate_q_1, _gate_q_2 {" << std::endl; + qasm3 << " h _gate_q_2;" << std::endl; + qasm3 << " ccx _gate_q_0, _gate_q_1, _gate_q_2;" << std::endl; + qasm3 << " h _gate_q_2;" << std::endl; + qasm3 << "}" << std::endl; + break; + case QkGate_RXX: + qasm3 << "gate rxx(p0) _gate_q_0, _gate_q_1 {" << std::endl; + qasm3 << " h _gate_q_0;" << std::endl; + qasm3 << " h _gate_q_1;" << std::endl; + qasm3 << " cx _gate_q_0, _gate_q_1;" << std::endl; + qasm3 << " rz(p0) _gate_q_1;" << std::endl; + qasm3 << " cx _gate_q_0, _gate_q_1;" << std::endl; + qasm3 << " h _gate_q_1;" << std::endl; + qasm3 << " h _gate_q_0;" << std::endl; + qasm3 << "}" << std::endl; + break; + case QkGate_RZX: + qasm3 << "gate rzx(p0) _gate_q_0, _gate_q_1 {" << std::endl; + qasm3 << " h _gate_q_1;" << std::endl; + qasm3 << " cx _gate_q_0, _gate_q_1;" << std::endl; + qasm3 << " rz(p0) _gate_q_1;" << std::endl; + qasm3 << " cx _gate_q_0, _gate_q_1;" << std::endl; + qasm3 << " h _gate_q_1;" << std::endl; + qasm3 << "}" << std::endl; + break; + case QkGate_RZZ: + qasm3 << "gate rzz(p0) _gate_q_0, _gate_q_1 {" << std::endl; + qasm3 << " cx _gate_q_0, _gate_q_1;" << std::endl; + qasm3 << " rz(p0) _gate_q_1;" << std::endl; + qasm3 << " cx _gate_q_0, _gate_q_1;" << std::endl; + qasm3 << "}" << std::endl; + break; + case QkGate_RCCX: + qasm3 << "gate rccx _gate_q_0, _gate_q_1, _gate_q_2 {" << std::endl; + qasm3 << " h _gate_q_2;" << std::endl; + qasm3 << " t _gate_q_2;" << std::endl; + qasm3 << " cx _gate_q_1, _gate_q_2;" << std::endl; + qasm3 << " tdg _gate_q_2;" << std::endl; + qasm3 << " cx _gate_q_0, _gate_q_2;" << std::endl; + qasm3 << " t _gate_q_2;" << std::endl; + qasm3 << " cx _gate_q_1, _gate_q_2;" << std::endl; + qasm3 << " tdg _gate_q_2;" << std::endl; + qasm3 << " h _gate_q_2;" << std::endl; + qasm3 << "}" << std::endl; + break; + case QkGate_C3X: + qasm3 << "gate mcx _gate_q_0, _gate_q_1, _gate_q_2, _gate_q_3 {" << std::endl; + qasm3 << " h _gate_q_3;" << std::endl; + qasm3 << " p(pi/8) _gate_q_0;" << std::endl; + qasm3 << " p(pi/8) _gate_q_1;" << std::endl; + qasm3 << " p(pi/8) _gate_q_2;" << std::endl; + qasm3 << " p(pi/8) _gate_q_3;" << std::endl; + qasm3 << " cx _gate_q_0, _gate_q_1;" << std::endl; + qasm3 << " p(-pi/8) _gate_q_1;" << std::endl; + qasm3 << " cx _gate_q_0, _gate_q_1;" << std::endl; + qasm3 << " cx _gate_q_1, _gate_q_2;" << std::endl; + qasm3 << " p(-pi/8) _gate_q_2;" << std::endl; + qasm3 << " cx _gate_q_0, _gate_q_2;" << std::endl; + qasm3 << " p(pi/8) _gate_q_2;" << std::endl; + qasm3 << " cx _gate_q_1, _gate_q_2;" << std::endl; + qasm3 << " p(-pi/8) _gate_q_2;" << std::endl; + qasm3 << " cx _gate_q_0, _gate_q_2;" << std::endl; + qasm3 << " cx _gate_q_2, _gate_q_3;" << std::endl; + qasm3 << " p(-pi/8) _gate_q_3;" << std::endl; + qasm3 << " cx _gate_q_1, _gate_q_3;" << std::endl; + qasm3 << " p(pi/8) _gate_q_3;" << std::endl; + qasm3 << " cx _gate_q_2, _gate_q_3;" << std::endl; + qasm3 << " p(-pi/8) _gate_q_3;" << std::endl; + qasm3 << " cx _gate_q_0, _gate_q_3;" << std::endl; + qasm3 << " p(pi/8) _gate_q_3;" << std::endl; + qasm3 << " cx _gate_q_2, _gate_q_3;" << std::endl; + qasm3 << " p(-pi/8) _gate_q_3;" << std::endl; + qasm3 << " cx _gate_q_1, _gate_q_3;" << std::endl; + qasm3 << " p(pi/8) _gate_q_3;" << std::endl; + qasm3 << " cx _gate_q_2, _gate_q_3;" << std::endl; + qasm3 << " p(-pi/8) _gate_q_3;" << std::endl; + qasm3 << " cx _gate_q_0, _gate_q_3;" << std::endl; + qasm3 << " h _gate_q_3;" << std::endl; + qasm3 << "}" << std::endl; + break; + case QkGate_C3SX: + qasm3 << "gate c3sx _gate_q_0, _gate_q_1, _gate_q_2, _gate_q_3 {" << std::endl; + qasm3 << " h _gate_q_3;" << std::endl; + qasm3 << " cp(pi/8) _gate_q_0, _gate_q_3;" << std::endl; + qasm3 << " h _gate_q_3;" << std::endl; + qasm3 << " cx _gate_q_0, _gate_q_1;" << std::endl; + qasm3 << " h _gate_q_3;" << std::endl; + qasm3 << " cp(-pi/8) _gate_q_1, _gate_q_3;" << std::endl; + qasm3 << " h _gate_q_3;" << std::endl; + qasm3 << " cx _gate_q_0, _gate_q_1;" << std::endl; + qasm3 << " h _gate_q_3;" << std::endl; + qasm3 << " cp(pi/8) _gate_q_1, _gate_q_3;" << std::endl; + qasm3 << " h _gate_q_3;" << std::endl; + qasm3 << " cx _gate_q_1, _gate_q_2;" << std::endl; + qasm3 << " h _gate_q_3;" << std::endl; + qasm3 << " cp(-pi/8) _gate_q_2, _gate_q_3;" << std::endl; + qasm3 << " h _gate_q_3;" << std::endl; + qasm3 << " cx _gate_q_0, _gate_q_2;" << std::endl; + qasm3 << " h _gate_q_3;" << std::endl; + qasm3 << " cp(pi/8) _gate_q_2, _gate_q_3;" << std::endl; + qasm3 << " h _gate_q_3;" << std::endl; + qasm3 << " cx _gate_q_1, _gate_q_2;" << std::endl; + qasm3 << " h _gate_q_3;" << std::endl; + qasm3 << " cp(-pi/8) _gate_q_2, _gate_q_3;" << std::endl; + qasm3 << " h _gate_q_3;" << std::endl; + qasm3 << " cx _gate_q_0, _gate_q_2;" << std::endl; + qasm3 << " h _gate_q_3;" << std::endl; + qasm3 << " cp(pi/8) _gate_q_2, _gate_q_3;" << std::endl; + qasm3 << " h _gate_q_3;" << std::endl; + qasm3 << "}" << std::endl; + break; + case QkGate_RC3X: + qasm3 << "gate rcccx _gate_q_0, _gate_q_1, _gate_q_2, _gate_q_3 {" << std::endl; + qasm3 << " h _gate_q_3;" << std::endl; + qasm3 << " t _gate_q_3;" << std::endl; + qasm3 << " cx _gate_q_2, _gate_q_3;" << std::endl; + qasm3 << " tdg _gate_q_3;" << std::endl; + qasm3 << " h _gate_q_3;" << std::endl; + qasm3 << " cx _gate_q_0, _gate_q_3;" << std::endl; + qasm3 << " t _gate_q_3;" << std::endl; + qasm3 << " cx _gate_q_1, _gate_q_3;" << std::endl; + qasm3 << " tdg _gate_q_3;" << std::endl; + qasm3 << " cx _gate_q_0, _gate_q_3;" << std::endl; + qasm3 << " t _gate_q_3;" << std::endl; + qasm3 << " cx _gate_q_1, _gate_q_3;" << std::endl; + qasm3 << " tdg _gate_q_3;" << std::endl; + qasm3 << " h _gate_q_3;" << std::endl; + qasm3 << " t _gate_q_3;" << std::endl; + qasm3 << " cx _gate_q_2, _gate_q_3;" << std::endl; + qasm3 << " tdg _gate_q_3;" << std::endl; + qasm3 << " h _gate_q_3;" << std::endl; + qasm3 << "}" << std::endl; + break; + case QkGate_CU1: + qasm3 << "gate cu1(p0) _gate_q_0, _gate_q_1 {" << std::endl; + qasm3 << " cp(p0) _gate_q_0 _gate_q_1;" << std::endl; + qasm3 << "}" << std::endl; + break; + case QkGate_CU3: + qasm3 << "gate cu3(p0, p1, p2) _gate_q_0, _gate_q_1 {" << std::endl; + qasm3 << " cu(p0, p1, p2, 0) _gate_q_0 _gate_q_1;" << std::endl; + qasm3 << "}" << std::endl; + break; + default: + break; + } + } + } + qk_opcounts_clear(&opcounts); + + // 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; + } + + auto recover_reg_data = [this](uint_t index) -> std::pair + { + 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()); + }; + + for (uint_t i = 0; i < nops; i++) { + QkCircuitInstruction *op = new QkCircuitInstruction; + qk_circuit_get_instruction(rust_circuit_.get(), i, op); + if (op->num_clbits > 0) { + if (op->num_qubits == op->num_clbits) { + for (uint_t j = 0; j < op->num_qubits; j++) { + 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; + } + } + } else { + if (strcmp(op->name, "u") == 0) { + qasm3 << "U"; + } else { + qasm3 << op->name; + } + if (op->num_params > 0) { + qasm3 << "("; + for (uint_t j = 0; j < op->num_params; j++) { + char* param = qk_param_str(op->params[j]); + qasm3 << param; + qk_str_free(param); + if (j != op->num_params - 1) + qasm3 << ", "; + } + qasm3 << ")"; + } + if (op->num_qubits > 0) { + qasm3 << " "; + for (uint_t j = 0; j < op->num_qubits; j++) { + qasm3 << qreg_name << "[" << op->qubits[j] << "]"; + if (j != op->num_qubits - 1) + qasm3 << ", "; + } + } + qasm3 << ";" << std::endl; + } + qk_circuit_instruction_clear(op); + } + + return qasm3.str(); + } /// @brief print circuit (this is for debug) - void print(void) const; + void print(void) const + { + uint_t nops; + nops = qk_circuit_num_instructions(rust_circuit_.get()); + + for (uint_t i = 0; i < nops; i++) { + QkOperationKind kind = qk_circuit_instruction_kind(rust_circuit_.get(), i); + QkCircuitInstruction *op = new QkCircuitInstruction; + qk_circuit_get_instruction(rust_circuit_.get(), i, op); + std::cout << op->name; + if (op->num_qubits > 0) { + std::cout << "("; + for (uint_t j = 0; j < op->num_qubits; j++) { + std::cout << op->qubits[j]; + if (j != op->num_qubits - 1) + std::cout << ", "; + } + std::cout << ") "; + } + if (op->num_clbits > 0) { + std::cout << "("; + for (uint_t j = 0; j < op->num_clbits; j++) { + std::cout << op->clbits[j]; + if (j != op->num_clbits - 1) + std::cout << ", "; + } + std::cout << ") "; + } + if (op->num_params > 0) { + std::cout << "["; + for (uint_t j = 0; j < op->num_params; j++) { + char* param = qk_param_str(op->params[j]); + std::cout << param; + qk_str_free(param); + if (j != op->num_params - 1) + std::cout << ", "; + } + std::cout << "]"; + } + std::cout << std::endl; + qk_circuit_instruction_clear(op); + } + } /// @brief draw the circuit - void draw(void) const; + void draw(void) const + { + QkCircuitDrawerConfig conf; + conf.bundle_cregs = true; + conf.merge_wires = false; + conf.fold = 0; + + char* out = qk_circuit_draw(rust_circuit_.get(), &conf); + std::cout << out << std::endl; + qk_str_free(out); + } /// @brief compare two circuits /// @param other a circuit to be compared with this circuit /// @return true if two circuits are the same - bool operator==(const QuantumCircuit& other) const; + bool operator==(const QuantumCircuit& other) const + { + if (global_phase_ != other.global_phase_) { + return false; + } + + // compare instructions + uint_t nops; + uint_t nops_other; + nops = qk_circuit_num_instructions(rust_circuit_.get()); + nops_other = qk_circuit_num_instructions(other.rust_circuit_.get()); + if (nops != nops_other) { + return false; + } + + for (uint_t i = 0; i < nops; i++) { + QkCircuitInstruction *op = new QkCircuitInstruction; + QkCircuitInstruction *op_other = new QkCircuitInstruction; + qk_circuit_get_instruction(rust_circuit_.get(), i, op); + qk_circuit_get_instruction(other.rust_circuit_.get(), i, op_other); + + if (std::string(op->name) != std::string(op_other->name)) { + qk_circuit_instruction_clear(op); + qk_circuit_instruction_clear(op_other); + return false; + } + if (op->num_qubits != op_other->num_qubits || op->num_clbits != op_other->num_clbits || op->num_params != op_other->num_params) { + qk_circuit_instruction_clear(op); + qk_circuit_instruction_clear(op_other); + return false; + } + for (int j = 0; j < op->num_qubits; j++) { + if (op->qubits[j] != op_other->qubits[j]) { + qk_circuit_instruction_clear(op); + qk_circuit_instruction_clear(op_other); + return false; + } + } + for (int j = 0; j < op->num_params; j++) { + QkParam* sub = qk_param_zero(); + qk_param_sub(sub, op->params[j], op_other->params[j]); + double diff = qk_param_as_real(sub); + qk_param_free(sub); + if (fabs(diff) > QC_COMPARE_EPS) { + qk_circuit_instruction_clear(op); + qk_circuit_instruction_clear(op_other); + return false; + } + } + for (int j = 0; j < op->num_clbits; j++) { + if (op->clbits[j] != op_other->clbits[j]) { + qk_circuit_instruction_clear(op); + qk_circuit_instruction_clear(op_other); + return false; + } + } + } + return true; + } + bool operator!=(const QuantumCircuit& other) const { return !(*this == other); @@ -708,8 +2032,27 @@ class QuantumCircuit add_pending_control_flow_op(); } - void get_qubits(reg_t &bits); - void get_clbits(reg_t &bits); + void get_qubits(reg_t &bits) + { + bits.clear(); + bits.reserve(num_qubits_); + for (uint_t i = 0; i < qregs_.size(); i++) { + for (uint_t j = 0; j < qregs_[i].size(); j++) { + bits.push_back(qregs_[i][j]); + } + } + } + + void get_clbits(reg_t &bits) + { + bits.clear(); + bits.reserve(num_clbits_); + for (uint_t i = 0; i < cregs_.size(); i++) { + for (uint_t j = 0; j < cregs_[i].size(); j++) { + bits.push_back(cregs_[i][j]); + } + } + } }; } // namespace circuit diff --git a/src/circuit/quantumcircuit_impl.hpp b/src/circuit/quantumcircuit_impl.hpp index 770cca6..2fc2022 100644 --- a/src/circuit/quantumcircuit_impl.hpp +++ b/src/circuit/quantumcircuit_impl.hpp @@ -12,7 +12,7 @@ # that they have been altered from the originals. */ -// Quantum circuit class implementations +// Quantum circuit class #ifndef __qiskitcpp_circuit_quantum_circuit_impl_hpp__ @@ -29,828 +29,11 @@ #include "controlflow/__init__.hpp" -#include "circuit/barrier.hpp" -#include "circuit/measure.hpp" -#include "circuit/reset.hpp" - - -namespace Qiskit { -namespace circuit { - -QuantumCircuit::QuantumCircuit(const uint_t num_qubits, const uint_t num_clbits, const double global_phase) -{ - num_qubits_ = num_qubits; - num_clbits_ = num_clbits; - global_phase_ = global_phase; - - qregs_.resize(1); - cregs_.resize(1); - - QuantumRegister qr(num_qubits_); - ClassicalRegister cr(num_clbits_); - qregs_[0] = qr; - cregs_[0] = cr; - - rust_circuit_ = std::shared_ptr(qk_circuit_new(0, 0), qk_circuit_free); - qk_circuit_add_quantum_register(rust_circuit_.get(), qregs_[0].get_register().get()); - qk_circuit_add_classical_register(rust_circuit_.get(), cregs_[0].get_register().get()); - - if (global_phase != 0.0) - { - qk_circuit_gate(rust_circuit_.get(), QkGate_GlobalPhase, nullptr, &global_phase_); - } -} - -QuantumCircuit::QuantumCircuit(QuantumRegister &qreg, ClassicalRegister &creg, const double global_phase) -{ - num_qubits_ = qreg.size(); - num_clbits_ = creg.size(); - global_phase_ = global_phase; - - qregs_.resize(1); - cregs_.resize(1); - - qregs_[0] = qreg; - cregs_[0] = creg; - - rust_circuit_ = std::shared_ptr(qk_circuit_new(0, 0), qk_circuit_free); - - qk_circuit_add_quantum_register(rust_circuit_.get(), qregs_[0].get_register().get()); - qk_circuit_add_classical_register(rust_circuit_.get(), cregs_[0].get_register().get()); - - if (global_phase != 0.0) - { - qk_circuit_gate(rust_circuit_.get(), QkGate_GlobalPhase, nullptr, &global_phase_); - } -} - -QuantumCircuit::QuantumCircuit(std::vector qregs, std::vector cregs, const double global_phase) -{ - num_qubits_ = 0; - num_clbits_ = 0; - global_phase_ = global_phase; - - qregs_.resize(qregs.size()); - cregs_.resize(cregs.size()); - - for (uint_t i = 0; i < qregs.size(); i++) - { - qregs_[i] = qregs[i]; - qregs[i][0].get_register()->set_base_index(num_qubits_); - qregs_[i].set_base_index(num_qubits_); - num_qubits_ += qregs[i].size(); - } - - for (uint_t i = 0; i < cregs.size(); i++) - { - cregs_[i] = cregs[i]; - cregs[i][0].get_register()->set_base_index(num_clbits_); - cregs_[i].set_base_index(num_clbits_); - num_clbits_ += cregs[i].size(); - } - - rust_circuit_ = std::shared_ptr(qk_circuit_new(0, 0), qk_circuit_free); - - for (uint_t i = 0; i < qregs_.size(); i++) - { - qk_circuit_add_quantum_register(rust_circuit_.get(), qregs_[i].get_register().get()); - } - for (uint_t i = 0; i < cregs_.size(); i++) - { - qk_circuit_add_classical_register(rust_circuit_.get(), cregs_[i].get_register().get()); - } - - if (global_phase != 0.0) - { - qk_circuit_gate(rust_circuit_.get(), QkGate_GlobalPhase, nullptr, &global_phase_); - } -} - -// create new circuit with same number of qubits -QuantumCircuit::QuantumCircuit(const QuantumCircuit &circ) -{ - num_qubits_ = circ.num_qubits_; - num_clbits_ = circ.num_clbits_; - global_phase_ = circ.global_phase_; - - qregs_ = circ.qregs_; - cregs_ = circ.cregs_; - - rust_circuit_ = circ.rust_circuit_; - - measure_map_ = circ.measure_map_; - qubit_map_ = circ.qubit_map_; -} - -QuantumCircuit QuantumCircuit::copy(void) -{ - QuantumCircuit copied; - copied.rust_circuit_ = std::shared_ptr(qk_circuit_copy(rust_circuit_.get()), qk_circuit_free); - - copied.num_qubits_ = num_qubits_; - copied.num_clbits_ = num_clbits_; - copied.global_phase_ = global_phase_; - - copied.qregs_ = qregs_; - copied.cregs_ = cregs_; - - copied.measure_map_ = measure_map_; - copied.qubit_map_ = qubit_map_; - return copied; -} - -void QuantumCircuit::set_qiskit_circuit(std::shared_ptr circ, const std::vector &map) -{ - if (rust_circuit_) - rust_circuit_.reset(); - rust_circuit_ = circ; - num_qubits_ = qk_circuit_num_qubits(circ.get()); - num_clbits_ = qk_circuit_num_clbits(circ.get()); - - qubit_map_.resize(map.size()); - for (int i = 0; i < map.size(); i++) { - qubit_map_[i] = (uint_t)map[i]; - } - - // get measured qubits - uint_t nops; - nops = qk_circuit_num_instructions(rust_circuit_.get()); - - for (uint_t i = 0; i < nops; i++) { - QkOperationKind kind = qk_circuit_instruction_kind(rust_circuit_.get(), i); - if (kind == QkOperationKind_Measure) { - QkCircuitInstruction *op = new QkCircuitInstruction; - qk_circuit_get_instruction(rust_circuit_.get(), i, op); - measure_map_.push_back(std::pair((uint_t)op->qubits[0], (uint_t)op->clbits[0])); - qk_circuit_instruction_clear(op); - } - } -} - -QuantumCircuit::~QuantumCircuit() -{ - if (pending_control_flow_op_) - { - pending_control_flow_op_.reset(); - } - - if (rust_circuit_) - { - rust_circuit_.reset(); - } -} - -void QuantumCircuit::get_qubits(reg_t &bits) -{ - bits.clear(); - bits.reserve(num_qubits_); - for (uint_t i = 0; i < qregs_.size(); i++) - { - for (uint_t j = 0; j < qregs_[i].size(); j++) - { - bits.push_back(qregs_[i][j]); - } - } -} - -void QuantumCircuit::get_clbits(reg_t &bits) -{ - bits.clear(); - bits.reserve(num_clbits_); - for (uint_t i = 0; i < cregs_.size(); i++) - { - for (uint_t j = 0; j < cregs_[i].size(); j++) - { - bits.push_back(cregs_[i][j]); - } - } -} - -void QuantumCircuit::global_phase(const double phase) -{ - global_phase_ = phase; - qk_circuit_gate(rust_circuit_.get(), QkGate_GlobalPhase, nullptr, &global_phase_); -} - -void QuantumCircuit::h(const uint_t qubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)qubit}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_H, qubits, nullptr); -} - -void QuantumCircuit::i(const uint_t qubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)qubit}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_I, qubits, nullptr); -} - -void QuantumCircuit::x(const uint_t qubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)qubit}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_X, qubits, nullptr); -} - -void QuantumCircuit::y(const uint_t qubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)qubit}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_Y, qubits, nullptr); -} - -void QuantumCircuit::z(const uint_t qubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)qubit}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_Z, qubits, nullptr); -} - -void QuantumCircuit::p(const double phase, const uint_t qubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)qubit}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_Phase, qubits, &phase); -} - -void QuantumCircuit::p(const Parameter &phase, const uint_t qubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)qubit}; - QkParam* params[] = {phase.qiskit_param_.get()}; - pre_add_gate(); - qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_Phase, qubits, params); -} - -void QuantumCircuit::r(const double theta, const double phi, const uint_t qubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)qubit}; - double params[] = {theta, phi}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_R, qubits, params); -} - -void QuantumCircuit::r(const Parameter &theta, const Parameter &phi, const uint_t qubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)qubit}; - QkParam* params[] = {theta.qiskit_param_.get(), phi.qiskit_param_.get()}; - pre_add_gate(); - qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_R, qubits, params); -} - -void QuantumCircuit::rx(const double theta, const uint_t qubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)qubit}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_RX, qubits, &theta); -} - -void QuantumCircuit::rx(const Parameter &theta, const uint_t qubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)qubit}; - QkParam* params[] = {theta.qiskit_param_.get()}; - pre_add_gate(); - qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_RX, qubits, params); -} - -void QuantumCircuit::ry(const double theta, const uint_t qubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)qubit}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_RY, qubits, &theta); -} - -void QuantumCircuit::ry(const Parameter &theta, const uint_t qubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)qubit}; - QkParam* params[] = {theta.qiskit_param_.get()}; - pre_add_gate(); - qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_RY, qubits, params); -} - -void QuantumCircuit::rz(const double theta, const uint_t qubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)qubit}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_RZ, qubits, &theta); -} - -void QuantumCircuit::rz(const Parameter &theta, const uint_t qubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)qubit}; - QkParam* params[] = {theta.qiskit_param_.get()}; - pre_add_gate(); - qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_RZ, qubits, params); -} - -void QuantumCircuit::s(const uint_t qubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)qubit}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_S, qubits, nullptr); -} - -void QuantumCircuit::sdg(const uint_t qubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)qubit}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_Sdg, qubits, nullptr); -} - -void QuantumCircuit::sx(const uint_t qubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)qubit}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_SX, qubits, nullptr); -} - -void QuantumCircuit::sxdg(const uint_t qubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)qubit}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_SXdg, qubits, nullptr); -} - -void QuantumCircuit::t(const uint_t qubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)qubit}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_T, qubits, nullptr); -} - -void QuantumCircuit::tdg(const uint_t qubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)qubit}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_Tdg, qubits, nullptr); -} - -void QuantumCircuit::u(const double theta, const double phi, const double lam, const uint_t qubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)qubit}; - double params[] = {theta, phi, lam}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_U, qubits, params); -} - -void QuantumCircuit::u(const Parameter &theta, const Parameter &phi, const Parameter &lam, const uint_t qubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)qubit}; - QkParam* params[] = {theta.qiskit_param_.get(), phi.qiskit_param_.get(), lam.qiskit_param_.get()}; - pre_add_gate(); - qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_U, qubits, params); -} - -void QuantumCircuit::u1(const double theta, const uint_t qubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)qubit}; - double params[] = {theta}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_U1, qubits, params); -} - -void QuantumCircuit::u1(const Parameter &theta, const uint_t qubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)qubit}; - QkParam* params[] = {theta.qiskit_param_.get()}; - pre_add_gate(); - qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_U1, qubits, params); -} - -void QuantumCircuit::u2(const double phi, const double lam, const uint_t qubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)qubit}; - double params[] = {phi, lam}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_U2, qubits, params); -} - -void QuantumCircuit::u2(const Parameter &phi, const Parameter &lam, const uint_t qubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)qubit}; - QkParam* params[] = {phi.qiskit_param_.get(), lam.qiskit_param_.get()}; - pre_add_gate(); - qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_U2, qubits, params); -} - -void QuantumCircuit::u3(const double theta, const double phi, const double lam, const uint_t qubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)qubit}; - double params[] = {theta, phi, lam}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_U3, qubits, params); -} - -void QuantumCircuit::u3(const Parameter &theta, const Parameter &phi, const Parameter &lam, const uint_t qubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)qubit}; - QkParam* params[] = {theta.qiskit_param_.get(), phi.qiskit_param_.get(), lam.qiskit_param_.get()}; - pre_add_gate(); - qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_U3, qubits, params); -} - -void QuantumCircuit::unitary(const std::vector &unitary, const reg_t &qubits) -{ - pre_add_gate(); - std::vector qubits32(qubits.size()); - for (uint_t i = 0; i < qubits.size(); i++) - qubits32[i] = (std::uint32_t)qubits[i]; - - qk_circuit_unitary(rust_circuit_.get(), (const QkComplex64 *)unitary.data(), qubits32.data(), (std::uint32_t)qubits.size(), true); -} - -void QuantumCircuit::ch(const uint_t cqubit, const uint_t tqubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_CH, qubits, nullptr); -} - -void QuantumCircuit::cx(const uint_t cqubit, const uint_t tqubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_CX, qubits, nullptr); -} - -void QuantumCircuit::cy(const uint_t cqubit, const uint_t tqubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_CY, qubits, nullptr); -} - -void QuantumCircuit::cz(const uint_t cqubit, const uint_t tqubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_CZ, qubits, nullptr); -} - -void QuantumCircuit::dcx(const uint_t qubit1, const uint_t qubit2) -{ - std::uint32_t qubits[] = {(std::uint32_t)qubit1, (std::uint32_t)qubit2}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_DCX, qubits, nullptr); -} - -void QuantumCircuit::ecr(const uint_t cqubit, const uint_t tqubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_ECR, qubits, nullptr); -} - -void QuantumCircuit::swap(const uint_t qubit1, const uint_t qubit2) -{ - std::uint32_t qubits[] = {(std::uint32_t)qubit1, (std::uint32_t)qubit2}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_Swap, qubits, nullptr); -} - -void QuantumCircuit::iswap(const uint_t qubit1, const uint_t qubit2) -{ - std::uint32_t qubits[] = {(std::uint32_t)qubit1, (std::uint32_t)qubit2}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_ISwap, qubits, nullptr); -} - -void QuantumCircuit::cp(const double phase, const uint_t cqubit, const uint_t tqubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_CPhase, qubits, &phase); -} - -void QuantumCircuit::cp(const Parameter &phase, const uint_t cqubit, const uint_t tqubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; - QkParam* params[] = {phase.qiskit_param_.get()}; - pre_add_gate(); - qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_CPhase, qubits, params); -} - -void QuantumCircuit::crx(const double theta, const uint_t cqubit, const uint_t tqubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_CRX, qubits, &theta); -} - -void QuantumCircuit::crx(const Parameter &theta, const uint_t cqubit, const uint_t tqubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; - QkParam* params[] = {theta.qiskit_param_.get()}; - pre_add_gate(); - qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_CRX, qubits, params); -} - -void QuantumCircuit::cry(const double theta, const uint_t cqubit, const uint_t tqubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_CRY, qubits, &theta); -} - -void QuantumCircuit::cry(const Parameter &theta, const uint_t cqubit, const uint_t tqubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; - QkParam* params[] = {theta.qiskit_param_.get()}; - pre_add_gate(); - qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_CRY, qubits, params); -} - -void QuantumCircuit::crz(const double theta, const uint_t cqubit, const uint_t tqubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_CRZ, qubits, &theta); -} - -void QuantumCircuit::crz(const Parameter &theta, const uint_t cqubit, const uint_t tqubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; - QkParam* params[] = {theta.qiskit_param_.get()}; - pre_add_gate(); - qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_CRZ, qubits, params); -} - -void QuantumCircuit::cs(const uint_t cqubit, const uint_t tqubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_CS, qubits, nullptr); -} - -void QuantumCircuit::csdg(const uint_t cqubit, const uint_t tqubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_CSdg, qubits, nullptr); -} - -void QuantumCircuit::csx(const uint_t cqubit, const uint_t tqubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_CSX, qubits, nullptr); -} - -void QuantumCircuit::cu(const double theta, const double phi, const double lam, const uint_t cqubit, const uint_t tqubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; - double params[] = {theta, phi, lam}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_CU, qubits, params); -} - -void QuantumCircuit::cu(const Parameter &theta, const Parameter &phi, const Parameter &lam, const uint_t cqubit, const uint_t tqubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; - QkParam* params[] = {theta.qiskit_param_.get(), phi.qiskit_param_.get(), lam.qiskit_param_.get()}; - pre_add_gate(); - qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_CU, qubits, params); -} - -void QuantumCircuit::cu1(const double theta, const uint_t cqubit, const uint_t tqubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; - double params[] = {theta}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_CU1, qubits, params); -} - -void QuantumCircuit::cu1(const Parameter &theta, const uint_t cqubit, const uint_t tqubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; - QkParam* params[] = {theta.qiskit_param_.get()}; - pre_add_gate(); - qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_CU1, qubits, params); -} - -void QuantumCircuit::cu3(const double theta, const double phi, const double lam, const uint_t cqubit, const uint_t tqubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; - double params[] = {theta, phi, lam}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_CU3, qubits, params); -} - -void QuantumCircuit::cu3(const Parameter &theta, const Parameter &phi, const Parameter &lam, const uint_t cqubit, const uint_t tqubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; - QkParam* params[] = {theta.qiskit_param_.get(), phi.qiskit_param_.get(), lam.qiskit_param_.get()}; - pre_add_gate(); - qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_CU3, qubits, params); -} - -void QuantumCircuit::rxx(const double theta, const uint_t qubit1, const uint_t qubit2) -{ - std::uint32_t qubits[] = {(std::uint32_t)qubit1, (std::uint32_t)qubit2}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_RXX, qubits, &theta); -} - -void QuantumCircuit::rxx(const Parameter &theta, const uint_t qubit1, const uint_t qubit2) -{ - std::uint32_t qubits[] = {(std::uint32_t)qubit1, (std::uint32_t)qubit2}; - QkParam* params[] = {theta.qiskit_param_.get()}; - pre_add_gate(); - qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_RXX, qubits, params); -} - -void QuantumCircuit::ryy(const double theta, const uint_t qubit1, const uint_t qubit2) -{ - std::uint32_t qubits[] = {(std::uint32_t)qubit1, (std::uint32_t)qubit2}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_RYY, qubits, &theta); -} - -void QuantumCircuit::ryy(const Parameter &theta, const uint_t qubit1, const uint_t qubit2) -{ - std::uint32_t qubits[] = {(std::uint32_t)qubit1, (std::uint32_t)qubit2}; - QkParam* params[] = {theta.qiskit_param_.get()}; - pre_add_gate(); - qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_RYY, qubits, params); -} - -void QuantumCircuit::rzz(const double theta, const uint_t qubit1, const uint_t qubit2) -{ - std::uint32_t qubits[] = {(std::uint32_t)qubit1, (std::uint32_t)qubit2}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_RZZ, qubits, &theta); -} - -void QuantumCircuit::rzz(const Parameter &theta, const uint_t qubit1, const uint_t qubit2) -{ - std::uint32_t qubits[] = {(std::uint32_t)qubit1, (std::uint32_t)qubit2}; - QkParam* params[] = {theta.qiskit_param_.get()}; - pre_add_gate(); - qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_RZZ, qubits, params); -} - -void QuantumCircuit::rzx(const double theta, const uint_t qubit1, const uint_t qubit2) -{ - std::uint32_t qubits[] = {(std::uint32_t)qubit1, (std::uint32_t)qubit2}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_RZX, qubits, &theta); -} - -void QuantumCircuit::rzx(const Parameter &theta, const uint_t qubit1, const uint_t qubit2) -{ - std::uint32_t qubits[] = {(std::uint32_t)qubit1, (std::uint32_t)qubit2}; - QkParam* params[] = {theta.qiskit_param_.get()}; - pre_add_gate(); - qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_RZX, qubits, params); -} - -void QuantumCircuit::xx_minus_yy(const double theta, const double beta, const uint_t qubit1, const uint_t qubit2) -{ - std::uint32_t qubits[] = {(std::uint32_t)qubit1, (std::uint32_t)qubit2}; - double params[] = {theta, beta}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_XXMinusYY, qubits, params); -} - -void QuantumCircuit::xx_minus_yy(const Parameter &theta, const Parameter &beta, const uint_t qubit1, const uint_t qubit2) -{ - std::uint32_t qubits[] = {(std::uint32_t)qubit1, (std::uint32_t)qubit2}; - QkParam* params[] = {theta.qiskit_param_.get(), beta.qiskit_param_.get()}; - pre_add_gate(); - qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_XXMinusYY, qubits, params); -} - -void QuantumCircuit::xx_plus_yy(const double theta, const double beta, const uint_t qubit1, const uint_t qubit2) -{ - std::uint32_t qubits[] = {(std::uint32_t)qubit1, (std::uint32_t)qubit2}; - double params[] = {theta, beta}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_XXPlusYY, qubits, params); -} - -void QuantumCircuit::xx_plus_yy(const Parameter &theta, const Parameter &beta, const uint_t qubit1, const uint_t qubit2) -{ - std::uint32_t qubits[] = {(std::uint32_t)qubit1, (std::uint32_t)qubit2}; - QkParam* params[] = {theta.qiskit_param_.get(), beta.qiskit_param_.get()}; - pre_add_gate(); - qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_XXPlusYY, qubits, params); -} - -void QuantumCircuit::ccx(const uint_t cqubit1, const uint_t cqubit2, const uint_t tqubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)cqubit1, (std::uint32_t)cqubit2, (std::uint32_t)tqubit}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_CCX, qubits, nullptr); -} - -void QuantumCircuit::ccz(const uint_t cqubit1, const uint_t cqubit2, const uint_t tqubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)cqubit1, (std::uint32_t)cqubit2, (std::uint32_t)tqubit}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_CCZ, qubits, nullptr); -} - -void QuantumCircuit::cswap(const uint_t cqubit, const uint_t qubit1, const uint_t qubit2) -{ - std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)qubit1, (std::uint32_t)qubit2}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_CSwap, qubits, nullptr); -} - -void QuantumCircuit::rccx(const uint_t cqubit1, const uint_t cqubit2, const uint_t tqubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)cqubit1, (std::uint32_t)cqubit2, (std::uint32_t)tqubit}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_RCCX, qubits, nullptr); -} - -void QuantumCircuit::cccx(const uint_t cqubit1, const uint_t cqubit2, const uint_t cqubit3, const uint_t tqubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)cqubit1, (std::uint32_t)cqubit2, (std::uint32_t)cqubit3, (std::uint32_t)tqubit}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_C3X, qubits, nullptr); -} - -void QuantumCircuit::cccsx(const uint_t cqubit1, const uint_t cqubit2, const uint_t cqubit3, const uint_t tqubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)cqubit1, (std::uint32_t)cqubit2, (std::uint32_t)cqubit3, (std::uint32_t)tqubit}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_C3SX, qubits, nullptr); -} - -void QuantumCircuit::rcccx(const uint_t cqubit1, const uint_t cqubit2, const uint_t cqubit3, const uint_t tqubit) -{ - std::uint32_t qubits[] = {(std::uint32_t)cqubit1, (std::uint32_t)cqubit2, (std::uint32_t)cqubit3, (std::uint32_t)tqubit}; - pre_add_gate(); - qk_circuit_gate(rust_circuit_.get(), QkGate_RC3X, qubits, nullptr); -} - -void QuantumCircuit::measure(const uint_t qubit, const uint_t cbit) -{ - pre_add_gate(); - qk_circuit_measure(rust_circuit_.get(), (std::uint32_t)qubit, (std::uint32_t)cbit); - measure_map_.push_back(std::pair(qubit, cbit)); -} - -void QuantumCircuit::measure(QuantumRegister &qreg, ClassicalRegister &creg) -{ - pre_add_gate(); - uint_t size = qreg.size(); - if (size > creg.size()) - size = creg.size(); - // TO DO implement multi-bits measure in C-API - for (uint_t i = 0; i < size; i++) - { - qk_circuit_measure(rust_circuit_.get(), (std::uint32_t)qreg[i], (std::uint32_t)creg[i]); - measure_map_.push_back(std::pair(qreg[i], creg[i])); - } -} - -void QuantumCircuit::reset(const uint_t qubit) -{ - pre_add_gate(); - qk_circuit_reset(rust_circuit_.get(), (std::uint32_t)qubit); -} - -void QuantumCircuit::reset(QuantumRegister &qreg) -{ - pre_add_gate(); - // TO DO implement multi-bits rest in C-API - for (uint_t i = 0; i < qreg.size(); i++) - { - qk_circuit_reset(rust_circuit_.get(), (std::uint32_t)qreg[i]); - } -} - -void QuantumCircuit::barrier(const uint_t qubit) -{ - pre_add_gate(); - std::uint32_t q = (std::uint32_t)qubit; - qk_circuit_barrier(rust_circuit_.get(), &q, 1); -} - -void QuantumCircuit::barrier(const reg_t &qubits) -{ - pre_add_gate(); - std::vector qubits32(qubits.size()); - for (uint_t i = 0; i < qubits.size(); i++) - { - qubits32[i] = (std::uint32_t)qubits[i]; - } - qk_circuit_barrier(rust_circuit_.get(), qubits32.data(), (uint32_t)qubits32.size()); -} +namespace Qiskit { +namespace circuit { -void QuantumCircuit::add_pending_control_flow_op(void) -{ - if (pending_control_flow_op_) - { - pending_control_flow_op_->add_control_flow_op(*this); - pending_control_flow_op_.reset(); - pending_control_flow_op_ = nullptr; - } -} -IfElseOp &QuantumCircuit::if_test(const std::uint32_t clbit, const std::uint32_t value, const std::function body) +inline IfElseOp& QuantumCircuit::if_test(const uint32_t clbit, const uint32_t value, const std::function body) { pre_add_gate(); @@ -862,769 +45,19 @@ IfElseOp &QuantumCircuit::if_test(const std::uint32_t clbit, const std::uint32_t return *op; } -uint_t QuantumCircuit::num_parameters(void) const -{ - return qk_circuit_num_param_symbols(rust_circuit_.get()); -} - -void QuantumCircuit::assign_parameters(const std::vector keys, const std::vector values) -{ - std::vector c_keys; - for (uint_t i = 0; i < keys.size(); i++) - { - c_keys.push_back((char *)keys[i].c_str()); - } - add_pending_control_flow_op(); - - // TO DO : add support for Parameter in Qiskit C-API - // qc_assign_parameters(rust_circuit_.get(), c_keys.data(), c_keys.size(), values.data(), values.size()); -} - -void QuantumCircuit::assign_parameter(const std::string key, const double val) -{ - add_pending_control_flow_op(); - - // TO DO : add support for Parameter in Qiskit C-API - // qc_assign_parameter(rust_circuit_.get(), (char*)key.c_str(), val); -} - -QuantumCircuit &QuantumCircuit::operator+=(QuantumCircuit &rhs) -{ - compose(rhs); - return *this; -} - -QuantumCircuit QuantumCircuit::operator+(QuantumCircuit &rhs) -{ - QuantumCircuit new_circ(*this); - if (num_qubits_ >= rhs.num_qubits_ && num_clbits_ >= rhs.num_clbits_) - { - reg_t qubits; - reg_t clbits; - rhs.get_qubits(qubits); - rhs.get_clbits(clbits); - uint_t size = std::min(qubits.size(), clbits.size()); - std::vector vqubits(size); - for (uint_t i = 0; i < size; i++) - { - vqubits[i] = (std::uint32_t)qubits[i]; - } - std::vector vclbits(size); - for (uint_t i = 0; i < size; i++) - { - vclbits[i] = (std::uint32_t)clbits[i]; - } - new_circ.compose(rhs); - } - return new_circ; -} -void QuantumCircuit::compose(QuantumCircuit &rhs) +inline void QuantumCircuit::add_pending_control_flow_op(void) { - if (num_qubits_ >= rhs.num_qubits_ && num_clbits_ >= rhs.num_clbits_) + if (pending_control_flow_op_) { - reg_t qubits; - reg_t clbits; - rhs.get_qubits(qubits); - rhs.get_clbits(clbits); - compose(rhs, qubits, clbits); - } -} - -void QuantumCircuit::compose(QuantumCircuit &circ, const reg_t &qubits, const reg_t &clbits) -{ - pre_add_gate(); - uint_t size = std::min(qubits.size(), clbits.size()); - std::vector vqubits(size); - for (uint_t i = 0; i < size; i++) { - vqubits[i] = (std::uint32_t)qubits[i]; - } - std::vector vclbits(size); - for (uint_t i = 0; i < size; i++) { - vclbits[i] = (std::uint32_t)clbits[i]; - } - - uint_t nops; - nops = qk_circuit_num_instructions(circ.rust_circuit_.get()); - - auto name_map = get_standard_gate_name_mapping(); - for (uint_t i = 0; i < nops; i++) { - QkCircuitInstruction *op = new QkCircuitInstruction; - qk_circuit_get_instruction(circ.rust_circuit_.get(), i, op); - - std::vector vqubits(op->num_qubits); - std::vector vclbits; - for (uint_t j = 0; j < op->num_qubits; j++) { - vqubits[j] = (std::uint32_t)qubits[op->qubits[j]]; - } - if (op->num_clbits > 0) { - vclbits.resize(op->num_clbits); - for (uint_t j = 0; j < op->num_clbits; j++) { - vclbits[j] = (std::uint32_t)clbits[op->clbits[j]]; - } - } - QkOperationKind kind = qk_circuit_instruction_kind(rust_circuit_.get(), i); - if (kind == QkOperationKind_Measure) { - qk_circuit_measure(rust_circuit_.get(), vqubits[0], vclbits[0]); - } else if (kind == QkOperationKind_Reset) { - qk_circuit_reset(rust_circuit_.get(), vqubits[0]); - } else if (kind == QkOperationKind_Barrier) { - qk_circuit_barrier(rust_circuit_.get(), vqubits.data(), (uint32_t)vqubits.size()); - } else if (kind == QkOperationKind_Gate) { - qk_circuit_parameterized_gate(rust_circuit_.get(), name_map[op->name].gate_map(), vqubits.data(), op->params); - } else if (kind == QkOperationKind_Unitary) { - // TO DO : how we can get unitary matrix from Rust ? - } - qk_circuit_instruction_clear(op); - } - - for (auto m : circ.measure_map_) { - measure_map_.push_back(m); - } -} - -void QuantumCircuit::append(const Instruction &op, const reg_t &qubits) -{ - if (op.num_qubits() == qubits.size()) { - std::vector vqubits(qubits.size()); - for (uint_t i = 0; i < qubits.size(); i++) { - vqubits[i] = (std::uint32_t)qubits[i]; - } - pre_add_gate(); - if (op.is_standard_gate()) { - if (op.num_params() > 0) { - std::vector params; - for (auto &p : op.params()) { - params.push_back(p.qiskit_param_.get()); - } - qk_circuit_parameterized_gate(rust_circuit_.get(), op.gate_map(), vqubits.data(), params.data()); - } - else - qk_circuit_gate(rust_circuit_.get(), op.gate_map(), vqubits.data(), nullptr); - } else { - if (std::string("reset") == op.name()) { - qk_circuit_reset(rust_circuit_.get(), vqubits[0]); - } - else if (std::string("barrier") == op.name()) { - qk_circuit_barrier(rust_circuit_.get(), vqubits.data(), (uint32_t)vqubits.size()); - } - else if (std::string("measure") == op.name()) { - qk_circuit_measure(rust_circuit_.get(), vqubits[0], vqubits[0]); - measure_map_.push_back(std::pair(qubits[0], qubits[0])); - } - } - } -} - -void QuantumCircuit::append(const Instruction &op, const std::vector &qubits) -{ - if (op.num_qubits() == qubits.size()) { - pre_add_gate(); - if (op.is_standard_gate()) { - if (op.num_params() > 0) { - std::vector params; - for (auto &p : op.params()) { - params.push_back(p.qiskit_param_.get()); - } - qk_circuit_parameterized_gate(rust_circuit_.get(), op.gate_map(), qubits.data(), params.data()); - } - else - qk_circuit_gate(rust_circuit_.get(), op.gate_map(), qubits.data(), nullptr); - } else { - if (std::string("reset") == op.name()) { - qk_circuit_reset(rust_circuit_.get(), qubits[0]); - } - else if (std::string("barrier") == op.name()) { - qk_circuit_barrier(rust_circuit_.get(), qubits.data(), (uint32_t)qubits.size()); - } - else if (std::string("measure") == op.name()) { - qk_circuit_measure(rust_circuit_.get(), qubits[0], qubits[0]); - measure_map_.push_back(std::pair((uint_t)qubits[0], (uint_t)qubits[0])); - } - } - } -} - -void QuantumCircuit::append(const CircuitInstruction &inst) -{ - std::vector vqubits(inst.qubits().size()); - for (uint_t i = 0; i < inst.qubits().size(); i++) { - vqubits[i] = (std::uint32_t)inst.qubits()[i]; - } - pre_add_gate(); - if (inst.instruction().is_standard_gate()) { - if (inst.instruction().num_params() > 0) { - std::vector params; - for (auto &p : inst.instruction().params()) { - params.push_back(p.qiskit_param_.get()); - } - qk_circuit_parameterized_gate(rust_circuit_.get(), inst.instruction().gate_map(), vqubits.data(), params.data()); - } - else - qk_circuit_gate(rust_circuit_.get(), inst.instruction().gate_map(), vqubits.data(), nullptr); - } else { - if (std::string("reset") == inst.instruction().name()) { - qk_circuit_reset(rust_circuit_.get(), vqubits[0]); - } - else if (std::string("barrier") == inst.instruction().name()) { - qk_circuit_barrier(rust_circuit_.get(), vqubits.data(), (uint32_t)vqubits.size()); - } - else if (std::string("measure") == inst.instruction().name()) { - qk_circuit_measure(rust_circuit_.get(), vqubits[0], (std::uint32_t)inst.clbits()[0]); - measure_map_.push_back(std::pair(inst.qubits()[0], inst.clbits()[0])); - } - } -} - -uint_t QuantumCircuit::num_instructions(void) -{ - return qk_circuit_num_instructions(rust_circuit_.get()); -} - -CircuitInstruction QuantumCircuit::operator[](uint_t i) -{ - if (i < qk_circuit_num_instructions(rust_circuit_.get())) { - auto name_map = get_standard_gate_name_mapping(); - - QkOperationKind kind = qk_circuit_instruction_kind(rust_circuit_.get(), i); - QkCircuitInstruction *op = new QkCircuitInstruction; - qk_circuit_get_instruction(rust_circuit_.get(), i, op); - reg_t qubits; - if (op->num_qubits > 0) { - qubits.resize(op->num_qubits); - for (int i = 0; i < op->num_qubits; i++) - qubits[i] = op->qubits[i]; - } - - reg_t clbits; - if (op->num_clbits > 0) { - clbits.resize(op->num_clbits); - for (int i = 0; i < op->num_clbits; i++) - clbits[i] = op->clbits[i]; - } - - std::vector params; - if (op->num_params > 0) { - params.resize(op->num_params); - for (int i = 0; i < op->num_params; i++) - params[i] = Parameter(qk_param_copy(op->params[i])); - } - std::string name = op->name; - qk_circuit_instruction_clear(op); - - if (kind == QkOperationKind_Measure) { - auto inst = Measure(); - return CircuitInstruction(inst, qubits, clbits); - } else if (kind == QkOperationKind_Reset) { - auto inst = Reset(); - return CircuitInstruction(inst, qubits, clbits); - } else if (kind == QkOperationKind_Barrier) { - auto inst = Barrier(); - return CircuitInstruction(inst, qubits, clbits); - } - - // standard gates - auto gate = name_map.find(name); - if (gate != name_map.end()) { - auto inst = gate->second; - if (params.size() > 0) { - inst.set_params(params); - } - return CircuitInstruction(inst, qubits); - } - } - return CircuitInstruction(); -} - -// print circuit -void QuantumCircuit::print(void) const -{ - uint_t nops; - nops = qk_circuit_num_instructions(rust_circuit_.get()); - - for (uint_t i = 0; i < nops; i++) { - QkOperationKind kind = qk_circuit_instruction_kind(rust_circuit_.get(), i); - QkCircuitInstruction *op = new QkCircuitInstruction; - qk_circuit_get_instruction(rust_circuit_.get(), i, op); - std::cout << op->name; - if (op->num_qubits > 0) { - std::cout << "("; - for (uint_t j = 0; j < op->num_qubits; j++) - { - std::cout << op->qubits[j]; - if (j != op->num_qubits - 1) - std::cout << ", "; - } - std::cout << ") "; - } - if (op->num_clbits > 0) { - std::cout << "("; - for (uint_t j = 0; j < op->num_clbits; j++) - { - std::cout << op->clbits[j]; - if (j != op->num_clbits - 1) - std::cout << ", "; - } - std::cout << ") "; - } - if (op->num_params > 0) { - std::cout << "["; - for (uint_t j = 0; j < op->num_params; j++) { - char* param = qk_param_str(op->params[j]); - std::cout << param; - qk_str_free(param); - if (j != op->num_params - 1) - std::cout << ", "; - } - std::cout << "]"; - } - std::cout << std::endl; - qk_circuit_instruction_clear(op); + pending_control_flow_op_->add_control_flow_op(*this); + pending_control_flow_op_.reset(); + pending_control_flow_op_ = nullptr; } } -void QuantumCircuit::draw(void) const -{ - QkCircuitDrawerConfig conf; - conf.bundle_cregs = true; - conf.merge_wires = false; - conf.fold = 0; - - char* out = qk_circuit_draw(rust_circuit_.get(), &conf); - std::cout << out << std::endl; - qk_str_free(out); -} - - - -std::string QuantumCircuit::to_qasm3(void) -{ - add_pending_control_flow_op(); - - std::stringstream qasm3; - qasm3 << std::setprecision(18); - qasm3 << "OPENQASM 3.0;" << std::endl; - qasm3 << "include \"stdgates.inc\";" << std::endl; - - auto name_map = get_standard_gate_name_mapping(); - // add header for non-standard gates - bool cs = false; - bool sxdg = false; - QkOpCounts opcounts = qk_circuit_count_ops(rust_circuit_.get()); - for (int i = 0; i < opcounts.len; i++) { - if (opcounts.data[i].count != 0) { - auto op = name_map[opcounts.data[i].name].gate_map(); - switch (op) - { - case QkGate_R: - qasm3 << "gate r(p0, p1) _gate_q_0 {" << std::endl; - qasm3 << " U(p0, -pi/2 + p1, pi/2 - p1) _gate_q_0;" << std::endl; - qasm3 << "}" << std::endl; - break; - case QkGate_SXdg: - case QkGate_RYY: - case QkGate_XXPlusYY: - case QkGate_XXMinusYY: - if (!sxdg) - { - qasm3 << "gate sxdg _gate_q_0 {" << std::endl; - qasm3 << " s _gate_q_0;" << std::endl; - qasm3 << " h _gate_q_0;" << std::endl; - qasm3 << " s _gate_q_0;" << std::endl; - qasm3 << "}" << std::endl; - sxdg = true; - } - if (op == QkGate_RYY) - { - qasm3 << "gate ryy(p0) _gate_q_0, _gate_q_1 {" << std::endl; - qasm3 << " sxdg _gate_q_0;" << std::endl; - qasm3 << " sxdg _gate_q_1;" << std::endl; - qasm3 << " cx _gate_q_0, _gate_q_1;" << std::endl; - qasm3 << " rz(p0) _gate_q_1;" << std::endl; - qasm3 << " cx _gate_q_0, _gate_q_1;" << std::endl; - qasm3 << " sx _gate_q_0;" << std::endl; - qasm3 << " sx _gate_q_1;" << std::endl; - qasm3 << "}" << std::endl; - } - if (op == QkGate_XXPlusYY) - { - qasm3 << "gate xx_plus_yy(p0, p1) _gate_q_0, _gate_q_1 {" << std::endl; - qasm3 << " rz(p1) _gate_q_0;" << std::endl; - qasm3 << " sdg _gate_q_1;" << std::endl; - qasm3 << " sx _gate_q_1;" << std::endl; - qasm3 << " s _gate_q_1;" << std::endl; - qasm3 << " s _gate_q_0;" << std::endl; - qasm3 << " cx _gate_q_1, _gate_q_0;" << std::endl; - qasm3 << " ry((-0.5)*p0) _gate_q_1;" << std::endl; - qasm3 << " ry((-0.5)*p0) _gate_q_0;" << std::endl; - qasm3 << " cx _gate_q_1, _gate_q_0;" << std::endl; - qasm3 << " sdg _gate_q_0;" << std::endl; - qasm3 << " sdg _gate_q_1;" << std::endl; - qasm3 << " sxdg _gate_q_1;" << std::endl; - qasm3 << " s _gate_q_1;" << std::endl; - qasm3 << " rz(-p1) _gate_q_0;" << std::endl; - qasm3 << "}" << std::endl; - } - if (op == QkGate_XXMinusYY) - { - qasm3 << "gate xx_minus_yy(p0, p1) _gate_q_0, _gate_q_1 {" << std::endl; - qasm3 << " rz(-p1) _gate_q_1;" << std::endl; - qasm3 << " sdg _gate_q_0;" << std::endl; - qasm3 << " sx _gate_q_0;" << std::endl; - qasm3 << " s _gate_q_0;" << std::endl; - qasm3 << " s _gate_q_1;" << std::endl; - qasm3 << " cx _gate_q_0, _gate_q_1;" << std::endl; - qasm3 << " ry(0.5*p0) _gate_q_0;" << std::endl; - qasm3 << " ry((-0.5)*p0) _gate_q_1;" << std::endl; - qasm3 << " cx _gate_q_0, _gate_q_1;" << std::endl; - qasm3 << " sdg _gate_q_1;" << std::endl; - qasm3 << " sdg _gate_q_0;" << std::endl; - qasm3 << " sxdg _gate_q_0;" << std::endl; - qasm3 << " s _gate_q_0;" << std::endl; - qasm3 << " rz(p1) _gate_q_1;" << std::endl; - qasm3 << "}" << std::endl; - } - break; - case QkGate_DCX: - qasm3 << "gate dcx _gate_q_0, _gate_q_1 {" << std::endl; - qasm3 << " cx _gate_q_0, _gate_q_1;" << std::endl; - qasm3 << " cx _gate_q_1, _gate_q_0;" << std::endl; - qasm3 << "}" << std::endl; - break; - case QkGate_ECR: - qasm3 << "gate ecr _gate_q_0, _gate_q_1 {" << std::endl; - qasm3 << " s _gate_q_0;" << std::endl; - qasm3 << " sx _gate_q_1;" << std::endl; - qasm3 << " cx _gate_q_0, _gate_q_1;" << std::endl; - qasm3 << " x _gate_q_0;" << std::endl; - qasm3 << "}" << std::endl; - break; - case QkGate_ISwap: - qasm3 << "gate iswap _gate_q_0, _gate_q_1 {" << std::endl; - qasm3 << " s _gate_q_0;" << std::endl; - qasm3 << " s _gate_q_1;" << std::endl; - qasm3 << " h _gate_q_0;" << std::endl; - qasm3 << " cx _gate_q_0, _gate_q_1;" << std::endl; - qasm3 << " cx _gate_q_1, _gate_q_0;" << std::endl; - qasm3 << " h _gate_q_1;" << std::endl; - qasm3 << "}" << std::endl; - break; - case QkGate_CSX: - case QkGate_CS: - if (!cs) - { - qasm3 << "gate cs _gate_q_0, _gate_q_1 {" << std::endl; - qasm3 << " t _gate_q_0;" << std::endl; - qasm3 << " cx _gate_q_0, _gate_q_1;" << std::endl; - qasm3 << " tdg _gate_q_1;" << std::endl; - qasm3 << " cx _gate_q_0, _gate_q_1;" << std::endl; - qasm3 << " t _gate_q_1;" << std::endl; - qasm3 << "}" << std::endl; - cs = true; - } - if (op == QkGate_CSX) - { - qasm3 << "gate csx _gate_q_0, _gate_q_1 {" << std::endl; - qasm3 << " h _gate_q_1;" << std::endl; - qasm3 << " cs _gate_q_0, _gate_q_1;" << std::endl; - qasm3 << " h _gate_q_1;" << std::endl; - qasm3 << "}" << std::endl; - } - break; - case QkGate_CSdg: - qasm3 << "gate csdg _gate_q_0, _gate_q_1 {" << std::endl; - qasm3 << " tdg _gate_q_0;" << std::endl; - qasm3 << " cx _gate_q_0, _gate_q_1;" << std::endl; - qasm3 << " t _gate_q_1;" << std::endl; - qasm3 << " cx _gate_q_0, _gate_q_1;" << std::endl; - qasm3 << " tdg _gate_q_1;" << std::endl; - qasm3 << "}" << std::endl; - break; - case QkGate_CCZ: - qasm3 << "gate ccz _gate_q_0, _gate_q_1, _gate_q_2 {" << std::endl; - qasm3 << " h _gate_q_2;" << std::endl; - qasm3 << " ccx _gate_q_0, _gate_q_1, _gate_q_2;" << std::endl; - qasm3 << " h _gate_q_2;" << std::endl; - qasm3 << "}" << std::endl; - break; - case QkGate_RXX: - qasm3 << "gate rxx(p0) _gate_q_0, _gate_q_1 {" << std::endl; - qasm3 << " h _gate_q_0;" << std::endl; - qasm3 << " h _gate_q_1;" << std::endl; - qasm3 << " cx _gate_q_0, _gate_q_1;" << std::endl; - qasm3 << " rz(p0) _gate_q_1;" << std::endl; - qasm3 << " cx _gate_q_0, _gate_q_1;" << std::endl; - qasm3 << " h _gate_q_1;" << std::endl; - qasm3 << " h _gate_q_0;" << std::endl; - qasm3 << "}" << std::endl; - break; - case QkGate_RZX: - qasm3 << "gate rzx(p0) _gate_q_0, _gate_q_1 {" << std::endl; - qasm3 << " h _gate_q_1;" << std::endl; - qasm3 << " cx _gate_q_0, _gate_q_1;" << std::endl; - qasm3 << " rz(p0) _gate_q_1;" << std::endl; - qasm3 << " cx _gate_q_0, _gate_q_1;" << std::endl; - qasm3 << " h _gate_q_1;" << std::endl; - qasm3 << "}" << std::endl; - break; - case QkGate_RZZ: - qasm3 << "gate rzz(p0) _gate_q_0, _gate_q_1 {" << std::endl; - qasm3 << " cx _gate_q_0, _gate_q_1;" << std::endl; - qasm3 << " rz(p0) _gate_q_1;" << std::endl; - qasm3 << " cx _gate_q_0, _gate_q_1;" << std::endl; - qasm3 << "}" << std::endl; - break; - case QkGate_RCCX: - qasm3 << "gate rccx _gate_q_0, _gate_q_1, _gate_q_2 {" << std::endl; - qasm3 << " h _gate_q_2;" << std::endl; - qasm3 << " t _gate_q_2;" << std::endl; - qasm3 << " cx _gate_q_1, _gate_q_2;" << std::endl; - qasm3 << " tdg _gate_q_2;" << std::endl; - qasm3 << " cx _gate_q_0, _gate_q_2;" << std::endl; - qasm3 << " t _gate_q_2;" << std::endl; - qasm3 << " cx _gate_q_1, _gate_q_2;" << std::endl; - qasm3 << " tdg _gate_q_2;" << std::endl; - qasm3 << " h _gate_q_2;" << std::endl; - qasm3 << "}" << std::endl; - break; - case QkGate_C3X: - qasm3 << "gate mcx _gate_q_0, _gate_q_1, _gate_q_2, _gate_q_3 {" << std::endl; - qasm3 << " h _gate_q_3;" << std::endl; - qasm3 << " p(pi/8) _gate_q_0;" << std::endl; - qasm3 << " p(pi/8) _gate_q_1;" << std::endl; - qasm3 << " p(pi/8) _gate_q_2;" << std::endl; - qasm3 << " p(pi/8) _gate_q_3;" << std::endl; - qasm3 << " cx _gate_q_0, _gate_q_1;" << std::endl; - qasm3 << " p(-pi/8) _gate_q_1;" << std::endl; - qasm3 << " cx _gate_q_0, _gate_q_1;" << std::endl; - qasm3 << " cx _gate_q_1, _gate_q_2;" << std::endl; - qasm3 << " p(-pi/8) _gate_q_2;" << std::endl; - qasm3 << " cx _gate_q_0, _gate_q_2;" << std::endl; - qasm3 << " p(pi/8) _gate_q_2;" << std::endl; - qasm3 << " cx _gate_q_1, _gate_q_2;" << std::endl; - qasm3 << " p(-pi/8) _gate_q_2;" << std::endl; - qasm3 << " cx _gate_q_0, _gate_q_2;" << std::endl; - qasm3 << " cx _gate_q_2, _gate_q_3;" << std::endl; - qasm3 << " p(-pi/8) _gate_q_3;" << std::endl; - qasm3 << " cx _gate_q_1, _gate_q_3;" << std::endl; - qasm3 << " p(pi/8) _gate_q_3;" << std::endl; - qasm3 << " cx _gate_q_2, _gate_q_3;" << std::endl; - qasm3 << " p(-pi/8) _gate_q_3;" << std::endl; - qasm3 << " cx _gate_q_0, _gate_q_3;" << std::endl; - qasm3 << " p(pi/8) _gate_q_3;" << std::endl; - qasm3 << " cx _gate_q_2, _gate_q_3;" << std::endl; - qasm3 << " p(-pi/8) _gate_q_3;" << std::endl; - qasm3 << " cx _gate_q_1, _gate_q_3;" << std::endl; - qasm3 << " p(pi/8) _gate_q_3;" << std::endl; - qasm3 << " cx _gate_q_2, _gate_q_3;" << std::endl; - qasm3 << " p(-pi/8) _gate_q_3;" << std::endl; - qasm3 << " cx _gate_q_0, _gate_q_3;" << std::endl; - qasm3 << " h _gate_q_3;" << std::endl; - qasm3 << "}" << std::endl; - break; - case QkGate_C3SX: - qasm3 << "gate c3sx _gate_q_0, _gate_q_1, _gate_q_2, _gate_q_3 {" << std::endl; - qasm3 << " h _gate_q_3;" << std::endl; - qasm3 << " cp(pi/8) _gate_q_0, _gate_q_3;" << std::endl; - qasm3 << " h _gate_q_3;" << std::endl; - qasm3 << " cx _gate_q_0, _gate_q_1;" << std::endl; - qasm3 << " h _gate_q_3;" << std::endl; - qasm3 << " cp(-pi/8) _gate_q_1, _gate_q_3;" << std::endl; - qasm3 << " h _gate_q_3;" << std::endl; - qasm3 << " cx _gate_q_0, _gate_q_1;" << std::endl; - qasm3 << " h _gate_q_3;" << std::endl; - qasm3 << " cp(pi/8) _gate_q_1, _gate_q_3;" << std::endl; - qasm3 << " h _gate_q_3;" << std::endl; - qasm3 << " cx _gate_q_1, _gate_q_2;" << std::endl; - qasm3 << " h _gate_q_3;" << std::endl; - qasm3 << " cp(-pi/8) _gate_q_2, _gate_q_3;" << std::endl; - qasm3 << " h _gate_q_3;" << std::endl; - qasm3 << " cx _gate_q_0, _gate_q_2;" << std::endl; - qasm3 << " h _gate_q_3;" << std::endl; - qasm3 << " cp(pi/8) _gate_q_2, _gate_q_3;" << std::endl; - qasm3 << " h _gate_q_3;" << std::endl; - qasm3 << " cx _gate_q_1, _gate_q_2;" << std::endl; - qasm3 << " h _gate_q_3;" << std::endl; - qasm3 << " cp(-pi/8) _gate_q_2, _gate_q_3;" << std::endl; - qasm3 << " h _gate_q_3;" << std::endl; - qasm3 << " cx _gate_q_0, _gate_q_2;" << std::endl; - qasm3 << " h _gate_q_3;" << std::endl; - qasm3 << " cp(pi/8) _gate_q_2, _gate_q_3;" << std::endl; - qasm3 << " h _gate_q_3;" << std::endl; - qasm3 << "}" << std::endl; - break; - case QkGate_RC3X: - qasm3 << "gate rcccx _gate_q_0, _gate_q_1, _gate_q_2, _gate_q_3 {" << std::endl; - qasm3 << " h _gate_q_3;" << std::endl; - qasm3 << " t _gate_q_3;" << std::endl; - qasm3 << " cx _gate_q_2, _gate_q_3;" << std::endl; - qasm3 << " tdg _gate_q_3;" << std::endl; - qasm3 << " h _gate_q_3;" << std::endl; - qasm3 << " cx _gate_q_0, _gate_q_3;" << std::endl; - qasm3 << " t _gate_q_3;" << std::endl; - qasm3 << " cx _gate_q_1, _gate_q_3;" << std::endl; - qasm3 << " tdg _gate_q_3;" << std::endl; - qasm3 << " cx _gate_q_0, _gate_q_3;" << std::endl; - qasm3 << " t _gate_q_3;" << std::endl; - qasm3 << " cx _gate_q_1, _gate_q_3;" << std::endl; - qasm3 << " tdg _gate_q_3;" << std::endl; - qasm3 << " h _gate_q_3;" << std::endl; - qasm3 << " t _gate_q_3;" << std::endl; - qasm3 << " cx _gate_q_2, _gate_q_3;" << std::endl; - qasm3 << " tdg _gate_q_3;" << std::endl; - qasm3 << " h _gate_q_3;" << std::endl; - qasm3 << "}" << std::endl; - break; - case QkGate_CU1: - qasm3 << "gate cu1(p0) _gate_q_0, _gate_q_1 {" << std::endl; - qasm3 << " cp(p0) _gate_q_0 _gate_q_1;" << std::endl; - qasm3 << "}" << std::endl; - break; - case QkGate_CU3: - qasm3 << "gate cu3(p0, p1, p2) _gate_q_0, _gate_q_1 {" << std::endl; - qasm3 << " cu(p0, p1, p2, 0) _gate_q_0 _gate_q_1;" << std::endl; - qasm3 << "}" << std::endl; - break; - default: - break; - } - } - } - qk_opcounts_clear(&opcounts); - - // 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; - } - - auto recover_reg_data = [this](uint_t index) -> std::pair - { - 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()); - }; - - for (uint_t i = 0; i < nops; i++) { - QkCircuitInstruction *op = new QkCircuitInstruction; - qk_circuit_get_instruction(rust_circuit_.get(), i, op); - if (op->num_clbits > 0) { - if (op->num_qubits == op->num_clbits) { - for (uint_t j = 0; j < op->num_qubits; j++) { - 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; - } - } - } else { - if (strcmp(op->name, "u") == 0) { - qasm3 << "U"; - } else { - qasm3 << op->name; - } - if (op->num_params > 0) { - qasm3 << "("; - for (uint_t j = 0; j < op->num_params; j++) { - char* param = qk_param_str(op->params[j]); - qasm3 << param; - qk_str_free(param); - if (j != op->num_params - 1) - qasm3 << ", "; - } - qasm3 << ")"; - } - if (op->num_qubits > 0) { - qasm3 << " "; - for (uint_t j = 0; j < op->num_qubits; j++) { - qasm3 << qreg_name << "[" << op->qubits[j] << "]"; - if (j != op->num_qubits - 1) - qasm3 << ", "; - } - } - qasm3 << ";" << std::endl; - } - qk_circuit_instruction_clear(op); - } - return qasm3.str(); } - - -#define QC_COMPARE_EPS (1e-15) - -bool QuantumCircuit::operator==(const QuantumCircuit& other) const -{ - if (global_phase_ != other.global_phase_) { - return false; - } - - // compare instructions - uint_t nops; - uint_t nops_other; - nops = qk_circuit_num_instructions(rust_circuit_.get()); - nops_other = qk_circuit_num_instructions(other.rust_circuit_.get()); - if (nops != nops_other) { - return false; - } - - for (uint_t i = 0; i < nops; i++) { - QkCircuitInstruction *op = new QkCircuitInstruction; - QkCircuitInstruction *op_other = new QkCircuitInstruction; - qk_circuit_get_instruction(rust_circuit_.get(), i, op); - qk_circuit_get_instruction(other.rust_circuit_.get(), i, op_other); - - if (std::string(op->name) != std::string(op_other->name)) { - qk_circuit_instruction_clear(op); - qk_circuit_instruction_clear(op_other); - return false; - } - if (op->num_qubits != op_other->num_qubits || op->num_clbits != op_other->num_clbits || op->num_params != op_other->num_params) { - qk_circuit_instruction_clear(op); - qk_circuit_instruction_clear(op_other); - return false; - } - for (int j = 0; j < op->num_qubits; j++) { - if (op->qubits[j] != op_other->qubits[j]) { - qk_circuit_instruction_clear(op); - qk_circuit_instruction_clear(op_other); - return false; - } - } - for (int j = 0; j < op->num_params; j++) { - QkParam* sub = qk_param_zero(); - qk_param_sub(sub, op->params[j], op_other->params[j]); - double diff = qk_param_as_real(sub); - qk_param_free(sub); - if (fabs(diff) > QC_COMPARE_EPS) { - qk_circuit_instruction_clear(op); - qk_circuit_instruction_clear(op_other); - return false; - } - } - for (int j = 0; j < op->num_clbits; j++) { - if (op->clbits[j] != op_other->clbits[j]) { - qk_circuit_instruction_clear(op); - qk_circuit_instruction_clear(op_other); - return false; - } - } - } - return true; } - - -} // namespace circuit -} // namespace Qiskit - - #endif // __qiskitcpp_circuit_quantum_circuit_impl_hpp__ - diff --git a/src/circuit/quantumregister.hpp b/src/circuit/quantumregister.hpp index 5f25e50..22914a8 100644 --- a/src/circuit/quantumregister.hpp +++ b/src/circuit/quantumregister.hpp @@ -17,9 +17,17 @@ #ifndef __qiskitcpp_circuit_quantum_register_hpp__ #define __qiskitcpp_circuit_quantum_register_hpp__ +#include + #include "circuit/register.hpp" #include "qiskit.h" + +namespace { + std::atomic QR_counter(0ull); +} + + namespace Qiskit { namespace circuit @@ -34,8 +42,7 @@ class QuantumRegister : public Register { protected: std::shared_ptr rust_register_ = nullptr; - static uint_t instances_counter_; - +// static uint_t instances_counter_; public: /// @brief Create a new generic register QuantumRegister() @@ -85,12 +92,12 @@ class QuantumRegister : public Register std::string prefix(void) override { std::string ret = "q"; - ret += std::to_string(instances_counter_++); + ret += std::to_string(QR_counter++); return ret; } }; -uint_t QuantumRegister::instances_counter_ = 0; +//inline uint_t QuantumRegister::instances_counter_ = 0; } // namespace circuit } // namespace Qiskit diff --git a/src/circuit/register.hpp b/src/circuit/register.hpp index b0b2b92..eb4fd90 100644 --- a/src/circuit/register.hpp +++ b/src/circuit/register.hpp @@ -123,11 +123,35 @@ class Register /// @param (size) The number of bits to include in the register /// @param (name) The name of the register. If not provided, a unique name will be auto-generated from the register type. /// @param (bits) A list of Bit instances to be used to populate the register. - Register(uint_t size, std::string name, std::vector &bits); + Register(uint_t size, std::string name, std::vector &bits) + { + if (size != bits.size()) + { + throw std::runtime_error("Register : size of bits and size is different"); + } + + size_ = size; + bits_ = bits; + + for (uint_t i = 0; i < size; i++) + { + bits[i].register_ = this; + bits[i].index_ = (uint32_t)i; + bits_[i].register_ = this; + bits_[i].index_ = (uint32_t)i; + } + } /// @brief Create a new generic register as a copy of reg /// @param (reg) copy source - Register(const Register ®); + Register(const Register ®) + { + size_ = reg.size_; + name_ = reg.name_; + bits_ = reg.bits_; + base_index_ = reg.base_index_; + } + /// @brief Resize this register with size /// @param (size) new size of this register @@ -166,58 +190,25 @@ class Register protected: virtual std::string prefix(void) = 0; - void allocate_bits(void); + void allocate_bits(void) + { + bits_.resize(size_); + for (uint_t i = 0; i < size_; i++) + { + bits_[i].register_ = this; + bits_[i].index_ = (uint32_t)i; + } + } }; -// ======================= -// class for bit -// ======================= -uint32_t Bit::global_index(void) + +inline uint32_t Bit::global_index(void) { if (register_) return (uint32_t)register_->base_index_ + index_; return index_; } -// ======================= -// base class for register -// ======================= -Register::Register(uint_t size, std::string name, std::vector &bits) -{ - if (size != bits.size()) - { - throw std::runtime_error("Register : size of bits and size is different"); - } - - size_ = size; - bits_ = bits; - - for (uint_t i = 0; i < size; i++) - { - bits[i].register_ = this; - bits[i].index_ = (uint32_t)i; - bits_[i].register_ = this; - bits_[i].index_ = (uint32_t)i; - } -} - -Register::Register(const Register ®) -{ - size_ = reg.size_; - name_ = reg.name_; - bits_ = reg.bits_; - base_index_ = reg.base_index_; -} - -void Register::allocate_bits(void) -{ - bits_.resize(size_); - for (uint_t i = 0; i < size_; i++) - { - bits_[i].register_ = this; - bits_[i].index_ = (uint32_t)i; - } -} } // namespace circuit } // namespace Qiskit diff --git a/src/compiler/transpiler.hpp b/src/compiler/transpiler.hpp index 96674db..ae055c5 100644 --- a/src/compiler/transpiler.hpp +++ b/src/compiler/transpiler.hpp @@ -31,7 +31,7 @@ namespace compiler { /// @param seed_transpiler The seed for the transpiler (default = -1) /// @param approximation_degree The approximation degree a heurstic dial (default = 1.0) /// @return transpiled QuantumCircuit -circuit::QuantumCircuit transpile(circuit::QuantumCircuit &circ, providers::BackendV2 &backend, int optimization_level = 2, double approximation_degree = 1.0, int seed_transpiler = -1) +inline circuit::QuantumCircuit transpile(circuit::QuantumCircuit &circ, providers::BackendV2 &backend, int optimization_level = 2, double approximation_degree = 1.0, int seed_transpiler = -1) { auto target = backend.target(); auto capi_target = target.rust_target(); diff --git a/src/primitives/containers/bit_array.hpp b/src/primitives/containers/bit_array.hpp index f3a6b06..df2a69a 100644 --- a/src/primitives/containers/bit_array.hpp +++ b/src/primitives/containers/bit_array.hpp @@ -84,193 +84,167 @@ class BitArray { } // from simulator samples (< 64 qubits) - void from_samples(const reg_t& samples, uint_t num_bits); - void from_samples(const uint_t* samples, uint_t num_samples, uint_t num_bits); + void from_samples(const reg_t& samples, uint_t num_bits) + { + num_bits_ = num_bits; + array_.resize(samples.size()); + for (uint_t i = 0; i < samples.size(); i++) { + array_[i].from_uint(samples[i], num_bits); + } + } + + void from_samples(const uint_t* samples, uint_t num_samples, uint_t num_bits) + { + num_bits_ = num_bits; + array_.resize(num_samples); + for (uint_t i = 0; i < num_samples; i++) { + array_[i].from_uint(samples[i], num_bits); + } + } + // from bitstring - void from_bitstring(const std::vector& samples); + void from_bitstring(const std::vector& samples) + { + array_.resize(samples.size()); + for (uint_t i = 0; i < samples.size(); i++) { + array_[i].from_string(samples[i]); + } + num_bits_ = array_[0].size(); + } /// @brief Return subsets of the BitArray /// @param start_bit start bit index of subset /// @param num_bits number of bits in a subset /// @return A new BitArray - BitArray get_subset(const uint_t start_bit, const uint_t num_bits); + BitArray get_subset(const uint_t start_bit, const uint_t num_bits) + { + BitArray ret; + ret.allocate(array_.size(), num_bits); + + for (uint_t i = 0; i < array_.size(); i++) { + ret.array_[i] = array_[i].get_subset(start_bit, num_bits); + } + + return ret; + } /// @brief Return a list of bitstrings. /// @return A list of bitstrings. - std::vector get_bitstrings(void); + std::vector get_bitstrings(void) + { + std::vector ret(array_.size()); + for (uint_t i = 0; i < array_.size(); i++) { + ret[i] = array_[i].to_string(); + } + return ret; + } /// @brief Return a list of bitstrings. /// @param index a list of index to be stored in the output list /// @return A list of bitstrings. - std::vector get_bitstrings(reg_t& index); + std::vector get_bitstrings(reg_t& index) + { + uint_t size = std::min(array_.size(), index.size()); + std::vector ret(size); + + for (uint_t i = 0; i < size; i++) { + uint_t pos = index[i]; + if (pos < array_.size()) + ret[i] = array_[pos].to_string(); + } + return ret; + } /// @brief Return a list of hex string /// @return A list of hex string. - std::vector get_hexstrings(void); + std::vector get_hexstrings(void) + { + std::vector ret(array_.size()); + for (uint_t i = 0; i < array_.size(); i++) { + ret[i] = array_[i].to_hex_string(); + } + return ret; + } /// @brief Return a list of hex string. /// @param index a list of index to be stored in the output list /// @return A list of hex string. - std::vector get_hexstrings(reg_t& index); + std::vector get_hexstrings(reg_t& index) + { + uint_t size = std::min(array_.size(), index.size()); + std::vector ret(size); + + for (uint_t i = 0; i < size; i++) { + uint_t pos = index[i]; + if (pos < array_.size()) + ret[i] = array_[pos].to_hex_string(); + } + return ret; + } /// @brief Return a counts dictionary with bitstring keys. /// @return A counts dictionary with bitstring keys. - std::unordered_map get_counts(void); + std::unordered_map get_counts(void) + { + std::unordered_map ret; + for (uint_t i = 0; i < array_.size(); i++) { + ret[array_[i].to_string()]++; + } + return ret; + } /// @brief Return a counts dictionary with bitstring keys. /// @param index a list of index to be stored in the output map /// @return A counts dictionary with bitstring keys. - std::unordered_map get_counts(reg_t& index); + std::unordered_map get_counts(reg_t& index) + { + uint_t size = std::min(array_.size(), index.size()); + std::unordered_map ret; + + for (uint_t i = 0; i < size; i++) { + uint_t pos = index[i]; + if (pos < array_.size()) + ret[array_[pos].to_string()]++; + } + return ret; + } /// @brief Set pub samples from json /// @param input JSON input - void from_json(nlohmann::ordered_json& input); + void from_json(nlohmann::ordered_json& input) + { + auto samples = input["samples"]; + auto num_bits = input["num_bits"]; + auto num_shots = samples.size(); + if (num_bits_ == 0) + num_bits_ = num_bits; + allocate(num_shots, num_bits_); + for (uint_t i = 0; i < num_shots; i++) { + array_[i].from_hex_string(samples[i]); + } + } /// @brief Set pub sample from hexstring /// @param index an index to be set /// @param input a sample in a hex string format - void set_hexstring(uint_t index, std::string& input); + void set_hexstring(uint_t index, std::string& input) + { + if (index < array_.size()) + array_[index].from_hex_string(input); + } /// @brief Return a list of bit counts /// @return A list of interger counts of bits appears in each shot - reg_t bitcount(void); - -}; - -void BitArray::from_samples(const reg_t& samples, uint_t num_bits) -{ - num_bits_ = num_bits; - array_.resize(samples.size()); - for (uint_t i = 0; i < samples.size(); i++) { - array_[i].from_uint(samples[i], num_bits); - } -} - -void BitArray::from_samples(const uint_t* samples, uint_t num_samples, uint_t num_bits) -{ - num_bits_ = num_bits; - array_.resize(num_samples); - for (uint_t i = 0; i < num_samples; i++) { - array_[i].from_uint(samples[i], num_bits); - } -} - -void BitArray::from_bitstring(const std::vector& samples) -{ - array_.resize(samples.size()); - for (uint_t i = 0; i < samples.size(); i++) { - array_[i].from_string(samples[i]); - } - num_bits_ = array_[0].size(); -} - -std::vector BitArray::get_bitstrings(void) -{ - std::vector ret(array_.size()); - for (uint_t i = 0; i < array_.size(); i++) { - ret[i] = array_[i].to_string(); - } - return ret; -} - -std::vector BitArray::get_bitstrings(reg_t& index) -{ - uint_t size = std::min(array_.size(), index.size()); - std::vector ret(size); - - for (uint_t i = 0; i < size; i++) { - uint_t pos = index[i]; - if (pos < array_.size()) - ret[i] = array_[pos].to_string(); - } - return ret; -} - -std::vector BitArray::get_hexstrings(void) -{ - std::vector ret(array_.size()); - for (uint_t i = 0; i < array_.size(); i++) { - ret[i] = array_[i].to_hex_string(); - } - return ret; -} - -std::vector BitArray::get_hexstrings(reg_t& index) -{ - uint_t size = std::min(array_.size(), index.size()); - std::vector ret(size); - - for (uint_t i = 0; i < size; i++) { - uint_t pos = index[i]; - if (pos < array_.size()) - ret[i] = array_[pos].to_hex_string(); - } - return ret; -} - - -std::unordered_map BitArray::get_counts(void) -{ - std::unordered_map ret; - for (uint_t i = 0; i < array_.size(); i++) { - ret[array_[i].to_string()]++; - } - return ret; -} - -std::unordered_map BitArray::get_counts(reg_t& index) -{ - uint_t size = std::min(array_.size(), index.size()); - std::unordered_map ret; - - for (uint_t i = 0; i < size; i++) { - uint_t pos = index[i]; - if (pos < array_.size()) - ret[array_[pos].to_string()]++; - } - return ret; -} - -void BitArray::from_json(nlohmann::ordered_json& input) -{ - auto samples = input["samples"]; - auto num_bits = input["num_bits"]; - auto num_shots = samples.size(); - if (num_bits_ == 0) - num_bits_ = num_bits; - allocate(num_shots, num_bits_); - for (uint_t i = 0; i < num_shots; i++) { - array_[i].from_hex_string(samples[i]); - } -} - -void BitArray::set_hexstring(uint_t index, std::string& input) -{ - if (index < array_.size()) - array_[index].from_hex_string(input); -} - -BitArray BitArray::get_subset(const uint_t start_bit, const uint_t num_bits) -{ - BitArray ret; - ret.allocate(array_.size(), num_bits); - - for (uint_t i = 0; i < array_.size(); i++) { - ret.array_[i] = array_[i].get_subset(start_bit, num_bits); - } - - return ret; -} - -reg_t BitArray::bitcount(void) -{ - reg_t count(array_.size()); - for (uint_t i = 0; i < array_.size(); i++) { - count[i] = array_[i].popcount(); + reg_t bitcount(void) + { + reg_t count(array_.size()); + for (uint_t i = 0; i < array_.size(); i++) { + count[i] = array_[i].popcount(); + } + return count; } - return count; -} +}; } // namespace primitives diff --git a/src/providers/sqc_backend.hpp b/src/providers/sqc_backend.hpp index 34ebb75..d20a80c 100644 --- a/src/providers/sqc_backend.hpp +++ b/src/providers/sqc_backend.hpp @@ -31,8 +31,6 @@ namespace Qiskit { namespace providers { -std::string replace_all(std::string s, const std::string& from, const std::string& to); - /// @class SQCBackend /// @brief Backend class using SQC. class SQCBackend : public BackendV2 { @@ -126,26 +124,27 @@ class SQCBackend : public BackendV2 { return std::make_shared(results_json); } -}; - -std::string replace_all(std::string s, const std::string& from, const std::string& to) { - if (from.empty()) return s; - std::string out; - out.reserve(s.size()); - std::size_t pos = 0; - while (true) { - std::size_t found = s.find(from, pos); - if (found == std::string::npos) { - out.append(s, pos, std::string::npos); - break; + std::string replace_all(std::string s, const std::string& from, const std::string& to) { + if (from.empty()) return s; + std::string out; + out.reserve(s.size()); + std::size_t pos = 0; + while (true) { + std::size_t found = s.find(from, pos); + if (found == std::string::npos) { + out.append(s, pos, std::string::npos); + break; + } + out.append(s, pos, found - pos); + out.append(to); + pos = found + from.size(); } - out.append(s, pos, found - pos); - out.append(to); - pos = found + from.size(); + return out; } - return out; -} +}; + + } // namespace providers diff --git a/src/quantum_info/sparse_observable.hpp b/src/quantum_info/sparse_observable.hpp index e56b239..0e8895d 100644 --- a/src/quantum_info/sparse_observable.hpp +++ b/src/quantum_info/sparse_observable.hpp @@ -37,8 +37,19 @@ class SparseObservable { obs_ = nullptr; } - SparseObservable(uint_t num_qubits, std::vector> &coeffs, std::vector &terms, reg_t &indicies, std::vector &boundaries); - SparseObservable(const SparseObservable &other); + SparseObservable(uint_t num_qubits, std::vector> &coeffs, std::vector &bits, reg_t &indicies, std::vector &boundaries) + { + std::vector idx32(indicies.size()); + for (int i = 0; i < indicies.size(); i++) { + idx32[i] = (std::uint32_t)indicies[i]; + } + obs_ = qk_obs_new((std::uint32_t)num_qubits, coeffs.size(), bits.size(), (QkComplex64 *)coeffs.data(), bits.data(), idx32.data(), boundaries.data()); + } + + SparseObservable(const SparseObservable &other) + { + obs_ = qk_obs_copy(other.obs_); + } ~SparseObservable() { @@ -62,8 +73,119 @@ class SparseObservable return ret; } - static SparseObservable from_label(std::string &label); - static SparseObservable from_list(std::vector>> &list, uint_t num_qubits = 0); + static SparseObservable from_label(std::string &label) + { + reg_t indices; + std::vector boundaries(2); + uint_t num_qubits = label.length(); + std::vector terms; + std::vector> coeff(1); + coeff[0] = 1.0; + + for (int i = 0; i < num_qubits; i++) + { + switch (label[num_qubits - 1 - i]) + { + case 'X': + terms.push_back(QkBitTerm_X); + break; + case 'Y': + terms.push_back(QkBitTerm_Y); + break; + case 'Z': + terms.push_back(QkBitTerm_Z); + break; + case '+': + terms.push_back(QkBitTerm_Plus); + break; + case '-': + terms.push_back(QkBitTerm_Minus); + break; + case 'l': + terms.push_back(QkBitTerm_Left); + break; + case 'r': + terms.push_back(QkBitTerm_Right); + break; + case '0': + terms.push_back(QkBitTerm_Zero); + break; + case '1': + terms.push_back(QkBitTerm_One); + break; + default: + break; + } + if (indices.size() < terms.size()) + indices.push_back(i); + } + boundaries[0] = 0; + boundaries[1] = terms.size(); + return SparseObservable(num_qubits, coeff, terms, indices, boundaries); + } + + static SparseObservable from_list(std::vector>> &list, uint_t num_qubits_in = 0) + { + reg_t indices; + std::vector boundaries; + uint_t num_qubits = num_qubits_in; + std::vector terms; + std::vector> coeffs; + boundaries.push_back(0); + + for (int i = 0; i < list.size(); i++) + { + if (num_qubits == 0) + { + num_qubits = list[i].first.length(); + } + else if (num_qubits != list[i].first.length()) + { + std::cerr << " SparseObservable : Error label with length " << list[i].first.length() << "cannot be added to a " << num_qubits << "-qubits operator" << std::endl; + abort(); + } + for (int j = 0; j < num_qubits; j++) + { + switch (list[i].first[num_qubits - 1 - j]) + { + case 'X': + terms.push_back(QkBitTerm_X); + break; + case 'Y': + terms.push_back(QkBitTerm_Y); + break; + case 'Z': + terms.push_back(QkBitTerm_Z); + break; + case '+': + terms.push_back(QkBitTerm_Plus); + break; + case '-': + terms.push_back(QkBitTerm_Minus); + break; + case 'l': + terms.push_back(QkBitTerm_Left); + break; + case 'r': + terms.push_back(QkBitTerm_Right); + break; + case '0': + terms.push_back(QkBitTerm_Zero); + break; + case '1': + terms.push_back(QkBitTerm_One); + break; + default: + break; + } + if (indices.size() < terms.size()) + indices.push_back(j); + } + boundaries.push_back(terms.size()); + coeffs.push_back(list[i].second); + } + return SparseObservable(num_qubits, coeffs, terms, indices, boundaries); + } uint_t num_qubits(void) const { @@ -134,194 +256,56 @@ class SparseObservable return ret; } - SparseObservable operator+(SparseObservable &rhs); - SparseObservable &operator+=(SparseObservable &rhs); - SparseObservable operator*(std::complex &rhs); - SparseObservable &operator*=(std::complex &rhs); - - bool operator==(SparseObservable &rhs); - - SparseObservable compose(SparseObservable &other); - - std::string to_string(void); -}; - -SparseObservable::SparseObservable(uint_t num_qubits, std::vector> &coeffs, std::vector &bits, reg_t &indicies, std::vector &boundaries) -{ - std::vector idx32(indicies.size()); - for (int i = 0; i < indicies.size(); i++) + SparseObservable operator+(SparseObservable &rhs) { - idx32[i] = (std::uint32_t)indicies[i]; + SparseObservable ret; + ret.obs_ = qk_obs_add(obs_, rhs.obs_); + return ret; } - obs_ = qk_obs_new((std::uint32_t)num_qubits, coeffs.size(), bits.size(), (QkComplex64 *)coeffs.data(), bits.data(), idx32.data(), boundaries.data()); -} - -SparseObservable::SparseObservable(const SparseObservable &other) -{ - obs_ = qk_obs_copy(other.obs_); -} -SparseObservable SparseObservable::operator+(SparseObservable &rhs) -{ - SparseObservable ret; - ret.obs_ = qk_obs_add(obs_, rhs.obs_); - return ret; -} - -SparseObservable &SparseObservable::operator+=(SparseObservable &rhs) -{ - QkObs *t = qk_obs_add(obs_, rhs.obs_); - qk_obs_free(obs_); - obs_ = t; - return *this; -} - -SparseObservable SparseObservable::operator*(std::complex &rhs) -{ - SparseObservable ret; - ret.obs_ = qk_obs_multiply(obs_, (QkComplex64 *)&rhs); - return ret; -} -SparseObservable &SparseObservable::operator*=(std::complex &rhs) -{ - QkObs *t = qk_obs_multiply(obs_, (QkComplex64 *)&rhs); - qk_obs_free(obs_); - obs_ = t; - return *this; -} -bool SparseObservable::operator==(SparseObservable &rhs) -{ - return qk_obs_equal(obs_, rhs.obs_); -} - -SparseObservable SparseObservable::compose(SparseObservable &other) -{ - SparseObservable ret; - ret.obs_ = qk_obs_compose(obs_, other.obs_); - return ret; -} + SparseObservable &operator+=(SparseObservable &rhs) + { + QkObs *t = qk_obs_add(obs_, rhs.obs_); + qk_obs_free(obs_); + obs_ = t; + return *this; + } -SparseObservable SparseObservable::from_label(std::string &label) -{ - reg_t indices; - std::vector boundaries(2); - uint_t num_qubits = label.length(); - std::vector terms; - std::vector> coeff(1); - coeff[0] = 1.0; + SparseObservable operator*(std::complex &rhs) + { + SparseObservable ret; + ret.obs_ = qk_obs_multiply(obs_, (QkComplex64 *)&rhs); + return ret; + } - for (int i = 0; i < num_qubits; i++) + SparseObservable &operator*=(std::complex &rhs) { - switch (label[num_qubits - 1 - i]) - { - case 'X': - terms.push_back(QkBitTerm_X); - break; - case 'Y': - terms.push_back(QkBitTerm_Y); - break; - case 'Z': - terms.push_back(QkBitTerm_Z); - break; - case '+': - terms.push_back(QkBitTerm_Plus); - break; - case '-': - terms.push_back(QkBitTerm_Minus); - break; - case 'l': - terms.push_back(QkBitTerm_Left); - break; - case 'r': - terms.push_back(QkBitTerm_Right); - break; - case '0': - terms.push_back(QkBitTerm_Zero); - break; - case '1': - terms.push_back(QkBitTerm_One); - break; - default: - break; - } - if (indices.size() < terms.size()) - indices.push_back(i); + QkObs *t = qk_obs_multiply(obs_, (QkComplex64 *)&rhs); + qk_obs_free(obs_); + obs_ = t; + return *this; } - boundaries[0] = 0; - boundaries[1] = terms.size(); - return SparseObservable(num_qubits, coeff, terms, indices, boundaries); -} -SparseObservable SparseObservable::from_list(std::vector>> &list, uint_t num_qubits_in) -{ - reg_t indices; - std::vector boundaries; - uint_t num_qubits = num_qubits_in; - std::vector terms; - std::vector> coeffs; - boundaries.push_back(0); + bool operator==(SparseObservable &rhs) + { + return qk_obs_equal(obs_, rhs.obs_); + } - for (int i = 0; i < list.size(); i++) + SparseObservable compose(SparseObservable &other) { - if (num_qubits == 0) - { - num_qubits = list[i].first.length(); - } - else if (num_qubits != list[i].first.length()) - { - std::cerr << " SparseObservable : Error label with length " << list[i].first.length() << "cannot be added to a " << num_qubits << "-qubits operator" << std::endl; - abort(); - } - for (int j = 0; j < num_qubits; j++) - { - switch (list[i].first[num_qubits - 1 - j]) - { - case 'X': - terms.push_back(QkBitTerm_X); - break; - case 'Y': - terms.push_back(QkBitTerm_Y); - break; - case 'Z': - terms.push_back(QkBitTerm_Z); - break; - case '+': - terms.push_back(QkBitTerm_Plus); - break; - case '-': - terms.push_back(QkBitTerm_Minus); - break; - case 'l': - terms.push_back(QkBitTerm_Left); - break; - case 'r': - terms.push_back(QkBitTerm_Right); - break; - case '0': - terms.push_back(QkBitTerm_Zero); - break; - case '1': - terms.push_back(QkBitTerm_One); - break; - default: - break; - } - if (indices.size() < terms.size()) - indices.push_back(j); - } - boundaries.push_back(terms.size()); - coeffs.push_back(list[i].second); + SparseObservable ret; + ret.obs_ = qk_obs_compose(obs_, other.obs_); + return ret; } - return SparseObservable(num_qubits, coeffs, terms, indices, boundaries); -} -std::string SparseObservable::to_string(void) -{ - char *str = qk_obs_str(obs_); - std::string ret = str; - qk_str_free(str); - return ret; -} + std::string to_string(void) + { + char *str = qk_obs_str(obs_); + std::string ret = str; + qk_str_free(str); + return ret; + } +}; } // namespace quantum_info } // namespace Qiskit diff --git a/src/transpiler/passmanager.hpp b/src/transpiler/passmanager.hpp index f3811c8..0e49595 100644 --- a/src/transpiler/passmanager.hpp +++ b/src/transpiler/passmanager.hpp @@ -115,121 +115,120 @@ class StagedPassManager : public PassManager } - circuit::QuantumCircuit run(circuit::QuantumCircuit& circ) override; -}; + circuit::QuantumCircuit run(circuit::QuantumCircuit& circ) override + { + QkTranspileOptions options = qk_transpiler_default_options(); + options.optimization_level = optimization_level_; + options.approximation_degree = approximation_degree_; + if (seed_transpiler_ >= 0) { + options.seed = seed_transpiler_; + } + char *error; + QkExitCode ret; + if (stages_.size() == 6) { + if (stages_[0] == "init" && stages_[1] == "layout" && stages_[2] == "routing" && + stages_[3] == "translation" && stages_[4] == "optimization" && stages_[5] == "scheduling") { + // use default transpiler -circuit::QuantumCircuit StagedPassManager::run(circuit::QuantumCircuit& circ) -{ - QkTranspileOptions options = qk_transpiler_default_options(); - options.optimization_level = optimization_level_; - options.approximation_degree = approximation_degree_; - if (seed_transpiler_ >= 0) { - options.seed = seed_transpiler_; - } - char *error; - QkExitCode ret; + QkTranspileResult result; - if (stages_.size() == 6) { - if (stages_[0] == "init" && stages_[1] == "layout" && stages_[2] == "routing" && - stages_[3] == "translation" && stages_[4] == "optimization" && stages_[5] == "scheduling") { - // use default transpiler + ret = qk_transpile(circ.get_rust_circuit().get(), target_.rust_target(), &options, &result, &error); + if (ret != QkExitCode_Success) { + std::cerr << "transpile error (" << ret << ") : " << error << std::endl; + return circ.copy(); + } + // save qubit map after transpile + std::vector layout_map(qk_transpile_layout_num_output_qubits(result.layout)); + qk_transpile_layout_final_layout(result.layout, false, layout_map.data()); - QkTranspileResult result; + circuit::QuantumCircuit transpiled = circ; + transpiled.set_qiskit_circuit(std::shared_ptr(result.circuit, qk_circuit_free), layout_map); - ret = qk_transpile(circ.get_rust_circuit().get(), target_.rust_target(), &options, &result, &error); - if (ret != QkExitCode_Success) { - std::cerr << "transpile error (" << ret << ") : " << error << std::endl; - return circ.copy(); + qk_transpile_layout_free(result.layout); + return transpiled; } - // save qubit map after transpile - std::vector layout_map(qk_transpile_layout_num_output_qubits(result.layout)); - qk_transpile_layout_final_layout(result.layout, false, layout_map.data()); - - circuit::QuantumCircuit transpiled = circ; - transpiled.set_qiskit_circuit(std::shared_ptr(result.circuit, qk_circuit_free), layout_map); - - qk_transpile_layout_free(result.layout); - return transpiled; } - } - QkDag* dag = qk_circuit_to_dag(circ.get_rust_circuit().get()); - if (dag == nullptr) { - return circ.copy(); - } - QkTranspilerStageState* state = nullptr; + QkDag* dag = qk_circuit_to_dag(circ.get_rust_circuit().get()); + if (dag == nullptr) { + return circ.copy(); + } + QkTranspilerStageState* state = nullptr; - for (auto stage : stages_) { - if (stage == "init") { - ret = qk_transpile_stage_init(dag, target_.rust_target(), &options, &state, &error); - if (ret != QkExitCode_Success) { - std::cerr << "StagedPassManager Error in init stage (" << ret << ") : " << error << std::endl; - } - } else if (stage == "layout") { - ret = qk_transpile_stage_layout(dag, target_.rust_target(), &options, &state, &error); - if (ret != QkExitCode_Success) { - std::cerr << "StagedPassManager Error in layout stage (" << ret << ") : " << error << std::endl; - } - } else if (stage == "routing") { - if (state == nullptr) { - int nq_dag = qk_dag_num_qubits(dag); - std::vector def_map(nq_dag + 1, 0); - for (int i = 0; i < nq_dag; i++) { - def_map[i] = (uint32_t)i; + for (auto stage : stages_) { + if (stage == "init") { + ret = qk_transpile_stage_init(dag, target_.rust_target(), &options, &state, &error); + if (ret != QkExitCode_Success) { + std::cerr << "StagedPassManager Error in init stage (" << ret << ") : " << error << std::endl; + } + } else if (stage == "layout") { + ret = qk_transpile_stage_layout(dag, target_.rust_target(), &options, &state, &error); + if (ret != QkExitCode_Success) { + std::cerr << "StagedPassManager Error in layout stage (" << ret << ") : " << error << std::endl; + } + } else if (stage == "routing") { + if (state == nullptr) { + int nq_dag = qk_dag_num_qubits(dag); + std::vector def_map(nq_dag + 1, 0); + for (int i = 0; i < nq_dag; i++) { + def_map[i] = (uint32_t)i; + } + QkTranspileLayout* def_layout = qk_transpile_layout_generate_from_mapping(dag, target_.rust_target(), def_map.data()); + qk_transpile_state_new(&state); + qk_transpile_state_layout_set(state, def_layout); } - QkTranspileLayout* def_layout = qk_transpile_layout_generate_from_mapping(dag, target_.rust_target(), def_map.data()); - qk_transpile_state_new(&state); - qk_transpile_state_layout_set(state, def_layout); - } - ret = qk_transpile_stage_routing(dag, target_.rust_target(), &options, state, &error); - if (ret != QkExitCode_Success) { - std::cerr << "StagedPassManager Error in routing stage (" << ret << ") : " << error << std::endl; - } - } else if (stage == "translation") { - ret = qk_transpile_stage_translation(dag, target_.rust_target(), &options, &error); - if (ret != QkExitCode_Success) { - std::cerr << "StagedPassManager Error in transplation stage (" << ret << ") : " << error << std::endl; - } - } else if (stage == "optimization") { - if (state == nullptr) { - int nq_dag = qk_dag_num_qubits(dag); - std::vector def_map(nq_dag + 1, 0); - for (int i = 0; i < nq_dag; i++) { - def_map[i] = (uint32_t)i; + ret = qk_transpile_stage_routing(dag, target_.rust_target(), &options, state, &error); + if (ret != QkExitCode_Success) { + std::cerr << "StagedPassManager Error in routing stage (" << ret << ") : " << error << std::endl; + } + } else if (stage == "translation") { + ret = qk_transpile_stage_translation(dag, target_.rust_target(), &options, &error); + if (ret != QkExitCode_Success) { + std::cerr << "StagedPassManager Error in transplation stage (" << ret << ") : " << error << std::endl; + } + } else if (stage == "optimization") { + if (state == nullptr) { + int nq_dag = qk_dag_num_qubits(dag); + std::vector def_map(nq_dag + 1, 0); + for (int i = 0; i < nq_dag; i++) { + def_map[i] = (uint32_t)i; + } + QkTranspileLayout* def_layout = qk_transpile_layout_generate_from_mapping(dag, target_.rust_target(), def_map.data()); + qk_transpile_state_new(&state); + qk_transpile_state_layout_set(state, def_layout); } - QkTranspileLayout* def_layout = qk_transpile_layout_generate_from_mapping(dag, target_.rust_target(), def_map.data()); - qk_transpile_state_new(&state); - qk_transpile_state_layout_set(state, def_layout); - } - ret = qk_transpile_stage_optimization(dag, target_.rust_target(), &options, &error, state); - if (ret != QkExitCode_Success) { - std::cerr << "StagedPassManager Error in optimization stage (" << ret << ") : " << error << std::endl; + ret = qk_transpile_stage_optimization(dag, target_.rust_target(), &options, &error, state); + if (ret != QkExitCode_Success) { + std::cerr << "StagedPassManager Error in optimization stage (" << ret << ") : " << error << std::endl; + } + } else if (stage == "scheduling") { + // to be implemented (?) in C-API } - } else if (stage == "scheduling") { - // to be implemented (?) in C-API } - } - QkCircuit* result_circ = qk_dag_to_circuit(dag); + QkCircuit* result_circ = qk_dag_to_circuit(dag); + + circuit::QuantumCircuit transpiled = circ; + if (state) { + QkTranspileLayout* layout = qk_transpile_state_layout(state); + std::vector layout_map(qk_transpile_layout_num_output_qubits(layout)); + qk_transpile_layout_final_layout(layout, false, layout_map.data()); - circuit::QuantumCircuit transpiled = circ; - if (state) { - QkTranspileLayout* layout = qk_transpile_state_layout(state); - std::vector layout_map(qk_transpile_layout_num_output_qubits(layout)); - qk_transpile_layout_final_layout(layout, false, layout_map.data()); + transpiled.set_qiskit_circuit(std::shared_ptr(result_circ, qk_circuit_free), layout_map); - transpiled.set_qiskit_circuit(std::shared_ptr(result_circ, qk_circuit_free), layout_map); + qk_transpile_state_free(state); + } else { + std::vector layout_map; + transpiled.set_qiskit_circuit(std::shared_ptr(result_circ, qk_circuit_free), layout_map); + } - qk_transpile_state_free(state); - } else { - std::vector layout_map; - transpiled.set_qiskit_circuit(std::shared_ptr(result_circ, qk_circuit_free), layout_map); + return transpiled; } +}; + - return transpiled; -} diff --git a/src/transpiler/preset_passmanagers/generate_preset_pass_manager.hpp b/src/transpiler/preset_passmanagers/generate_preset_pass_manager.hpp index e519df6..414df5c 100644 --- a/src/transpiler/preset_passmanagers/generate_preset_pass_manager.hpp +++ b/src/transpiler/preset_passmanagers/generate_preset_pass_manager.hpp @@ -35,7 +35,7 @@ const std::vector default_stages = {"init", "layout", "routing", "t /// (1.0=no approximation, 0.0=maximal approximation). /// @param seed_transpiler Sets random seed for the stochastic parts of the transpiler. /// @return a new preset pass manager -StagedPassManager generate_preset_pass_manager(uint_t optimization_level, providers::BackendV2& backend, double approximation_degree = 1.0, int seed_transpiler = -1) +inline StagedPassManager generate_preset_pass_manager(uint_t optimization_level, providers::BackendV2& backend, double approximation_degree = 1.0, int seed_transpiler = -1) { return StagedPassManager(default_stages, backend, optimization_level, approximation_degree, seed_transpiler); } @@ -48,7 +48,7 @@ StagedPassManager generate_preset_pass_manager(uint_t optimization_level, provid /// (1.0=no approximation, 0.0=maximal approximation). /// @param seed_transpiler Sets random seed for the stochastic parts of the transpiler. /// @return a new preset pass manager -StagedPassManager generate_preset_pass_manager(uint_t optimization_level, Target& target, double approximation_degree = 1.0, int seed_transpiler = -1) +inline StagedPassManager generate_preset_pass_manager(uint_t optimization_level, Target& target, double approximation_degree = 1.0, int seed_transpiler = -1) { return StagedPassManager(default_stages, target, optimization_level, approximation_degree, seed_transpiler); } @@ -61,7 +61,7 @@ StagedPassManager generate_preset_pass_manager(uint_t optimization_level, Target /// (1.0=no approximation, 0.0=maximal approximation). /// @param seed_transpiler Sets random seed for the stochastic parts of the transpiler. /// @return a new preset pass manager -StagedPassManager generate_preset_pass_manager(uint_t optimization_level, const std::vector& basis_gates, const std::vector>& coupling_map, double approximation_degree = 1.0, int seed_transpiler = -1) +inline StagedPassManager generate_preset_pass_manager(uint_t optimization_level, const std::vector& basis_gates, const std::vector>& coupling_map, double approximation_degree = 1.0, int seed_transpiler = -1) { auto target = Target(basis_gates, coupling_map); return StagedPassManager(default_stages, target, optimization_level, approximation_degree, seed_transpiler); @@ -75,7 +75,7 @@ StagedPassManager generate_preset_pass_manager(uint_t optimization_level, const /// (1.0=no approximation, 0.0=maximal approximation). /// @param seed_transpiler Sets random seed for the stochastic parts of the transpiler. /// @return a new preset pass manager -StagedPassManager generate_preset_pass_manager(uint_t optimization_level, const std::unordered_map>& props, double approximation_degree = 1.0, int seed_transpiler = -1) +inline StagedPassManager generate_preset_pass_manager(uint_t optimization_level, const std::unordered_map>& props, double approximation_degree = 1.0, int seed_transpiler = -1) { auto target = Target(props); return StagedPassManager(default_stages, target, optimization_level, approximation_degree, seed_transpiler); diff --git a/src/transpiler/target.hpp b/src/transpiler/target.hpp index 6e1391a..55c2642 100644 --- a/src/transpiler/target.hpp +++ b/src/transpiler/target.hpp @@ -87,7 +87,49 @@ class Target properties_ = props; } - Target(const std::vector& basis_gates, const std::vector>& coupling_map, double default_duration = 0.0, double default_error = 0.0); + Target(const std::vector& basis_gates, const std::vector>& coupling_map, double default_duration = 0.0, double default_error = 0.0) + { + basis_gates_ = basis_gates; + coupling_map_ = coupling_map; + + // get num qubits + num_qubits_ = 0; + for (auto &qubits : coupling_map) { + if (qubits.first > num_qubits_) { + num_qubits_ = qubits.first; + } + if (qubits.second > num_qubits_) { + num_qubits_ = qubits.second; + } + } + num_qubits_ += 1; + + auto name_map = Qiskit::circuit::get_standard_gate_name_mapping(); + for (auto &gate_name : basis_gates) { + std::vector props; + auto gate = name_map.find(gate_name); + if (gate != name_map.end()) { + if (gate->second.num_qubits() == 1) { + for (uint_t i = 0; i < num_qubits_; i++) { + InstructionProperty p; + p.qargs = {(uint32_t)i}; + p.duration = default_duration; + p.error = default_error; + props.push_back(p); + } + } else if (gate->second.num_qubits() == 2) { + for (auto &qargs : coupling_map) { + InstructionProperty p; + p.qargs = {qargs.first, qargs.second}; + p.duration = default_duration; + p.error = default_error; + props.push_back(p); + } + } + } + properties_[gate_name] = props; + } + } ~Target() { @@ -134,274 +176,218 @@ class Target /// @brief make target from json /// @param input json target obtained from IQP /// @return true if target is successfully made - bool from_json(nlohmann::ordered_json &input); - - /// @brief add instruction to the target - /// @param instruction reference to the instruction to be added - /// @param properties properties of the instruction - void add_instruction(const circuit::Instruction& instruction, const std::vector& properties); - -protected: - void build_target(void); - -}; - - -Target::Target(const std::vector& basis_gates, const std::vector>& coupling_map, double default_duration, double default_error) -{ - basis_gates_ = basis_gates; - coupling_map_ = coupling_map; - - // get num qubits - num_qubits_ = 0; - for (auto &qubits : coupling_map) { - if (qubits.first > num_qubits_) { - num_qubits_ = qubits.first; + bool from_json(nlohmann::ordered_json &input) + { + if (!input.contains("configuration")) { + std::cerr << " Target Error : No configuration section found" << std::endl; + return false; } - if (qubits.second > num_qubits_) { - num_qubits_ = qubits.second; + auto backend_configuration = input["configuration"]; + if (!input.contains("properties")) { + std::cerr << " Target Error : No properties section found" << std::endl; + return false; } - } - num_qubits_ += 1; - - auto name_map = Qiskit::circuit::get_standard_gate_name_mapping(); - for (auto &gate_name : basis_gates) { - std::vector props; - auto gate = name_map.find(gate_name); - if (gate != name_map.end()) { - if (gate->second.num_qubits() == 1) { - for (uint_t i = 0; i < num_qubits_; i++) { - InstructionProperty p; - p.qargs = {(uint32_t)i}; - p.duration = default_duration; - p.error = default_error; - props.push_back(p); - } - } else if (gate->second.num_qubits() == 2) { - for (auto &qargs : coupling_map) { - InstructionProperty p; - p.qargs = {qargs.first, qargs.second}; - p.duration = default_duration; - p.error = default_error; - props.push_back(p); - } - } - } - properties_[gate_name] = props; - } -} - + auto backend_properties = input["properties"]; -bool Target::from_json(nlohmann::ordered_json &input) -{ - if (!input.contains("configuration")) { - std::cerr << " Target Error : No configuration section found" << std::endl; - return false; - } - auto backend_configuration = input["configuration"]; - if (!input.contains("properties")) { - std::cerr << " Target Error : No properties section found" << std::endl; - return false; - } - auto backend_properties = input["properties"]; - - if (!backend_configuration.contains("n_qubits")) { - std::cerr << " Target Error : n_qubits not found in backend config" << std::endl; - return false; - } - num_qubits_ = backend_configuration["n_qubits"]; - - if (target_) { - target_.reset(); - } + if (!backend_configuration.contains("n_qubits")) { + std::cerr << " Target Error : n_qubits not found in backend config" << std::endl; + return false; + } + num_qubits_ = backend_configuration["n_qubits"]; - QkTarget* t = qk_target_new((uint32_t)num_qubits_); - if (t == nullptr) - return false; - target_ = std::shared_ptr(t, qk_target_free); + if (target_) { + target_.reset(); + } - max_experiments_ = backend_configuration["max_experiments"]; - max_shots_ = backend_configuration["max_shots"]; + QkTarget* t = qk_target_new((uint32_t)num_qubits_); + if (t == nullptr) + return false; + target_ = std::shared_ptr(t, qk_target_free); - // set target configs available in C-API - if (backend_configuration.at("dt").is_number()) { - dt_ = backend_configuration["dt"]; - qk_target_set_dt(target_.get(), dt_); - } - if (backend_configuration.contains("timing_constraints")) { - auto timing_constraints = backend_configuration["timing_constraints"]; - qk_target_set_granularity(target_.get(), timing_constraints["granularity"]); - qk_target_set_min_length(target_.get(), timing_constraints["min_length"]); - qk_target_set_pulse_alignment(target_.get(), timing_constraints["pulse_alignment"]); - qk_target_set_acquire_alignment(target_.get(), timing_constraints["acquire_alignment"]); - } + max_experiments_ = backend_configuration["max_experiments"]; + max_shots_ = backend_configuration["max_shots"]; - // get basis gates and make property entries - auto name_map = Qiskit::circuit::get_standard_gate_name_mapping(); - for (auto &gate : backend_configuration["basis_gates"]) { - basis_gates_.push_back(gate); - } + // set target configs available in C-API + if (backend_configuration.at("dt").is_number()) { + dt_ = backend_configuration["dt"]; + qk_target_set_dt(target_.get(), dt_); + } + if (backend_configuration.contains("timing_constraints")) { + auto timing_constraints = backend_configuration["timing_constraints"]; + qk_target_set_granularity(target_.get(), timing_constraints["granularity"]); + qk_target_set_min_length(target_.get(), timing_constraints["min_length"]); + qk_target_set_pulse_alignment(target_.get(), timing_constraints["pulse_alignment"]); + qk_target_set_acquire_alignment(target_.get(), timing_constraints["acquire_alignment"]); + } - // add gate properties - std::unordered_map property_map; - for (auto &prop : backend_properties["gates"]) { - std::string gate = prop["gate"]; - if (gate == "rzz") { - // TODO: Add RZZ support when we have angle wrapping in - // Qiskit's target and C transpiler. - continue; + // get basis gates and make property entries + auto name_map = Qiskit::circuit::get_standard_gate_name_mapping(); + for (auto &gate : backend_configuration["basis_gates"]) { + basis_gates_.push_back(gate); } - std::vector qubits = prop["qubits"]; - double duration = 0.0; - double error = 0.0; - for (auto ¶m : prop["parameters"]) { - if (param["name"] == "gate_error") { - error = param["value"]; - } else if (param["name"] == "gate_length") { - duration = 1e-9 * (double)param["value"]; + + // add gate properties + std::unordered_map property_map; + for (auto &prop : backend_properties["gates"]) { + std::string gate = prop["gate"]; + if (gate == "rzz") { + // TODO: Add RZZ support when we have angle wrapping in + // Qiskit's target and C transpiler. + continue; + } + std::vector qubits = prop["qubits"]; + double duration = 0.0; + double error = 0.0; + for (auto ¶m : prop["parameters"]) { + if (param["name"] == "gate_error") { + error = param["value"]; + } else if (param["name"] == "gate_length") { + duration = 1e-9 * (double)param["value"]; + } } - } - QkTargetEntry *target_entry = nullptr; - auto entry = property_map.find(gate); - if (entry == property_map.end()) { - auto inst = name_map.find(gate); - if (inst == name_map.end()) { - if (gate == "reset") { - target_entry = qk_target_entry_new_reset(); + QkTargetEntry *target_entry = nullptr; + auto entry = property_map.find(gate); + if (entry == property_map.end()) { + auto inst = name_map.find(gate); + if (inst == name_map.end()) { + if (gate == "reset") { + target_entry = qk_target_entry_new_reset(); + property_map[gate] = target_entry; + } + } else { + target_entry = qk_target_entry_new(inst->second.gate_map()); property_map[gate] = target_entry; } } else { - target_entry = qk_target_entry_new(inst->second.gate_map()); - property_map[gate] = target_entry; + target_entry = entry->second; } - } else { - target_entry = entry->second; - } - if (target_entry) { - QkExitCode ret = qk_target_entry_add_property(target_entry, qubits.data(), (uint32_t)qubits.size(), duration, error); - if (ret != QkExitCode_Success) { - std::cerr << " target qk_target_entry_add_property error (" << ret << ") : " << gate << " ["; - for (int i = 0; i < qubits.size(); i++) { - std::cerr << qubits[i] << ", "; + if (target_entry) { + QkExitCode ret = qk_target_entry_add_property(target_entry, qubits.data(), (uint32_t)qubits.size(), duration, error); + if (ret != QkExitCode_Success) { + std::cerr << " target qk_target_entry_add_property error (" << ret << ") : " << gate << " ["; + for (int i = 0; i < qubits.size(); i++) { + std::cerr << qubits[i] << ", "; + } + std::cerr << "]" << std::endl; } - std::cerr << "]" << std::endl; } } - } - for (auto &entry : property_map) { - QkExitCode ret = qk_target_add_instruction(target_.get(), entry.second); - if (ret != QkExitCode_Success) { - std::cerr << " target qk_target_add_instruction error (" << ret << ")" << std::endl; + for (auto &entry : property_map) { + QkExitCode ret = qk_target_add_instruction(target_.get(), entry.second); + if (ret != QkExitCode_Success) { + std::cerr << " target qk_target_add_instruction error (" << ret << ")" << std::endl; + } + // qk_target_entry_free(entry.second); } - // qk_target_entry_free(entry.second); - } - // add measure properties - QkTargetEntry *measure = qk_target_entry_new_measure(); - uint32_t qubit = 0; - for (uint32_t qubit = 0; qubit < backend_properties["qubits"].size(); qubit++) { - double duration = 0.0; - double error = 0.0; - for (auto ¶m : backend_properties["qubits"][qubit]) { - if (param["name"] == "readout_error") { - error = param["value"]; - } else if (param["name"] == "readout_length") { - duration = 1e-9 * (double)param["value"]; + // add measure properties + QkTargetEntry *measure = qk_target_entry_new_measure(); + uint32_t qubit = 0; + for (uint32_t qubit = 0; qubit < backend_properties["qubits"].size(); qubit++) { + double duration = 0.0; + double error = 0.0; + for (auto ¶m : backend_properties["qubits"][qubit]) { + if (param["name"] == "readout_error") { + error = param["value"]; + } else if (param["name"] == "readout_length") { + duration = 1e-9 * (double)param["value"]; + } } + qk_target_entry_add_property(measure, &qubit, 1, duration, error); } - qk_target_entry_add_property(measure, &qubit, 1, duration, error); - } - qk_target_add_instruction(target_.get(), measure); - - is_set_ = true; - return true; -} - + qk_target_add_instruction(target_.get(), measure); -void Target::add_instruction(const circuit::Instruction& instruction, const std::vector& properties) -{ - auto prop = properties_.find(instruction.name()); - if (prop == properties_.end()) { - properties_[instruction.name()] = properties; - } else { - prop->second.insert(prop->second.end(), properties.begin(), properties.end()); + is_set_ = true; + return true; } -} - -void Target::build_target(void) -{ - if (target_) { - target_.reset(); + /// @brief add instruction to the target + /// @param instruction reference to the instruction to be added + /// @param properties properties of the instruction + void add_instruction(const circuit::Instruction& instruction, const std::vector& properties) + { + auto prop = properties_.find(instruction.name()); + if (prop == properties_.end()) { + properties_[instruction.name()] = properties; + } else { + prop->second.insert(prop->second.end(), properties.begin(), properties.end()); + } } - // get num qubits - if (num_qubits_ == 0) { - for (auto &prop : properties_) { - for (auto &inst : prop.second) { - for (auto &qubit : inst.qargs) { - if (qubit > num_qubits_) { - num_qubits_ = qubit; +protected: + void build_target(void) + { + if (target_) { + target_.reset(); + } + + // get num qubits + if (num_qubits_ == 0) { + for (auto &prop : properties_) { + for (auto &inst : prop.second) { + for (auto &qubit : inst.qargs) { + if (qubit > num_qubits_) { + num_qubits_ = qubit; + } } } } } - } - num_qubits_ += 1; - - QkTarget* t = qk_target_new((uint32_t)num_qubits_); - if (t == nullptr) - return; - target_ = std::shared_ptr(t, qk_target_free); - - // add properties - auto name_map = Qiskit::circuit::get_standard_gate_name_mapping(); - for (auto &prop : properties_) { - QkTargetEntry *target_entry = nullptr; - if (prop.first == "reset") { - target_entry = qk_target_entry_new_reset(); - } else if (prop.first == "rzz") { - std::cerr << " Target: rzz gate is not supported until Qiskit C-API will support it." << std::endl; - } else { - auto gate = name_map.find(prop.first); - if (gate != name_map.end()) { - target_entry = qk_target_entry_new(gate->second.gate_map()); + num_qubits_ += 1; + + QkTarget* t = qk_target_new((uint32_t)num_qubits_); + if (t == nullptr) + return; + target_ = std::shared_ptr(t, qk_target_free); + + // add properties + auto name_map = Qiskit::circuit::get_standard_gate_name_mapping(); + for (auto &prop : properties_) { + QkTargetEntry *target_entry = nullptr; + if (prop.first == "reset") { + target_entry = qk_target_entry_new_reset(); + } else if (prop.first == "rzz") { + std::cerr << " Target: rzz gate is not supported until Qiskit C-API will support it." << std::endl; + } else { + auto gate = name_map.find(prop.first); + if (gate != name_map.end()) { + target_entry = qk_target_entry_new(gate->second.gate_map()); + } } - } - if (target_entry != nullptr) { - for (auto &inst : prop.second) { - QkExitCode ret = qk_target_entry_add_property(target_entry, inst.qargs.data(), (uint32_t)inst.qargs.size(), inst.duration, inst.error); - if (ret != QkExitCode_Success) { - std::cerr << " Target : qk_target_entry_add_property error (" << ret << ") : " << prop.first << " ["; - for (int i = 0; i < inst.qargs.size(); i++) { - std::cerr << inst.qargs[i] << ", "; + if (target_entry != nullptr) { + for (auto &inst : prop.second) { + QkExitCode ret = qk_target_entry_add_property(target_entry, inst.qargs.data(), (uint32_t)inst.qargs.size(), inst.duration, inst.error); + if (ret != QkExitCode_Success) { + std::cerr << " Target : qk_target_entry_add_property error (" << ret << ") : " << prop.first << " ["; + for (int i = 0; i < inst.qargs.size(); i++) { + std::cerr << inst.qargs[i] << ", "; + } + std::cerr << "]" << std::endl; } - std::cerr << "]" << std::endl; } - } - QkExitCode ret = qk_target_add_instruction(target_.get(), target_entry); - if (ret != QkExitCode_Success) { - std::cerr << " Target : qk_target_add_instruction error (" << ret << ")" << std::endl; + QkExitCode ret = qk_target_add_instruction(target_.get(), target_entry); + if (ret != QkExitCode_Success) { + std::cerr << " Target : qk_target_add_instruction error (" << ret << ")" << std::endl; + } } } - } - // add measure properties - QkTargetEntry *measure = qk_target_entry_new_measure(); - uint32_t qubit = 0; - for (uint32_t qubit = 0; qubit < num_qubits_; qubit++) { - double duration = 0.0; - double error = 0.0; - qk_target_entry_add_property(measure, &qubit, 1, duration, error); - } - qk_target_add_instruction(target_.get(), measure); - - is_set_ = true; -} + // add measure properties + QkTargetEntry *measure = qk_target_entry_new_measure(); + uint32_t qubit = 0; + for (uint32_t qubit = 0; qubit < num_qubits_; qubit++) { + double duration = 0.0; + double error = 0.0; + qk_target_entry_add_property(measure, &qubit, 1, duration, error); + } + qk_target_add_instruction(target_.get(), measure); + is_set_ = true; + } +}; } // namespace transpiler diff --git a/src/utils/bitvector.hpp b/src/utils/bitvector.hpp index 8c91bf0..9481e1f 100644 --- a/src/utils/bitvector.hpp +++ b/src/utils/bitvector.hpp @@ -56,7 +56,26 @@ class BitVector uint_t size() { return size_; } uint_t length() { return bits_.size(); } - void allocate(uint_t n, uint_t base = 2); + void allocate(uint_t n, uint_t base = 2) + { + vec_shift_bits_ = REG_BITS; + uint_t t = 1; + elem_shift_bits_ = 0; + for (uint_t i = 0; i < REG_BITS; i++) { + t <<= 1; + if (t >= base) { + break; + } + vec_shift_bits_--; + elem_shift_bits_++; + } + elem_mask_ = (1ull << (elem_shift_bits_ + 1)) - 1; + vec_mask_ = (1ull << vec_shift_bits_) - 1; + + uint_t size = (n + (REG_SIZE >> elem_shift_bits_) - 1) >> vec_shift_bits_; + bits_.resize(size, 0ull); + size_ = n; + } BitVector &operator=(const BitVector &src) { @@ -81,7 +100,14 @@ class BitVector } // copy with swap - void map(const BitVector &src, const reg_t map); + void map(const BitVector &src, const reg_t map) + { + allocate(map.size(), src.base_); + + for (uint_t i = 0; i < map.size(); i++) { + set(i, src[map[i]]); + } + } // bit access inline uint_t get(const uint_t idx) const @@ -108,226 +134,153 @@ class BitVector /// @param start_bit start bit index of subset /// @param num_bits number of bits in a subset /// @return A new BitVector - BitVector get_subset(const uint_t start_bit, const uint_t num_bits); - - // convert from other data - void from_uint(const uint_t src, const uint_t n, const uint_t base = 2); - void from_string(const std::string &src, const uint_t base = 2); - void from_hex_string(const std::string &src, const uint_t base = 2); - void from_vector(const reg_t &src, const uint_t base = 2); - void from_vector_with_map(const reg_t &src, const reg_t &map, - const uint_t base = 2); - - // convert to other data types - std::string to_string(); - std::string to_hex_string(); - reg_t to_vector(); - - /// @brief Return number of 1 bits - /// @return A number of 1 bits - uint_t popcount(void); -}; - -void BitVector::allocate(uint_t n, uint_t base) -{ - vec_shift_bits_ = REG_BITS; - uint_t t = 1; - elem_shift_bits_ = 0; - for (uint_t i = 0; i < REG_BITS; i++) + BitVector get_subset(const uint_t start_bit, const uint_t num_bits) { - t <<= 1; - if (t >= base) - { - break; + BitVector ret(num_bits); + + for (uint_t i = 0; i < num_bits; i++) { + ret.set(i, get(start_bit + i)); } - vec_shift_bits_--; - elem_shift_bits_++; + return ret; } - elem_mask_ = (1ull << (elem_shift_bits_ + 1)) - 1; - vec_mask_ = (1ull << vec_shift_bits_) - 1; - uint_t size = (n + (REG_SIZE >> elem_shift_bits_) - 1) >> vec_shift_bits_; - bits_.resize(size, 0ull); - size_ = n; -} - -void BitVector::map(const BitVector &src, const reg_t map) -{ - allocate(map.size(), src.base_); - - for (uint_t i = 0; i < map.size(); i++) + // convert from other data + void from_uint(const uint_t src, const uint_t n, const uint_t base = 2) { - set(i, src[map[i]]); + allocate(n, base); + bits_[0] = src; } -} -void BitVector::from_uint(const uint_t src, const uint_t n, - const uint_t base) -{ - allocate(n, base); - bits_[0] = src; -} - -void BitVector::from_string(const std::string &src, const uint_t base) -{ - allocate(src.size(), base); - - uint_t pos = 0; - uint_t n = REG_SIZE >> elem_shift_bits_; - for (uint_t i = 0; i < bits_.size(); i++) + void from_string(const std::string &src, const uint_t base = 2) { - uint_t val = 0; - if (n > size_ - pos) - n = size_ - pos; - for (uint_t j = 0; j < n; j++) - { - val |= (((uint_t)(src[size_ - 1 - pos] - '0') & elem_mask_) - << (j << elem_shift_bits_)); - pos++; + allocate(src.size(), base); + + uint_t pos = 0; + uint_t n = REG_SIZE >> elem_shift_bits_; + for (uint_t i = 0; i < bits_.size(); i++) { + uint_t val = 0; + if (n > size_ - pos) + n = size_ - pos; + for (uint_t j = 0; j < n; j++) { + val |= (((uint_t)(src[size_ - 1 - pos] - '0') & elem_mask_) + << (j << elem_shift_bits_)); + pos++; + } + bits_[i] = val; } - bits_[i] = val; } -} -void BitVector::from_hex_string(const std::string &src, const uint_t base) -{ - uint_t size; - if (src.size() > 2 && src[0] == '0' && src[1] == 'x') - { - size = src.size() - 2; - } - else + void from_hex_string(const std::string &src, const uint_t base = 2) { - size = src.size(); - } - if (size * 4 > ((size_ + 3) / 4) * 4) - allocate(size * 4, base); - - for (uint_t i = 0; i < size; i++) - { - char c = src[src.size() - 1 - i]; - uint_t h = 0; - if (c >= '0' && c <= '9') - { - h = (uint_t)(c - '0'); - } - else if (c >= 'a' && c <= 'f') - { - h = (uint_t)(c - 'a') + 10; + uint_t size; + if (src.size() > 2 && src[0] == '0' && src[1] == 'x') { + size = src.size() - 2; + } else { + size = src.size(); } - else if (c >= 'A' && c <= 'F') - { - h = (uint_t)(c - 'A') + 10; + if (size * 4 > ((size_ + 3) / 4) * 4) + allocate(size * 4, base); + + for (uint_t i = 0; i < size; i++) { + char c = src[src.size() - 1 - i]; + uint_t h = 0; + if (c >= '0' && c <= '9') { + h = (uint_t)(c - '0'); + } else if (c >= 'a' && c <= 'f') { + h = (uint_t)(c - 'a') + 10; + } else if (c >= 'A' && c <= 'F') { + h = (uint_t)(c - 'A') + 10; + } + uint_t pos = i % (REG_SIZE >> 2); + bits_[i / (REG_SIZE >> 2)] |= (h << (pos << 2)); } - uint_t pos = i % (REG_SIZE >> 2); - bits_[i / (REG_SIZE >> 2)] |= (h << (pos << 2)); } -} - -void BitVector::from_vector(const reg_t &src, const uint_t base) -{ - allocate(src.size(), base); - - uint_t pos = 0; - uint_t n = REG_SIZE >> elem_shift_bits_; - for (uint_t i = 0; i < bits_.size(); i++) + void from_vector(const reg_t &src, const uint_t base = 2) { - uint_t val = 0; - if (n > size_ - pos) - n = size_ - pos; - for (uint_t j = 0; j < n; j++) - { - val |= ((src[pos++] & elem_mask_) << (j << elem_shift_bits_)); + allocate(src.size(), base); + + uint_t pos = 0; + uint_t n = REG_SIZE >> elem_shift_bits_; + for (uint_t i = 0; i < bits_.size(); i++) { + uint_t val = 0; + if (n > size_ - pos) + n = size_ - pos; + for (uint_t j = 0; j < n; j++) { + val |= ((src[pos++] & elem_mask_) << (j << elem_shift_bits_)); + } + bits_[i] = val; } - bits_[i] = val; } -} -void BitVector::from_vector_with_map(const reg_t &src, const reg_t &map, - const uint_t base) -{ - allocate(src.size(), base); - - uint_t pos = 0; - uint_t n = REG_SIZE >> elem_shift_bits_; - for (uint_t i = 0; i < bits_.size(); i++) + void from_vector_with_map(const reg_t &src, const reg_t &map, + const uint_t base = 2) { - uint_t val = 0; - if (n > size_ - pos) - n = size_ - pos; - for (uint_t j = 0; j < n; j++) - { - val |= ((src[map[pos++]] & elem_mask_) << (j << elem_shift_bits_)); + allocate(src.size(), base); + + uint_t pos = 0; + uint_t n = REG_SIZE >> elem_shift_bits_; + for (uint_t i = 0; i < bits_.size(); i++) { + uint_t val = 0; + if (n > size_ - pos) + n = size_ - pos; + for (uint_t j = 0; j < n; j++) { + val |= ((src[map[pos++]] & elem_mask_) << (j << elem_shift_bits_)); + } + bits_[i] = val; } - bits_[i] = val; } -} -std::string BitVector::to_string(void) -{ - std::string str; - for (uint_t i = 0; i < size_; i++) + // convert to other data types + std::string to_string() { - uint_t val = get(size_ - 1 - i); - str += std::to_string(val); + std::string str; + for (uint_t i = 0; i < size_; i++) { + uint_t val = get(size_ - 1 - i); + str += std::to_string(val); + } + return str; } - return str; -} -std::string BitVector::to_hex_string(void) -{ - uint_t size = size_ / 4; - std::string str = "0x"; - for (uint_t i = 0; i < size; i++) - { - str += '0'; - } - for (uint_t i = 0; i < size; i++) + std::string to_hex_string() { - uint_t pos = i % (REG_SIZE >> 2); - uint_t val = (bits_[i / (REG_SIZE >> 2)] >> (pos << 2)) & 15; - - if (val < 10) - { - str[str.size() - 1 - i] = ('0' + (char)val); + uint_t size = size_ / 4; + std::string str = "0x"; + for (uint_t i = 0; i < size; i++) { + str += '0'; } - else - { - str[str.size() - 1 - i] = ('a' + (char)(val - 10)); + for (uint_t i = 0; i < size; i++) { + uint_t pos = i % (REG_SIZE >> 2); + uint_t val = (bits_[i / (REG_SIZE >> 2)] >> (pos << 2)) & 15; + + if (val < 10) { + str[str.size() - 1 - i] = ('0' + (char)val); + } else { + str[str.size() - 1 - i] = ('a' + (char)(val - 10)); + } } + return str; } - return str; -} -reg_t BitVector::to_vector(void) -{ - reg_t ret(size_); - for (uint_t i = 0; i < size_; i++) + reg_t to_vector() { - ret[i] = get(i); - } - return ret; -} - -BitVector BitVector::get_subset(const uint_t start_bit, const uint_t num_bits) -{ - BitVector ret(num_bits); - - for (uint_t i = 0; i < num_bits; i++) { - ret.set(i, get(start_bit + i)); + reg_t ret(size_); + for (uint_t i = 0; i < size_; i++) { + ret[i] = get(i); + } + return ret; } - return ret; -} -uint_t BitVector::popcount(void) -{ - uint_t count = 0; - for (uint_t i = 0; i < bits_.size(); i++) { - count += Qiskit::popcount(bits_[i]); + /// @brief Return number of 1 bits + /// @return A number of 1 bits + uint_t popcount(void) + { + uint_t count = 0; + for (uint_t i = 0; i < bits_.size(); i++) { + count += Qiskit::popcount(bits_[i]); + } + return count; } - return count; -} - +}; //------------------------------------------------------------------------------ } // namespace Qiskit diff --git a/src/utils/utils.hpp b/src/utils/utils.hpp index 25b5667..6778377 100644 --- a/src/utils/utils.hpp +++ b/src/utils/utils.hpp @@ -53,7 +53,7 @@ inline uint_t _instrinsic_weight(uint_t x) { return (__builtin_popcountll(x)); } #endif #endif -uint_t _naive_weight(uint_t x) { +inline uint_t _naive_weight(uint_t x) { auto count = x; count = (count & 0x5555555555555555) + ((count >> 1) & 0x5555555555555555); count = (count & 0x3333333333333333) + ((count >> 2) & 0x3333333333333333); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index f424d66..7183953 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -28,9 +28,9 @@ FetchContent_MakeAvailable(json) # files into a single executable. This has the benefit that a single test # executable is built and run rather than invididual ones for every individual # test file. -create_test_sourcelist (source_files test_driver.c ${discovered_tests}) +create_test_sourcelist (source_files test_driver.cpp ${discovered_tests}) -add_library(common STATIC common.c) +add_library(common STATIC common.cpp) # Actually define the test driver program executable to be built... add_executable (test_driver ${source_files}) # ...include the location of the header file... @@ -38,7 +38,6 @@ target_include_directories (test_driver PRIVATE ${CMAKE_SOURCE_DIR} nlohmann_jso # ...and linked with the qiskit library. target_link_libraries (test_driver ${qiskit} common nlohmann_json::nlohmann_json) -target_link_options(test_driver PRIVATE "-Wl,-z,muldefs") # On MSVC we need to link the Python dll, we search it here and adjust the PATH in the tests below if (MSVC) diff --git a/test/common.c b/test/common.cpp similarity index 79% rename from test/common.c rename to test/common.cpp index e5f1bc7..047fccb 100644 --- a/test/common.c +++ b/test/common.cpp @@ -10,9 +10,9 @@ // copyright notice, and modified files need to carry a notice indicating // that they have been altered from the originals. -#include "common.h" -#include -#include +#include "common.hpp" +#include +#include // A function to run a test function of a given name. This function will also // post-process the returned `TestResult` to product a minimal info message for @@ -26,14 +26,11 @@ int run(const char *name, int (*test_function)(void)) { char *msg; if (result == Ok) { did_fail = 0; - msg = "Ok"; + std::cerr << "--- " << name << ": OK" << std::endl; } else if (result == EqualityError) { - msg = "FAILED with an EqualityError"; + std::cerr << "--- " << name << ": FAILED with an EqualityError" << std::endl; } else { - msg = "FAILED with unknown error"; + std::cerr << "--- " << name << ": FAILED with unknown error" << std::endl; } - fprintf(stderr, "--- %-30s: %s\n", name, msg); - fflush(stderr); - return did_fail; } diff --git a/test/common.h b/test/common.hpp similarity index 98% rename from test/common.h rename to test/common.hpp index 238ef78..2d3ee0c 100644 --- a/test/common.h +++ b/test/common.hpp @@ -13,8 +13,6 @@ #ifndef _TEST_COMMON_H_ #define _TEST_COMMON_H_ -#include - // An enumeration of test results. These should be returned by test functions to // indicate what kind of error occurred. This will be used to produce more // helpful messages for the developer running the test suite. diff --git a/test/test_circuit.cpp b/test/test_circuit.cpp index 19722a6..2722274 100644 --- a/test/test_circuit.cpp +++ b/test/test_circuit.cpp @@ -13,14 +13,12 @@ #include #include +#include "common.hpp" + #include "circuit/quantumcircuit.hpp" using namespace Qiskit; using namespace Qiskit::circuit; -extern "C" { - #include "common.h" -} - static int test_standard_gates(void) { auto circ = QuantumCircuit(4, 4); uint_t count = 0; @@ -644,7 +642,7 @@ static int test_to_qasm3_multi_regs(void) { } -extern "C" int test_circuit(void) { +int test_circuit(int argc, char** argv) { int num_failed = 0; num_failed += RUN_TEST(test_standard_gates); num_failed += RUN_TEST(test_measure); diff --git a/test/test_parameter.cpp b/test/test_parameter.cpp index d680c2c..9adbccc 100644 --- a/test/test_parameter.cpp +++ b/test/test_parameter.cpp @@ -14,14 +14,12 @@ #include #include +#include "common.hpp" + #include "circuit/parameter.hpp" using namespace Qiskit; using namespace Qiskit::circuit; -extern "C" { - #include "common.h" -} - /** * Test creating a new free symbol and check the name. */ @@ -332,7 +330,7 @@ int test_parameter_copy(void) { return result; } -extern "C" int test_parameter(void) { +int test_parameter(int argc, char** argv) { int num_failed = 0; num_failed += RUN_TEST(test_parameter_new); num_failed += RUN_TEST(test_parameter_new_values); diff --git a/test/test_transpiler.cpp b/test/test_transpiler.cpp index 012ebf9..95f8782 100644 --- a/test/test_transpiler.cpp +++ b/test/test_transpiler.cpp @@ -17,14 +17,12 @@ #include "circuit/quantumcircuit.hpp" #include "transpiler/passmanager.hpp" +#include "common.hpp" using namespace Qiskit; using namespace Qiskit::circuit; using namespace Qiskit::transpiler; -extern "C" { - #include "common.h" -} static int test_translate_h(void) { @@ -122,7 +120,7 @@ static int test_ghz_routing(void) } -extern "C" int test_transpiler(void) { +int test_transpiler(int argc, char** argv) { int num_failed = 0; num_failed += RUN_TEST(test_translate_h); num_failed += RUN_TEST(test_translate_cx); From 457cc3eeb9a17851474e315b8dab64ea02d79188 Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Tue, 21 Apr 2026 17:02:41 +0900 Subject: [PATCH 3/5] fix for Windows test --- test/test_circuit.cpp | 5 ++++- test/test_parameter.cpp | 4 ++++ test/test_transpiler.cpp | 4 ++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/test/test_circuit.cpp b/test/test_circuit.cpp index 2722274..663f161 100644 --- a/test/test_circuit.cpp +++ b/test/test_circuit.cpp @@ -641,8 +641,11 @@ static int test_to_qasm3_multi_regs(void) { return Ok; } - +#if defined(_WIN32) +int test_circuit(int argc, const char** argv) { +#else int test_circuit(int argc, char** argv) { +#endif int num_failed = 0; num_failed += RUN_TEST(test_standard_gates); num_failed += RUN_TEST(test_measure); diff --git a/test/test_parameter.cpp b/test/test_parameter.cpp index 9adbccc..c4a4eb9 100644 --- a/test/test_parameter.cpp +++ b/test/test_parameter.cpp @@ -330,7 +330,11 @@ int test_parameter_copy(void) { return result; } +#if defined(_WIN32) +int test_parameter(int argc, const char** argv) { +#else int test_parameter(int argc, char** argv) { +#endif int num_failed = 0; num_failed += RUN_TEST(test_parameter_new); num_failed += RUN_TEST(test_parameter_new_values); diff --git a/test/test_transpiler.cpp b/test/test_transpiler.cpp index 95f8782..877abc0 100644 --- a/test/test_transpiler.cpp +++ b/test/test_transpiler.cpp @@ -120,7 +120,11 @@ static int test_ghz_routing(void) } +#if defined(_WIN32) +int test_transpiler(int argc, const char** argv) { +#else int test_transpiler(int argc, char** argv) { +#endif int num_failed = 0; num_failed += RUN_TEST(test_translate_h); num_failed += RUN_TEST(test_translate_cx); From 6639f4ad3a271c2861d45c3dde3f9dccae050c78 Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Tue, 21 Apr 2026 17:18:09 +0900 Subject: [PATCH 4/5] fix for Windows test --- test/test_circuit.cpp | 2 +- test/test_parameter.cpp | 2 +- test/test_transpiler.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/test_circuit.cpp b/test/test_circuit.cpp index 663f161..bbd41e2 100644 --- a/test/test_circuit.cpp +++ b/test/test_circuit.cpp @@ -642,7 +642,7 @@ static int test_to_qasm3_multi_regs(void) { } #if defined(_WIN32) -int test_circuit(int argc, const char** argv) { +int test_circuit(int argc, char** argv const) { #else int test_circuit(int argc, char** argv) { #endif diff --git a/test/test_parameter.cpp b/test/test_parameter.cpp index c4a4eb9..1c1de92 100644 --- a/test/test_parameter.cpp +++ b/test/test_parameter.cpp @@ -331,7 +331,7 @@ int test_parameter_copy(void) { } #if defined(_WIN32) -int test_parameter(int argc, const char** argv) { +int test_parameter(int argc, char** argv const) { #else int test_parameter(int argc, char** argv) { #endif diff --git a/test/test_transpiler.cpp b/test/test_transpiler.cpp index 877abc0..64eb9fd 100644 --- a/test/test_transpiler.cpp +++ b/test/test_transpiler.cpp @@ -121,7 +121,7 @@ static int test_ghz_routing(void) #if defined(_WIN32) -int test_transpiler(int argc, const char** argv) { +int test_transpiler(int argc, char** argv const) { #else int test_transpiler(int argc, char** argv) { #endif From 011f054ad9d6a2a881213ea1f830af9e4dc6ddb8 Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Tue, 21 Apr 2026 17:36:25 +0900 Subject: [PATCH 5/5] fix for Windows test --- test/test_circuit.cpp | 2 +- test/test_parameter.cpp | 2 +- test/test_transpiler.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/test_circuit.cpp b/test/test_circuit.cpp index bbd41e2..eae4cd8 100644 --- a/test/test_circuit.cpp +++ b/test/test_circuit.cpp @@ -642,7 +642,7 @@ static int test_to_qasm3_multi_regs(void) { } #if defined(_WIN32) -int test_circuit(int argc, char** argv const) { +int test_circuit(int argc, char** const argv) { #else int test_circuit(int argc, char** argv) { #endif diff --git a/test/test_parameter.cpp b/test/test_parameter.cpp index 1c1de92..bfe24bf 100644 --- a/test/test_parameter.cpp +++ b/test/test_parameter.cpp @@ -331,7 +331,7 @@ int test_parameter_copy(void) { } #if defined(_WIN32) -int test_parameter(int argc, char** argv const) { +int test_parameter(int argc, char** const argv) { #else int test_parameter(int argc, char** argv) { #endif diff --git a/test/test_transpiler.cpp b/test/test_transpiler.cpp index 64eb9fd..e14a9d2 100644 --- a/test/test_transpiler.cpp +++ b/test/test_transpiler.cpp @@ -121,7 +121,7 @@ static int test_ghz_routing(void) #if defined(_WIN32) -int test_transpiler(int argc, char** argv const) { +int test_transpiler(int argc, char** const argv) { #else int test_transpiler(int argc, char** argv) { #endif