From 6bac22326a167f7d728ca12109ed171dcb489380 Mon Sep 17 00:00:00 2001 From: Ryo Wakizaka Date: Tue, 25 Nov 2025 11:34:23 +0900 Subject: [PATCH 01/26] Added skelton for SQC backend --- samples/CMakeLists.txt | 15 +++++ samples/sqc_test.cpp | 111 ++++++++++++++++++++++++++++++++++ src/providers/sqc_backend.hpp | 77 +++++++++++++++++++++++ 3 files changed, 203 insertions(+) create mode 100644 samples/sqc_test.cpp create mode 100644 src/providers/sqc_backend.hpp diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index 01dcbe4..1a404be 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -36,6 +36,7 @@ function(add_application APP_NAME CPP_FILE) PUBLIC ${QISKIT_ROOT}/target/release ${QRMI_ROOT}/target/release + #${SQC_ROOT}/ ${QISKIT_IBM_RUNTIME_C_ROOT}/build/cargo/debug ) if(QRMI_ROOT) @@ -44,6 +45,9 @@ function(add_application APP_NAME CPP_FILE) elseif(QISKIT_IBM_RUNTIME_C_ROOT) target_link_libraries(${APP_NAME} qiskit_cext.dll.lib qiskit_ibm_runtime.dll.lib nlohmann_json::nlohmann_json) set(CMAKE_CXX_FLAGS "-DQISKIT_IBM_RUNTIME_C_ROOT=${QISKIT_IBM_RUNTIME_C_ROOT}") + #elseif(SQC_ROOT) + #target_link_libraries(${APP_NAME} qiskit_cext.dll.lib nlohmann_json::nlohmann_json) + #set(CMAKE_CXX_FLAGS "-DSQC_ROOT=${SQC_ROOT}") else() target_link_libraries(${APP_NAME} qiskit_cext.dll.lib nlohmann_json::nlohmann_json) target_compile_options(${APP_NAME} PRIVATE "-DQISKIT_IBM_RUNTIME_C_ROOT=${QISKIT_IBM_RUNTIME_C_ROOT}") @@ -61,6 +65,12 @@ function(add_application APP_NAME CPP_FILE) "-L${QISKIT_ROOT}/dist/c/lib -L${QISKIT_IBM_RUNTIME_C_ROOT}/build/cargo/debug -Wl,-rpath ${QISKIT_ROOT}/dist/c/lib -Wl,-rpath ${QISKIT_IBM_RUNTIME_C_ROOT}/build/cargo/debug" qiskit qiskit_ibm_runtime nlohmann_json::nlohmann_json ) target_compile_options(${APP_NAME} PRIVATE "-DQISKIT_IBM_RUNTIME_C_ROOT=${QISKIT_IBM_RUNTIME_C_ROOT}") + #elseif(SQC_ROOT) + # target_link_libraries(${APP_NAME} + # PRIVATE + # "-L${QISKIT_ROOT}/dist/c/lib -L${SQC_ROOT}/ -Wl,-rpath ${QISKIT_ROOT}/dist/c/lib -Wl,-rpath ${QISKIT_IBM_RUNTIME_C_ROOT}/build/cargo/debug" qiskit qiskit_ibm_runtime nlohmann_json::nlohmann_json + # ) + # target_compile_options(${APP_NAME} PRIVATE "-DSQC_ROOT=${SQC_ROOT}") else() target_link_libraries(${APP_NAME} PRIVATE @@ -75,6 +85,7 @@ function(add_application APP_NAME CPP_FILE) ${QISKIT_ROOT}/dist/c/include ${QRMI_ROOT} ${QISKIT_IBM_RUNTIME_C_ROOT}/include + ${SQC_ROOT}/capi/include ${SAMPLES_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/../src nlohmann_json::nlohmann_json @@ -95,3 +106,7 @@ if(QRMI_ROOT OR QISKIT_IBM_RUNTIME_C_ROOT) add_application(sampler_test sampler_test.cpp) add_application(transpile_test transpile_test.cpp) endif() + +if(SQC_ROOT) + add_application(sqc_test sqc_test.cpp) +endif() diff --git a/samples/sqc_test.cpp b/samples/sqc_test.cpp new file mode 100644 index 0000000..ca34c6c --- /dev/null +++ b/samples/sqc_test.cpp @@ -0,0 +1,111 @@ +/* +# 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. +*/ + +// Test program for SQC + +#define _USE_MATH_DEFINES +#include +#include +#include +#include + +#include "circuit/quantumcircuit.hpp" +#include "primitives/backend_sampler_v2.hpp" +//#include "service/qiskit_runtime_service.hpp" +#include "compiler/transpiler.hpp" + +using namespace Qiskit; +using namespace Qiskit::circuit; +using namespace Qiskit::providers; +using namespace Qiskit::primitives; +//using namespace Qiskit::service; +using namespace Qiskit::compiler; + +using Sampler = BackendSamplerV2; + +int main() +{ + int num_qubits = 10; + auto qreg = QuantumRegister(num_qubits); + auto creg = ClassicalRegister(num_qubits, std::string("meas")); + auto ctest = ClassicalRegister(num_qubits, std::string("test")); + QuantumCircuit circ(std::vector({qreg,}), std::vector({creg, ctest})); + + // test measure all + circ.measure(qreg, ctest); + + // GHZ circuit + circ.h(0); + for (int i = 0; i < num_qubits - 1; i++) + { + circ.cx(i, i + 1); + } + circ.measure(qreg, creg); + + //auto service = QiskitRuntimeService(); + //auto backend = service.backend("ibm_torino"); + //auto sampler = Sampler(backend, 100); + + //auto transpiled_circ = transpile(circ, backend); + + //auto job = sampler.run({SamplerPub(transpiled_circ)}); + //if (job == nullptr) + // return -1; + //auto result = job->result(); + + //auto pub_result = result[0]; + //auto meas_bits = pub_result.data("meas"); + //auto bits = meas_bits.get_bitstrings(); + //std::cout << " ===== samples for pub[0] =====" << std::endl; + //for (auto b : bits) + //{ + // std::cout << b << ", "; + //} + //std::cout << std::endl; + + //std::cout << " --- test bits ---" << std::endl; + //auto test_bits = pub_result.data("test"); + //bits = test_bits.get_bitstrings(); + //for (auto b : bits) + //{ + // std::cout << b << ", "; + //} + //std::cout << std::endl; + + //std::cout << " ===== counts for pub[0] =====" << std::endl; + //auto count = meas_bits.get_counts(); + //for (auto c : count) + //{ + // std::cout << c.first << " : " << c.second << std::endl; + //} + + + //auto bitcounts = test_bits.bitcount(); + //reg_t zero_index; + //zero_index.reserve(bitcounts.size()); + //for (uint_t i = 0; i < bitcounts.size(); i++) { + // if (bitcounts[i] == 0) { + // zero_index.push_back(i); + // } + //} + + //std::cout << " ===== counts for pub[0] whose test bit are 0 =====" << std::endl; + //count = meas_bits.get_counts(zero_index); + //for (auto c : count) + //{ + // std::cout << c.first << " : " << c.second << std::endl; + //} + + return 0; +} diff --git a/src/providers/sqc_backend.hpp b/src/providers/sqc_backend.hpp new file mode 100644 index 0000000..066d951 --- /dev/null +++ b/src/providers/sqc_backend.hpp @@ -0,0 +1,77 @@ +/* +# 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. +*/ + +// SQC Backend + +#ifndef __qiskitcpp_providers_SQC_backend_def_hpp__ +#define __qiskitcpp_providers_SQC_backend_def_hpp__ + +#include "utils/types.hpp" +#include "transpiler/target.hpp" +#include "primitives/containers/sampler_pub.hpp" +#include "providers/job.hpp" + +#include "sqc_api.h" + +namespace Qiskit { +namespace providers { + +/// @class SQCBackend +/// @brief Backend class using SQC. +class SQCBackend : public BackendV2 { +public: + /// @brief Create a new QRMIBackend + SQCBackend() {} + + /// @brief Create a new QRMIBackend object + /// @param backend_name a resource name for backend. + SQCBackend(const std::string name) + { + this->name_ = name; + } + + /// @brief Create a new SQCBackend from other + SQCBackend(const SQCBackend& other) + { + this->name_ = other.name_; + } + + ~SQCBackend() {} + + /// @brief Return a target properties for this backend + /// @return a target class + std::shared_ptr target(void) override + { + std::cout << "called SQCBackend::target()" << std::endl; + return nullptr; + } + + /// @brief Run and collect samples from each pub. + /// @return PrimitiveJob + std::shared_ptr run(std::vector& input_pubs, uint_t shots) override + { + std::string qasm3 = input_pubs[0].circuit().to_qasm3(); + std::cout << "run qasm3: \n" << qasm3 << std::endl; + return nullptr; + } + +}; + +} // namespace providers +} // namespace Qiskit + + +#endif //__qiskitcpp_providers_SQC_backend_def_hpp__ + + From 02352ec63f0251536d83d132888c0ae9828d0eb9 Mon Sep 17 00:00:00 2001 From: Ryo Wakizaka Date: Tue, 25 Nov 2025 16:56:34 +0900 Subject: [PATCH 02/26] Uncomment sample code for SQC --- samples/sqc_test.cpp | 110 +++++++++---------- src/providers/sqc_backend.hpp | 7 +- src/providers/sqc_job.hpp | 116 +++++++++++++++++++++ src/service/qiskit_runtime_service_sqc.hpp | 48 +++++++++ 4 files changed, 224 insertions(+), 57 deletions(-) create mode 100644 src/providers/sqc_job.hpp create mode 100644 src/service/qiskit_runtime_service_sqc.hpp diff --git a/samples/sqc_test.cpp b/samples/sqc_test.cpp index ca34c6c..67377bf 100644 --- a/samples/sqc_test.cpp +++ b/samples/sqc_test.cpp @@ -22,14 +22,14 @@ #include "circuit/quantumcircuit.hpp" #include "primitives/backend_sampler_v2.hpp" -//#include "service/qiskit_runtime_service.hpp" +#include "service/qiskit_runtime_service_sqc.hpp" #include "compiler/transpiler.hpp" using namespace Qiskit; using namespace Qiskit::circuit; using namespace Qiskit::providers; using namespace Qiskit::primitives; -//using namespace Qiskit::service; +using namespace Qiskit::service; using namespace Qiskit::compiler; using Sampler = BackendSamplerV2; @@ -53,59 +53,59 @@ int main() } circ.measure(qreg, creg); - //auto service = QiskitRuntimeService(); - //auto backend = service.backend("ibm_torino"); - //auto sampler = Sampler(backend, 100); - - //auto transpiled_circ = transpile(circ, backend); - - //auto job = sampler.run({SamplerPub(transpiled_circ)}); - //if (job == nullptr) - // return -1; - //auto result = job->result(); - - //auto pub_result = result[0]; - //auto meas_bits = pub_result.data("meas"); - //auto bits = meas_bits.get_bitstrings(); - //std::cout << " ===== samples for pub[0] =====" << std::endl; - //for (auto b : bits) - //{ - // std::cout << b << ", "; - //} - //std::cout << std::endl; - - //std::cout << " --- test bits ---" << std::endl; - //auto test_bits = pub_result.data("test"); - //bits = test_bits.get_bitstrings(); - //for (auto b : bits) - //{ - // std::cout << b << ", "; - //} - //std::cout << std::endl; - - //std::cout << " ===== counts for pub[0] =====" << std::endl; - //auto count = meas_bits.get_counts(); - //for (auto c : count) - //{ - // std::cout << c.first << " : " << c.second << std::endl; - //} - - - //auto bitcounts = test_bits.bitcount(); - //reg_t zero_index; - //zero_index.reserve(bitcounts.size()); - //for (uint_t i = 0; i < bitcounts.size(); i++) { - // if (bitcounts[i] == 0) { - // zero_index.push_back(i); - // } - //} - - //std::cout << " ===== counts for pub[0] whose test bit are 0 =====" << std::endl; - //count = meas_bits.get_counts(zero_index); - //for (auto c : count) - //{ - // std::cout << c.first << " : " << c.second << std::endl; - //} + auto service = QiskitRuntimeService(); + auto backend = service.backend(); + auto sampler = Sampler(backend, 100); + + auto transpiled_circ = transpile(circ, backend); + + auto job = sampler.run({SamplerPub(transpiled_circ)}); + if (job == nullptr) + return -1; + auto result = job->result(); + + auto pub_result = result[0]; + auto meas_bits = pub_result.data("meas"); + auto bits = meas_bits.get_bitstrings(); + std::cout << " ===== samples for pub[0] =====" << std::endl; + for (auto b : bits) + { + std::cout << b << ", "; + } + std::cout << std::endl; + + std::cout << " --- test bits ---" << std::endl; + auto test_bits = pub_result.data("test"); + bits = test_bits.get_bitstrings(); + for (auto b : bits) + { + std::cout << b << ", "; + } + std::cout << std::endl; + + std::cout << " ===== counts for pub[0] =====" << std::endl; + auto count = meas_bits.get_counts(); + for (auto c : count) + { + std::cout << c.first << " : " << c.second << std::endl; + } + + + auto bitcounts = test_bits.bitcount(); + reg_t zero_index; + zero_index.reserve(bitcounts.size()); + for (uint_t i = 0; i < bitcounts.size(); i++) { + if (bitcounts[i] == 0) { + zero_index.push_back(i); + } + } + + std::cout << " ===== counts for pub[0] whose test bit are 0 =====" << std::endl; + count = meas_bits.get_counts(zero_index); + for (auto c : count) + { + std::cout << c.first << " : " << c.second << std::endl; + } return 0; } diff --git a/src/providers/sqc_backend.hpp b/src/providers/sqc_backend.hpp index 066d951..c1fe450 100644 --- a/src/providers/sqc_backend.hpp +++ b/src/providers/sqc_backend.hpp @@ -22,7 +22,7 @@ #include "primitives/containers/sampler_pub.hpp" #include "providers/job.hpp" -#include "sqc_api.h" +//#include "sqc_api.h" namespace Qiskit { namespace providers { @@ -61,7 +61,10 @@ class SQCBackend : public BackendV2 { /// @return PrimitiveJob std::shared_ptr run(std::vector& input_pubs, uint_t shots) override { - std::string qasm3 = input_pubs[0].circuit().to_qasm3(); + std::string qasm3 = [&]() { + auto circuit = input_pubs[0].circuit(); + return circuit.to_qasm3(); + }(); std::cout << "run qasm3: \n" << qasm3 << std::endl; return nullptr; } diff --git a/src/providers/sqc_job.hpp b/src/providers/sqc_job.hpp new file mode 100644 index 0000000..5674636 --- /dev/null +++ b/src/providers/sqc_job.hpp @@ -0,0 +1,116 @@ +/* +# 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. +*/ + +// Job class for SQC + +#ifndef __qiskitcpp_providers_SQC_job_def_hpp__ +#define __qiskitcpp_providers_SQC_job_def_hpp__ + +#include + +#include "utils/types.hpp" + +#include "primitives/containers/sampler_pub_result.hpp" +#include "providers/job.hpp" + +namespace Qiskit { +namespace providers { + +/// @class SQCJob +/// @brief Job class for SQC +class SQCJob : public Job { +private: + std::string job_id_; + nlohmann::ordered_json results_; // json formatted results (converted output from SQC) + uint_t num_results_ = 0; +public: + /// @brief Create a new QkrtBackend + SQCJob() + { + num_results_ = 0; + } + + /// @brief Create a new QkrtBackend object + /// @param qrmi a pointer to QRMI handle + /// @param job an id of the job + SQCJob(const std::string& job) + { + job_id_ = job; + num_results_ = 0; + } + + /// @brief Create a new QkrtJob from other + SQCJob(const SQCJob& other) + { + job_id_ = other.job_id_; + num_results_ = 0; + } + + ~SQCJob() {} + + /// @brief Return the status of the job. + /// @return JobStatus enum. + providers::JobStatus status(void) override + { + return providers::JobStatus::FAILED; + } + + + /// @brief Return the number of results in this job + /// @return number of results + uint_t num_results(void) override + { + if (num_results_ == 0) + read_results(); + return num_results_; + } + + /// @brief get sampler pub result + /// @param index an index of the reuslt + /// @param result an output sampler pub result + /// @return true if result is successfully set + bool result(uint_t index, primitives::SamplerPubResult& result) override + { + //if (num_results_ == 0) + // read_results(); + + //if (index >= num_results_) + // return false; + + //result.from_json(results_["results"][index]); + return false; + } + +protected: + void read_results(void) + { + //char *result = nullptr; + //int rc = qrmi_resource_task_result(qrmi_.get(), job_id_.c_str(), &result); + //if (rc == QRMI_RETURN_CODE_SUCCESS) { + // results_ = nlohmann::ordered_json::parse(result); + + // num_results_ = results_["results"].size(); + // qrmi_string_free((char *)result); + //} + //qrmi_resource_task_stop(qrmi_.get(), job_id_.c_str()); + } +}; + +} // namespace providers +} // namespace Qiskit + + +#endif //__qiskitcpp_providers_QRMI_job_def_hpp__ + + diff --git a/src/service/qiskit_runtime_service_sqc.hpp b/src/service/qiskit_runtime_service_sqc.hpp new file mode 100644 index 0000000..f7e9c37 --- /dev/null +++ b/src/service/qiskit_runtime_service_sqc.hpp @@ -0,0 +1,48 @@ +/* +# 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. +*/ + +// Qiskit Runtime Service for SQC + +#ifndef __qiskitcpp_providers_qiskit_runtime_service_SQC_def_hpp__ +#define __qiskitcpp_providers_qiskit_runtime_service_SQC_def_hpp__ + +#include "providers/sqc_backend.hpp" + +namespace Qiskit { +namespace service { + +class QiskitRuntimeService { +private: +public: + /// @brief Create a new runtime service class + QiskitRuntimeService() + { + } + + ~QiskitRuntimeService() + { + } + + /// @brief create a new backend object + /// @return a new QkrtBackend class + Qiskit::providers::SQCBackend backend() + { + return Qiskit::providers::SQCBackend(); + } +}; + +} // namespace service +} // namespace Qiskit + +#endif From baa3bdf6d767af4fe36cbf2021cca5aa0ca150fb Mon Sep 17 00:00:00 2001 From: Ryo Wakizaka Date: Wed, 26 Nov 2025 15:33:58 +0900 Subject: [PATCH 03/26] Add init/free SQC system --- src/providers/sqc_backend.hpp | 47 ++++++++++++++++++++--------------- src/providers/sqc_job.hpp | 13 ++-------- 2 files changed, 29 insertions(+), 31 deletions(-) diff --git a/src/providers/sqc_backend.hpp b/src/providers/sqc_backend.hpp index c1fe450..31bb43a 100644 --- a/src/providers/sqc_backend.hpp +++ b/src/providers/sqc_backend.hpp @@ -22,7 +22,7 @@ #include "primitives/containers/sampler_pub.hpp" #include "providers/job.hpp" -//#include "sqc_api.h" +#include "sqc_api.h" namespace Qiskit { namespace providers { @@ -30,30 +30,40 @@ namespace providers { /// @class SQCBackend /// @brief Backend class using SQC. class SQCBackend : public BackendV2 { +private: + sqcInitOptions* init_options_; + const sqcBackend backend_type_; + public: - /// @brief Create a new QRMIBackend - SQCBackend() {} + /// @brief Create a new SQCBackend. Internally this initializes SQC. + SQCBackend() + : SQCBackend("unspecified") + {} - /// @brief Create a new QRMIBackend object + /// @brief Create a new SQCBackend object /// @param backend_name a resource name for backend. SQCBackend(const std::string name) + : name_(name), + init_options_(nullptr), + backend_type_(SQC_RPC_SCHED_QC_TYPE_IBM_DACC) { - this->name_ = name; + init_options_ = sqcMallocInitOptions(); + init_options_->use_qiskit = 1; // only ibm_dacc is supported + sqcInitialize(init_options_); } - /// @brief Create a new SQCBackend from other - SQCBackend(const SQCBackend& other) - { - this->name_ = other.name_; - } + SQCBackend(const SQCBackend& other) = delete; - ~SQCBackend() {} + ~SQCBackend() { + sqcFinalize(init_options_); + sqcFreeInitOptions(init_options_); + } - /// @brief Return a target properties for this backend - /// @return a target class + /// @brief Return a target properties for this backend. + /// @return a target class (nullptr) std::shared_ptr target(void) override { - std::cout << "called SQCBackend::target()" << std::endl; + std::cerr << "Error: SQCBackend::target() cannot be used" << std::endl; return nullptr; } @@ -61,16 +71,13 @@ class SQCBackend : public BackendV2 { /// @return PrimitiveJob std::shared_ptr run(std::vector& input_pubs, uint_t shots) override { - std::string qasm3 = [&]() { - auto circuit = input_pubs[0].circuit(); - return circuit.to_qasm3(); - }(); - std::cout << "run qasm3: \n" << qasm3 << std::endl; + auto circuit = input_pubs[0].circuit(); + std::cout << "run qasm3: \n" << circuit.to_qasm3() << std::endl; return nullptr; } - }; + } // namespace providers } // namespace Qiskit diff --git a/src/providers/sqc_job.hpp b/src/providers/sqc_job.hpp index 5674636..e6e4e17 100644 --- a/src/providers/sqc_job.hpp +++ b/src/providers/sqc_job.hpp @@ -44,9 +44,9 @@ class SQCJob : public Job { /// @brief Create a new QkrtBackend object /// @param qrmi a pointer to QRMI handle /// @param job an id of the job - SQCJob(const std::string& job) + SQCJob(const std::string& job_id) { - job_id_ = job; + job_id_ = job_id; num_results_ = 0; } @@ -95,15 +95,6 @@ class SQCJob : public Job { protected: void read_results(void) { - //char *result = nullptr; - //int rc = qrmi_resource_task_result(qrmi_.get(), job_id_.c_str(), &result); - //if (rc == QRMI_RETURN_CODE_SUCCESS) { - // results_ = nlohmann::ordered_json::parse(result); - - // num_results_ = results_["results"].size(); - // qrmi_string_free((char *)result); - //} - //qrmi_resource_task_stop(qrmi_.get(), job_id_.c_str()); } }; From 35720a0f2ed796ef6c272bb23a5435b3da45068a Mon Sep 17 00:00:00 2001 From: Ryo Wakizaka Date: Wed, 26 Nov 2025 16:41:28 +0900 Subject: [PATCH 04/26] Build a target information via SQC API --- src/providers/sqc_backend.hpp | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/providers/sqc_backend.hpp b/src/providers/sqc_backend.hpp index 31bb43a..2112074 100644 --- a/src/providers/sqc_backend.hpp +++ b/src/providers/sqc_backend.hpp @@ -37,7 +37,7 @@ class SQCBackend : public BackendV2 { public: /// @brief Create a new SQCBackend. Internally this initializes SQC. SQCBackend() - : SQCBackend("unspecified") + : SQCBackend("unspecified") // @TODO {} /// @brief Create a new SQCBackend object @@ -63,8 +63,28 @@ class SQCBackend : public BackendV2 { /// @return a target class (nullptr) std::shared_ptr target(void) override { - std::cerr << "Error: SQCBackend::target() cannot be used" << std::endl; - return nullptr; + if(target_) { + return target_; + } + + // Create a dummy circuit to get target json files + std::unique_ptr qc_handle(sqcQuantumCircuit(0), sqcDestroyQuantumCircuit); + if(sqcIbmdTranspileInfo(qc_handle.get(), backend_type_) != SQC_RESULT_OK) { + std::cerr << "Failed to get the target information" << std::endl; + return nullptr; + } + + nlohmann::ordered_json target_json; + target_json["configuration"] = nlohmann::ordered_json::parse(qc_handle->backend_config_json) + target_json["properties"] = nlohmann::ordered_json::parse(qc_handle->backend_props_json); + auto target = std::shared_ptr(); + if(!target->from_json(target_json)) { + std::cerr << "Failed to create a target from json files" << std::endl; + return nullptr; + } + target_ = target; + + return target_; } /// @brief Run and collect samples from each pub. From 0afd1d893db9ce0bfed10fc9c8f714cee572fc08 Mon Sep 17 00:00:00 2001 From: Ryo Wakizaka Date: Wed, 26 Nov 2025 18:02:16 +0900 Subject: [PATCH 05/26] Implement a conversion from qiskit circuits to SQC circuits --- src/providers/sqc_backend.hpp | 123 +++++++++++++++++++++++++++++++++- 1 file changed, 122 insertions(+), 1 deletion(-) diff --git a/src/providers/sqc_backend.hpp b/src/providers/sqc_backend.hpp index 2112074..d5bc9d6 100644 --- a/src/providers/sqc_backend.hpp +++ b/src/providers/sqc_backend.hpp @@ -92,12 +92,133 @@ class SQCBackend : public BackendV2 { std::shared_ptr run(std::vector& input_pubs, uint_t shots) override { auto circuit = input_pubs[0].circuit(); - std::cout << "run qasm3: \n" << circuit.to_qasm3() << std::endl; + auto qasm_str = circuit.to_qasm3(); + std::cout << "run qasm3: \n" << qasm_str << std::endl; + return nullptr; } }; +/// @brief Convert a qiskit quantum circuit to a SQC circuit. +/// @param A SQC circuit where a result is stored +/// @param An original qiskit circuit +/// @note This function destroys the original SQC circuit data. +/// @note Currently parameterized circuits are not supported. +bool qk_circ_to_sqc_circ(sqcQC* qc_handle, const circuit::QuantumCircuit& qk_circ) +{ + if(qc_handle == NULL) + { + std::cerr << "Error: Given SQC handle is null." << std::endl; + return false; + } + if(qk_circ.num_instructions() > MAX_N_GATES) + { + std::cerr << "Error: The number of a given circuit exceeds the limit of SQC." << std::endl; + return false; + } + + qc_handle->qubits = static_cast(qk_circ.num_qubits()); + qc_handle->ngates = static_cast(qk_circ.num_instructions()); + + for(int i = 0; i < static_cast(qk_circ.num_instructions()); ++i) { + const auto circ_instr = qk_circ[i]; + const auto& instr_name = circ_instr.instruction().name(); + const auto& qubits = circ_instr.qubits(); + const auto& clbits = circ_instr.clbits(); + + if(instr_name == "measure") + { + sqcMeasure(qc_handle, qubits[0], clbits[0], NULL); + } + else if(instr_name == "h") + { + sqcHGate(qc_handle, qubits[0]); + } + else if(instr_name == "cx") + { + sqcCXGate(qc_handle, qubits[0], qubits[1]); + } + else if(instr_name == "cz") + { + sqcCXGate(qc_handle, qubits[0], qubits[1]); + } + else if(instr_name == "rz") + { + sqcRZGate(qc_handle, qubits[0], qubits[1]); + } + else if(instr_name == "s") + { + sqcSGate(qc_handle, qubits[0]); + } + else if(instr_name == "sdg") + { + sqcSdgGate(qc_handle, qubits[0]); + } + else if(instr_name == "rx") + { + const auto& instr = circ_instr.instruction(); + assert(instr.params().size() == 1); + sqcRXGate(qc_handle, instr.params()[0], qubits[0]); + } + else if(instr_name == "ry") + { + const auto& instr = circ_instr.instruction(); + assert(instr.params().size() == 1); + sqcRZGate(qc_handle, instr.params()[0], qubits[0]); + } + else if(instr_name == "x") + { + sqcXGate(qc_handle, qubits[0]); + } + else if(instr_name == "z") + { + sqcZGate(qc_handle, qubits[0]); + } + else if(instr_name == "p") + { + sqcU1Gate(qc_handle, qubits[0]); + } + else if(instr_name == "reset") + { + sqcReset(qc_handle, qubits[0]); + } + else if(instr_name == "barrier") + { + for(auto qubit : qubits) + { + sqcBarrier(qc_handle, qubit); + } + } + else if(instr_name == "ecr") + { + sqcECRGate(qc_handle, qubits[0], qubits[1]); + } + else if(instr_name == "sx") + { + sqcSXGate(qc_handle, qubits[0]); + } + else if(instr_name == "id") + { + sqcIDGate(qc_handle, qubits[0]); + } + else if(instr_name == "delay") + { + // TODO + std::cerr << "Error (WIP): The delay operation is not support now." << std::endl; + return false; + } + else + { + std::cerr << "Error: An instruction " << instr_name << " is not supported in SQC." << std::endl; + return false; + } + } + + return true; +} + + } // namespace providers } // namespace Qiskit From bf3ad5c73e7df03b23ece658b412ad1202f9a09b Mon Sep 17 00:00:00 2001 From: Ryo Wakizaka Date: Wed, 26 Nov 2025 18:48:19 +0900 Subject: [PATCH 06/26] [WIP] Implementing circuit execution --- src/providers/sqc_backend.hpp | 51 +++++++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 8 deletions(-) diff --git a/src/providers/sqc_backend.hpp b/src/providers/sqc_backend.hpp index d5bc9d6..0213e72 100644 --- a/src/providers/sqc_backend.hpp +++ b/src/providers/sqc_backend.hpp @@ -32,6 +32,9 @@ namespace providers { class SQCBackend : public BackendV2 { private: sqcInitOptions* init_options_; + /// @note A circuit data will be built via qiskit-cpp, not SQC. + /// A `qc_handle_` field is just used for an interface between qiskit-cpp and SQC. + sqcQC* qc_handle_; const sqcBackend backend_type_; public: @@ -44,17 +47,22 @@ class SQCBackend : public BackendV2 { /// @param backend_name a resource name for backend. SQCBackend(const std::string name) : name_(name), - init_options_(nullptr), - backend_type_(SQC_RPC_SCHED_QC_TYPE_IBM_DACC) + init_options_(NULL), + qc_handle_(NULL), + backend_type_(SQC_RPC_SCHED_QC_TYPE_IBM_DACC), { init_options_ = sqcMallocInitOptions(); init_options_->use_qiskit = 1; // only ibm_dacc is supported - sqcInitialize(init_options_); + if(sqcInitialize(init_options_) != E_SUCCESS) { + std::cerr << "Failed to initialize SQC" << std::endl; + } + qc_handle_ = sqcQuantumCircuit(0); } SQCBackend(const SQCBackend& other) = delete; ~SQCBackend() { + sqcDestroyQuantumCircuit(qc_handle_); sqcFinalize(init_options_); sqcFreeInitOptions(init_options_); } @@ -63,9 +71,7 @@ class SQCBackend : public BackendV2 { /// @return a target class (nullptr) std::shared_ptr target(void) override { - if(target_) { - return target_; - } + if(target_) return target_; // Create a dummy circuit to get target json files std::unique_ptr qc_handle(sqcQuantumCircuit(0), sqcDestroyQuantumCircuit); @@ -92,8 +98,37 @@ class SQCBackend : public BackendV2 { std::shared_ptr run(std::vector& input_pubs, uint_t shots) override { auto circuit = input_pubs[0].circuit(); - auto qasm_str = circuit.to_qasm3(); - std::cout << "run qasm3: \n" << qasm_str << std::endl; + std::cout << "run qasm3: \n" << circuit.to_qasm3() << std::endl; + + if(!qk_circ_to_sqc_circ(qc_handle_, circuit)) + { + std::cerr << "Error: Failed to convert a given qiskit circuit to a SQC circuit." << std::endl; + return nullptr; + } + + // @TODO: gateInfo2qasm3 is implemented in sqc_api.c, but not declared in the header file. + qc_handle_->qasm = gateInfo2qasm3(qc_handle_); + + std::unique_ptr run_options(new sqcRunOption); + sqcInitializeRunOpt(run_options.get()); + run_options->nshots = shots; + run_options->qubits = qc_handle_->qubits; + run_options->outFormat = SQC_OUT_RAW; // @TODO + + std::unique_ptr result(new sqcOut, + [&run_options](sqcOut* out) { sqcFreeOut(out, run_options->outFormat); }); + int error_code = sqcQCRun(qc_handle_, backend_type_, *run_options, result); + + if(error_code != SQC_RESULT_OK) + { + std::cerr << "Error: Failed to run a SQC circuit." << std::endl; + return nullptr; + } + + auto result_json = nlohmann::ordered_json::parse(result->result); + + // TODO: create a job + // note: Current SQC api does not support async execution return nullptr; } From f3232698e6b540424ab0d092c84bc9fb18ce1791 Mon Sep 17 00:00:00 2001 From: Ryo Wakizaka Date: Thu, 27 Nov 2025 14:05:03 +0900 Subject: [PATCH 07/26] Implement a SQC Job and execution of sampler pubs --- src/providers/sqc_backend.hpp | 11 +++---- src/providers/sqc_job.hpp | 61 +++++++++++++++++------------------ 2 files changed, 33 insertions(+), 39 deletions(-) diff --git a/src/providers/sqc_backend.hpp b/src/providers/sqc_backend.hpp index 0213e72..e276fb5 100644 --- a/src/providers/sqc_backend.hpp +++ b/src/providers/sqc_backend.hpp @@ -94,7 +94,7 @@ class SQCBackend : public BackendV2 { } /// @brief Run and collect samples from each pub. - /// @return PrimitiveJob + /// @return SQCJob std::shared_ptr run(std::vector& input_pubs, uint_t shots) override { auto circuit = input_pubs[0].circuit(); @@ -116,7 +116,7 @@ class SQCBackend : public BackendV2 { run_options->outFormat = SQC_OUT_RAW; // @TODO std::unique_ptr result(new sqcOut, - [&run_options](sqcOut* out) { sqcFreeOut(out, run_options->outFormat); }); + [&run_options](sqcOut* out) { sqcFreeOut(out, run_options->outFormat); }); int error_code = sqcQCRun(qc_handle_, backend_type_, *run_options, result); if(error_code != SQC_RESULT_OK) @@ -125,12 +125,9 @@ class SQCBackend : public BackendV2 { return nullptr; } - auto result_json = nlohmann::ordered_json::parse(result->result); + auto results_json = nlohmann::ordered_json::parse(result->result); - // TODO: create a job - // note: Current SQC api does not support async execution - - return nullptr; + return std::make_shared(results_json); } }; diff --git a/src/providers/sqc_job.hpp b/src/providers/sqc_job.hpp index e6e4e17..b0988ad 100644 --- a/src/providers/sqc_job.hpp +++ b/src/providers/sqc_job.hpp @@ -14,8 +14,8 @@ // Job class for SQC -#ifndef __qiskitcpp_providers_SQC_job_def_hpp__ -#define __qiskitcpp_providers_SQC_job_def_hpp__ +#ifndef __qiskitcpp_providers_SQC_job_hpp__ +#define __qiskitcpp_providers_SQC_job_hpp__ #include @@ -34,27 +34,32 @@ class SQCJob : public Job { std::string job_id_; nlohmann::ordered_json results_; // json formatted results (converted output from SQC) uint_t num_results_ = 0; + public: - /// @brief Create a new QkrtBackend + /// @brief Create a new SQCBackend SQCJob() - { - num_results_ = 0; - } + : SQCJob("") + {} - /// @brief Create a new QkrtBackend object - /// @param qrmi a pointer to QRMI handle - /// @param job an id of the job + /// @brief Create a new SQCBackend object SQCJob(const std::string& job_id) - { - job_id_ = job_id; - num_results_ = 0; - } - - /// @brief Create a new QkrtJob from other + : job_id_(job_id), + num_results_(0) + {} + + /// @note [TODO] This constructor will be removed after SQC API provides a async job execution + SQCJob(const nlohmann::ordered_json results) + : job_id_(""), + num_results_(results["results"].size()), + results_(results) + {} + + /// @brief Create a new SQCJob from other SQCJob(const SQCJob& other) { job_id_ = other.job_id_; - num_results_ = 0; + num_results_ = other.num_results_; + results_ = other.results_; } ~SQCJob() {} @@ -63,7 +68,8 @@ class SQCJob : public Job { /// @return JobStatus enum. providers::JobStatus status(void) override { - return providers::JobStatus::FAILED; + /// @todo Wait SQC API for making the status request API public. + return providers::JobStatus::DONE; } @@ -71,30 +77,21 @@ class SQCJob : public Job { /// @return number of results uint_t num_results(void) override { - if (num_results_ == 0) - read_results(); return num_results_; } /// @brief get sampler pub result - /// @param index an index of the reuslt + /// @param index an index of the result /// @param result an output sampler pub result /// @return true if result is successfully set bool result(uint_t index, primitives::SamplerPubResult& result) override { - //if (num_results_ == 0) - // read_results(); - - //if (index >= num_results_) - // return false; + if (index >= num_results_) + return false; - //result.from_json(results_["results"][index]); - return false; - } + result.from_json(results_["results"][index]); -protected: - void read_results(void) - { + return true; } }; @@ -102,6 +99,6 @@ class SQCJob : public Job { } // namespace Qiskit -#endif //__qiskitcpp_providers_QRMI_job_def_hpp__ +#endif //__qiskitcpp_providers_SQC_job_hpp__ From fbff50759d9405fddb02333e8c5247133709324d Mon Sep 17 00:00:00 2001 From: Ryo Wakizaka Date: Thu, 27 Nov 2025 14:26:59 +0900 Subject: [PATCH 08/26] minor fix --- src/providers/sqc_backend.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/providers/sqc_backend.hpp b/src/providers/sqc_backend.hpp index e276fb5..d01afc1 100644 --- a/src/providers/sqc_backend.hpp +++ b/src/providers/sqc_backend.hpp @@ -115,8 +115,7 @@ class SQCBackend : public BackendV2 { run_options->qubits = qc_handle_->qubits; run_options->outFormat = SQC_OUT_RAW; // @TODO - std::unique_ptr result(new sqcOut, - [&run_options](sqcOut* out) { sqcFreeOut(out, run_options->outFormat); }); + std::unique_ptr result(new sqcOut, [](sqcOut* out) { sqcFreeOut(out, SQC_OUT_RAW); }); int error_code = sqcQCRun(qc_handle_, backend_type_, *run_options, result); if(error_code != SQC_RESULT_OK) From 19be22e4d427b49f1ad8a2045a20a0cae449c2b2 Mon Sep 17 00:00:00 2001 From: Ryo Wakizaka Date: Thu, 27 Nov 2025 14:36:15 +0900 Subject: [PATCH 09/26] Move initialization and finalization of SQC to runtime service --- src/providers/sqc_backend.hpp | 15 +++------------ src/service/qiskit_runtime_service_sqc.hpp | 12 ++++++++++++ 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/providers/sqc_backend.hpp b/src/providers/sqc_backend.hpp index d01afc1..4afb9f5 100644 --- a/src/providers/sqc_backend.hpp +++ b/src/providers/sqc_backend.hpp @@ -31,7 +31,6 @@ namespace providers { /// @brief Backend class using SQC. class SQCBackend : public BackendV2 { private: - sqcInitOptions* init_options_; /// @note A circuit data will be built via qiskit-cpp, not SQC. /// A `qc_handle_` field is just used for an interface between qiskit-cpp and SQC. sqcQC* qc_handle_; @@ -47,24 +46,16 @@ class SQCBackend : public BackendV2 { /// @param backend_name a resource name for backend. SQCBackend(const std::string name) : name_(name), - init_options_(NULL), qc_handle_(NULL), backend_type_(SQC_RPC_SCHED_QC_TYPE_IBM_DACC), { - init_options_ = sqcMallocInitOptions(); - init_options_->use_qiskit = 1; // only ibm_dacc is supported - if(sqcInitialize(init_options_) != E_SUCCESS) { - std::cerr << "Failed to initialize SQC" << std::endl; - } + qc_handle_ = sqcQuantumCircuit(0); } - SQCBackend(const SQCBackend& other) = delete; - - ~SQCBackend() { + ~SQCBackend() + { sqcDestroyQuantumCircuit(qc_handle_); - sqcFinalize(init_options_); - sqcFreeInitOptions(init_options_); } /// @brief Return a target properties for this backend. diff --git a/src/service/qiskit_runtime_service_sqc.hpp b/src/service/qiskit_runtime_service_sqc.hpp index f7e9c37..df4b5a9 100644 --- a/src/service/qiskit_runtime_service_sqc.hpp +++ b/src/service/qiskit_runtime_service_sqc.hpp @@ -24,14 +24,26 @@ namespace service { class QiskitRuntimeService { private: + sqcInitOptions* init_options_; + public: /// @brief Create a new runtime service class QiskitRuntimeService() + : init_options_(NULL) { + init_options_ = sqcMallocInitOptions(); + init_options_->use_qiskit = 1; // only ibm_dacc is supported + if(sqcInitialize(init_options_) != E_SUCCESS) { + std::cerr << "Failed to initialize SQC" << std::endl; + } } + QiskitRuntimeService(QiskitRuntimeService const&) = delete; + ~QiskitRuntimeService() { + sqcFinalize(init_options_); + sqcFreeInitOptions(init_options_); } /// @brief create a new backend object From 36ee1f9719b670e0109d1c3a63e4767817bc499a Mon Sep 17 00:00:00 2001 From: Ryo Wakizaka Date: Thu, 4 Dec 2025 17:04:55 +0900 Subject: [PATCH 10/26] Fix errors --- src/providers/sqc_backend.hpp | 73 ++++++++++++---------- src/providers/sqc_job.hpp | 2 +- src/service/qiskit_runtime_service_sqc.hpp | 2 - 3 files changed, 41 insertions(+), 36 deletions(-) diff --git a/src/providers/sqc_backend.hpp b/src/providers/sqc_backend.hpp index 4afb9f5..8b840ae 100644 --- a/src/providers/sqc_backend.hpp +++ b/src/providers/sqc_backend.hpp @@ -17,46 +17,54 @@ #ifndef __qiskitcpp_providers_SQC_backend_def_hpp__ #define __qiskitcpp_providers_SQC_backend_def_hpp__ +#include + #include "utils/types.hpp" #include "transpiler/target.hpp" #include "primitives/containers/sampler_pub.hpp" -#include "providers/job.hpp" +#include "providers/sqc_job.hpp" +#include "sqc_ecode.h" #include "sqc_api.h" namespace Qiskit { namespace providers { +/// @brief Convert a qiskit quantum circuit to a SQC circuit. +/// @param A SQC circuit where a result is stored +/// @param An original qiskit circuit +/// @note This function destroys the original SQC circuit data. +/// @note Currently parameterized circuits are not supported. +bool qk_circ_to_sqc_circ(sqcQC* qc_handle, circuit::QuantumCircuit& qk_circ); + /// @class SQCBackend /// @brief Backend class using SQC. class SQCBackend : public BackendV2 { private: - /// @note A circuit data will be built via qiskit-cpp, not SQC. - /// A `qc_handle_` field is just used for an interface between qiskit-cpp and SQC. - sqcQC* qc_handle_; const sqcBackend backend_type_; + std::shared_ptr target_; public: /// @brief Create a new SQCBackend. Internally this initializes SQC. SQCBackend() - : SQCBackend("unspecified") // @TODO + : SQCBackend("unspecified") {} /// @brief Create a new SQCBackend object /// @param backend_name a resource name for backend. SQCBackend(const std::string name) - : name_(name), - qc_handle_(NULL), + : BackendV2(name), backend_type_(SQC_RPC_SCHED_QC_TYPE_IBM_DACC), - { - - qc_handle_ = sqcQuantumCircuit(0); - } + target_(nullptr) + {} - ~SQCBackend() - { - sqcDestroyQuantumCircuit(qc_handle_); - } + SQCBackend(const SQCBackend& other) + : BackendV2(other.name_), + backend_type_(other.backend_type_), + target_(other.target_) + {} + + ~SQCBackend() {} /// @brief Return a target properties for this backend. /// @return a target class (nullptr) @@ -65,14 +73,14 @@ class SQCBackend : public BackendV2 { if(target_) return target_; // Create a dummy circuit to get target json files - std::unique_ptr qc_handle(sqcQuantumCircuit(0), sqcDestroyQuantumCircuit); + std::unique_ptr qc_handle(sqcQuantumCircuit(0), &sqcDestroyQuantumCircuit); if(sqcIbmdTranspileInfo(qc_handle.get(), backend_type_) != SQC_RESULT_OK) { std::cerr << "Failed to get the target information" << std::endl; return nullptr; } nlohmann::ordered_json target_json; - target_json["configuration"] = nlohmann::ordered_json::parse(qc_handle->backend_config_json) + target_json["configuration"] = nlohmann::ordered_json::parse(qc_handle->backend_config_json); target_json["properties"] = nlohmann::ordered_json::parse(qc_handle->backend_props_json); auto target = std::shared_ptr(); if(!target->from_json(target_json)) { @@ -89,25 +97,28 @@ class SQCBackend : public BackendV2 { std::shared_ptr run(std::vector& input_pubs, uint_t shots) override { auto circuit = input_pubs[0].circuit(); - std::cout << "run qasm3: \n" << circuit.to_qasm3() << std::endl; - - if(!qk_circ_to_sqc_circ(qc_handle_, circuit)) + const auto qasm3_str = circuit.to_qasm3(); + std::cout << "run qasm3: \n" << qasm3_str << std::endl; + + // Create a sqcQC from a qiskit circuit + const uint_t qasm_len = qasm3_str.size() + 500; + std::unique_ptr sqc_circ(sqcQuantumCircuit(0), &sqcDestroyQuantumCircuit); + sqc_circ->qasm = (char*)malloc(qasm_len); + if(!qk_circ_to_sqc_circ(sqc_circ.get(), circuit)) { std::cerr << "Error: Failed to convert a given qiskit circuit to a SQC circuit." << std::endl; return nullptr; } - - // @TODO: gateInfo2qasm3 is implemented in sqc_api.c, but not declared in the header file. - qc_handle_->qasm = gateInfo2qasm3(qc_handle_); + sqcConvQASMtoMemory(sqc_circ.get(), backend_type_, sqc_circ->qasm, qasm_len); std::unique_ptr run_options(new sqcRunOption); sqcInitializeRunOpt(run_options.get()); run_options->nshots = shots; - run_options->qubits = qc_handle_->qubits; + run_options->qubits = sqc_circ->qubits; run_options->outFormat = SQC_OUT_RAW; // @TODO - std::unique_ptr result(new sqcOut, [](sqcOut* out) { sqcFreeOut(out, SQC_OUT_RAW); }); - int error_code = sqcQCRun(qc_handle_, backend_type_, *run_options, result); + std::shared_ptr result(new sqcOut, [](sqcOut* out) { sqcFreeOut(out, SQC_OUT_RAW); }); + int error_code = sqcQCRun(sqc_circ.get(), backend_type_, *run_options, result.get()); if(error_code != SQC_RESULT_OK) { @@ -122,12 +133,7 @@ class SQCBackend : public BackendV2 { }; -/// @brief Convert a qiskit quantum circuit to a SQC circuit. -/// @param A SQC circuit where a result is stored -/// @param An original qiskit circuit -/// @note This function destroys the original SQC circuit data. -/// @note Currently parameterized circuits are not supported. -bool qk_circ_to_sqc_circ(sqcQC* qc_handle, const circuit::QuantumCircuit& qk_circ) +bool qk_circ_to_sqc_circ(sqcQC* qc_handle, circuit::QuantumCircuit& qk_circ) { if(qc_handle == NULL) { @@ -199,7 +205,8 @@ bool qk_circ_to_sqc_circ(sqcQC* qc_handle, const circuit::QuantumCircuit& qk_cir } else if(instr_name == "p") { - sqcU1Gate(qc_handle, qubits[0]); + const auto& instr = circ_instr.instruction(); + sqcU1Gate(qc_handle, instr.params()[0], qubits[0]); } else if(instr_name == "reset") { diff --git a/src/providers/sqc_job.hpp b/src/providers/sqc_job.hpp index b0988ad..61ad051 100644 --- a/src/providers/sqc_job.hpp +++ b/src/providers/sqc_job.hpp @@ -38,7 +38,7 @@ class SQCJob : public Job { public: /// @brief Create a new SQCBackend SQCJob() - : SQCJob("") + : SQCJob(std::string{""}) {} /// @brief Create a new SQCBackend object diff --git a/src/service/qiskit_runtime_service_sqc.hpp b/src/service/qiskit_runtime_service_sqc.hpp index df4b5a9..6ab9ebb 100644 --- a/src/service/qiskit_runtime_service_sqc.hpp +++ b/src/service/qiskit_runtime_service_sqc.hpp @@ -38,8 +38,6 @@ class QiskitRuntimeService { } } - QiskitRuntimeService(QiskitRuntimeService const&) = delete; - ~QiskitRuntimeService() { sqcFinalize(init_options_); From 4a110aaaa5b1848b06e475ee3a4a8442ddf42817 Mon Sep 17 00:00:00 2001 From: Ryo Wakizaka Date: Thu, 4 Dec 2025 17:16:12 +0900 Subject: [PATCH 11/26] Fix typo --- src/providers/sqc_backend.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/providers/sqc_backend.hpp b/src/providers/sqc_backend.hpp index 8b840ae..fee8a1e 100644 --- a/src/providers/sqc_backend.hpp +++ b/src/providers/sqc_backend.hpp @@ -111,7 +111,7 @@ class SQCBackend : public BackendV2 { } sqcConvQASMtoMemory(sqc_circ.get(), backend_type_, sqc_circ->qasm, qasm_len); - std::unique_ptr run_options(new sqcRunOption); + std::unique_ptr run_options(new sqcRunOptions); sqcInitializeRunOpt(run_options.get()); run_options->nshots = shots; run_options->qubits = sqc_circ->qubits; From caef4ae2e3b7be62cf9b15f23bedf55d374b6758 Mon Sep 17 00:00:00 2001 From: Ryo Wakizaka Date: Thu, 4 Dec 2025 17:51:53 +0900 Subject: [PATCH 12/26] Update CMakeLists.txt --- samples/CMakeLists.txt | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index 1a404be..26c206a 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -36,7 +36,8 @@ function(add_application APP_NAME CPP_FILE) PUBLIC ${QISKIT_ROOT}/target/release ${QRMI_ROOT}/target/release - #${SQC_ROOT}/ + ${SQC_ROOT}/lib + ${SQC_ROOT}/lib64 ${QISKIT_IBM_RUNTIME_C_ROOT}/build/cargo/debug ) if(QRMI_ROOT) @@ -45,9 +46,8 @@ function(add_application APP_NAME CPP_FILE) elseif(QISKIT_IBM_RUNTIME_C_ROOT) target_link_libraries(${APP_NAME} qiskit_cext.dll.lib qiskit_ibm_runtime.dll.lib nlohmann_json::nlohmann_json) set(CMAKE_CXX_FLAGS "-DQISKIT_IBM_RUNTIME_C_ROOT=${QISKIT_IBM_RUNTIME_C_ROOT}") - #elseif(SQC_ROOT) - #target_link_libraries(${APP_NAME} qiskit_cext.dll.lib nlohmann_json::nlohmann_json) - #set(CMAKE_CXX_FLAGS "-DSQC_ROOT=${SQC_ROOT}") + #else(SQC_ROOT) + # SQC for MSVC is not supported else() target_link_libraries(${APP_NAME} qiskit_cext.dll.lib nlohmann_json::nlohmann_json) target_compile_options(${APP_NAME} PRIVATE "-DQISKIT_IBM_RUNTIME_C_ROOT=${QISKIT_IBM_RUNTIME_C_ROOT}") @@ -65,12 +65,12 @@ function(add_application APP_NAME CPP_FILE) "-L${QISKIT_ROOT}/dist/c/lib -L${QISKIT_IBM_RUNTIME_C_ROOT}/build/cargo/debug -Wl,-rpath ${QISKIT_ROOT}/dist/c/lib -Wl,-rpath ${QISKIT_IBM_RUNTIME_C_ROOT}/build/cargo/debug" qiskit qiskit_ibm_runtime nlohmann_json::nlohmann_json ) target_compile_options(${APP_NAME} PRIVATE "-DQISKIT_IBM_RUNTIME_C_ROOT=${QISKIT_IBM_RUNTIME_C_ROOT}") - #elseif(SQC_ROOT) - # target_link_libraries(${APP_NAME} - # PRIVATE - # "-L${QISKIT_ROOT}/dist/c/lib -L${SQC_ROOT}/ -Wl,-rpath ${QISKIT_ROOT}/dist/c/lib -Wl,-rpath ${QISKIT_IBM_RUNTIME_C_ROOT}/build/cargo/debug" qiskit qiskit_ibm_runtime nlohmann_json::nlohmann_json - # ) - # target_compile_options(${APP_NAME} PRIVATE "-DSQC_ROOT=${SQC_ROOT}") + elseif(SQC_ROOT) + target_link_libraries(${APP_NAME} + PRIVATE + "-L${QISKIT_ROOT}/dist/c/lib -L${SQC_ROOT}/lib -L${SQC_ROOT}/lib -Wl,-rpath ${QISKIT_ROOT}/dist/c/lib ${SQC_COMPILE_OPTIONS}" qiskit nlohmann_json::nlohmann_json + ) + target_compile_options(${APP_NAME} PRIVATE "-DSQC_ROOT=${SQC_ROOT} -DSQC_COMPILE_OPTIONS=${SQC_COMPILE_OPTIONS}") else() target_link_libraries(${APP_NAME} PRIVATE @@ -85,7 +85,7 @@ function(add_application APP_NAME CPP_FILE) ${QISKIT_ROOT}/dist/c/include ${QRMI_ROOT} ${QISKIT_IBM_RUNTIME_C_ROOT}/include - ${SQC_ROOT}/capi/include + ${SQC_ROOT}/include ${SAMPLES_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/../src nlohmann_json::nlohmann_json From cfc4448d8129dd14500fd3fbcd60fb2bdc8074fb Mon Sep 17 00:00:00 2001 From: Ryo Wakizaka Date: Thu, 4 Dec 2025 18:20:08 +0900 Subject: [PATCH 13/26] Fix CMakeLists.txt --- samples/CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index 26c206a..b5d9052 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -68,9 +68,9 @@ function(add_application APP_NAME CPP_FILE) elseif(SQC_ROOT) target_link_libraries(${APP_NAME} PRIVATE - "-L${QISKIT_ROOT}/dist/c/lib -L${SQC_ROOT}/lib -L${SQC_ROOT}/lib -Wl,-rpath ${QISKIT_ROOT}/dist/c/lib ${SQC_COMPILE_OPTIONS}" qiskit nlohmann_json::nlohmann_json + "-L${QISKIT_ROOT}/dist/c/lib -L${SQC_ROOT}/lib -L${SQC_ROOT}/lib -Wl,-rpath ${QISKIT_ROOT}/dist/c/lib $ENV{SQC_LINK_OPTIONS}" qiskit nlohmann_json::nlohmann_json ) - target_compile_options(${APP_NAME} PRIVATE "-DSQC_ROOT=${SQC_ROOT} -DSQC_COMPILE_OPTIONS=${SQC_COMPILE_OPTIONS}") + target_compile_options(${APP_NAME} PRIVATE "-DSQC_ROOT=${SQC_ROOT} -DSQC_LINK_OPTIONS=${SQC_LINK_OPTIONS}") else() target_link_libraries(${APP_NAME} PRIVATE @@ -107,6 +107,6 @@ if(QRMI_ROOT OR QISKIT_IBM_RUNTIME_C_ROOT) add_application(transpile_test transpile_test.cpp) endif() -if(SQC_ROOT) +if(SQC_ROOT AND SQC_LINK_OPTIONS) add_application(sqc_test sqc_test.cpp) endif() From 28f642f9db762369f0b88dd3cf42bca8da5f9127 Mon Sep 17 00:00:00 2001 From: Ryo Wakizaka Date: Thu, 4 Dec 2025 18:21:40 +0900 Subject: [PATCH 14/26] Fix path --- samples/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index b5d9052..6be212d 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -68,7 +68,7 @@ function(add_application APP_NAME CPP_FILE) elseif(SQC_ROOT) target_link_libraries(${APP_NAME} PRIVATE - "-L${QISKIT_ROOT}/dist/c/lib -L${SQC_ROOT}/lib -L${SQC_ROOT}/lib -Wl,-rpath ${QISKIT_ROOT}/dist/c/lib $ENV{SQC_LINK_OPTIONS}" qiskit nlohmann_json::nlohmann_json + "-L${QISKIT_ROOT}/dist/c/lib -L${SQC_ROOT}/lib -L${SQC_ROOT}/lib64 -Wl,-rpath ${QISKIT_ROOT}/dist/c/lib $ENV{SQC_LINK_OPTIONS}" qiskit nlohmann_json::nlohmann_json ) target_compile_options(${APP_NAME} PRIVATE "-DSQC_ROOT=${SQC_ROOT} -DSQC_LINK_OPTIONS=${SQC_LINK_OPTIONS}") else() From 6c433bd21cdd44edf541c8a6886fe8941ee792b7 Mon Sep 17 00:00:00 2001 From: Ryo Wakizaka Date: Thu, 4 Dec 2025 18:25:40 +0900 Subject: [PATCH 15/26] Clean unnecessary files --- samples/CMakeLists.txt | 6 +- samples/sqc_test.cpp | 111 ------------------------- src/service/qiskit_runtime_service.hpp | 2 + 3 files changed, 3 insertions(+), 116 deletions(-) delete mode 100644 samples/sqc_test.cpp diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index 6be212d..327f4f8 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -102,11 +102,7 @@ endfunction() add_application(circuit_test circuit_test.cpp) add_application(observable_test observable_test.cpp) -if(QRMI_ROOT OR QISKIT_IBM_RUNTIME_C_ROOT) +if(QRMI_ROOT OR QISKIT_IBM_RUNTIME_C_ROOT OR (SQC_ROOT AND SQC_LINK_OPTIONS)) add_application(sampler_test sampler_test.cpp) add_application(transpile_test transpile_test.cpp) endif() - -if(SQC_ROOT AND SQC_LINK_OPTIONS) - add_application(sqc_test sqc_test.cpp) -endif() diff --git a/samples/sqc_test.cpp b/samples/sqc_test.cpp deleted file mode 100644 index 67377bf..0000000 --- a/samples/sqc_test.cpp +++ /dev/null @@ -1,111 +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. -*/ - -// Test program for SQC - -#define _USE_MATH_DEFINES -#include -#include -#include -#include - -#include "circuit/quantumcircuit.hpp" -#include "primitives/backend_sampler_v2.hpp" -#include "service/qiskit_runtime_service_sqc.hpp" -#include "compiler/transpiler.hpp" - -using namespace Qiskit; -using namespace Qiskit::circuit; -using namespace Qiskit::providers; -using namespace Qiskit::primitives; -using namespace Qiskit::service; -using namespace Qiskit::compiler; - -using Sampler = BackendSamplerV2; - -int main() -{ - int num_qubits = 10; - auto qreg = QuantumRegister(num_qubits); - auto creg = ClassicalRegister(num_qubits, std::string("meas")); - auto ctest = ClassicalRegister(num_qubits, std::string("test")); - QuantumCircuit circ(std::vector({qreg,}), std::vector({creg, ctest})); - - // test measure all - circ.measure(qreg, ctest); - - // GHZ circuit - circ.h(0); - for (int i = 0; i < num_qubits - 1; i++) - { - circ.cx(i, i + 1); - } - circ.measure(qreg, creg); - - auto service = QiskitRuntimeService(); - auto backend = service.backend(); - auto sampler = Sampler(backend, 100); - - auto transpiled_circ = transpile(circ, backend); - - auto job = sampler.run({SamplerPub(transpiled_circ)}); - if (job == nullptr) - return -1; - auto result = job->result(); - - auto pub_result = result[0]; - auto meas_bits = pub_result.data("meas"); - auto bits = meas_bits.get_bitstrings(); - std::cout << " ===== samples for pub[0] =====" << std::endl; - for (auto b : bits) - { - std::cout << b << ", "; - } - std::cout << std::endl; - - std::cout << " --- test bits ---" << std::endl; - auto test_bits = pub_result.data("test"); - bits = test_bits.get_bitstrings(); - for (auto b : bits) - { - std::cout << b << ", "; - } - std::cout << std::endl; - - std::cout << " ===== counts for pub[0] =====" << std::endl; - auto count = meas_bits.get_counts(); - for (auto c : count) - { - std::cout << c.first << " : " << c.second << std::endl; - } - - - auto bitcounts = test_bits.bitcount(); - reg_t zero_index; - zero_index.reserve(bitcounts.size()); - for (uint_t i = 0; i < bitcounts.size(); i++) { - if (bitcounts[i] == 0) { - zero_index.push_back(i); - } - } - - std::cout << " ===== counts for pub[0] whose test bit are 0 =====" << std::endl; - count = meas_bits.get_counts(zero_index); - for (auto c : count) - { - std::cout << c.first << " : " << c.second << std::endl; - } - - return 0; -} diff --git a/src/service/qiskit_runtime_service.hpp b/src/service/qiskit_runtime_service.hpp index 185b85c..94045d4 100644 --- a/src/service/qiskit_runtime_service.hpp +++ b/src/service/qiskit_runtime_service.hpp @@ -16,6 +16,8 @@ #ifdef QRMI_ROOT #include "service/qiskit_runtime_service qrmi.hpp" +#elif defined(SQC_ROOT) +#include "service/qiskit_runtime_service_sqc.hpp" #else // otherwise use Qiskit IBM runtime C-API #ifndef __qiskitcpp_providers_qiskit_runtime_service_def_hpp__ From 24c76cd0264abed91f43a998183a382a457c302a Mon Sep 17 00:00:00 2001 From: Ryo Wakizaka Date: Thu, 4 Dec 2025 18:29:22 +0900 Subject: [PATCH 16/26] Add backend name for consistency --- src/service/qiskit_runtime_service_sqc.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/service/qiskit_runtime_service_sqc.hpp b/src/service/qiskit_runtime_service_sqc.hpp index 6ab9ebb..e2f6d44 100644 --- a/src/service/qiskit_runtime_service_sqc.hpp +++ b/src/service/qiskit_runtime_service_sqc.hpp @@ -28,7 +28,7 @@ class QiskitRuntimeService { public: /// @brief Create a new runtime service class - QiskitRuntimeService() + QiskitRuntimeService(const std::string) : init_options_(NULL) { init_options_ = sqcMallocInitOptions(); From e8e5ddb70d931004a842d61f3c58b390b647bc70 Mon Sep 17 00:00:00 2001 From: Ryo Wakizaka Date: Thu, 4 Dec 2025 18:31:33 +0900 Subject: [PATCH 17/26] Fix --- src/service/qiskit_runtime_service_sqc.hpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/service/qiskit_runtime_service_sqc.hpp b/src/service/qiskit_runtime_service_sqc.hpp index e2f6d44..df93c7f 100644 --- a/src/service/qiskit_runtime_service_sqc.hpp +++ b/src/service/qiskit_runtime_service_sqc.hpp @@ -28,7 +28,7 @@ class QiskitRuntimeService { public: /// @brief Create a new runtime service class - QiskitRuntimeService(const std::string) + QiskitRuntimeService() : init_options_(NULL) { init_options_ = sqcMallocInitOptions(); @@ -44,11 +44,12 @@ class QiskitRuntimeService { sqcFreeInitOptions(init_options_); } - /// @brief create a new backend object - /// @return a new QkrtBackend class - Qiskit::providers::SQCBackend backend() + /// @brief Create a new backend object + /// @param name the name of the backend resource + /// @return A new QkrtBackend class + Qiskit::providers::SQCBackend backend(std::string name) { - return Qiskit::providers::SQCBackend(); + return Qiskit::providers::SQCBackend(name); } }; From 3950402d6af4c607e3e2a0c0d5b50b2b692b6cf5 Mon Sep 17 00:00:00 2001 From: Ryo Wakizaka Date: Thu, 4 Dec 2025 18:44:24 +0900 Subject: [PATCH 18/26] Update README --- README.md | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e66f2c5..44dd22d 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,8 @@ $ cmake .. $ make ``` +If you want to use [SQC C API](https://github.com/jhpc-quantum/SQC), follow the SQC documentation. + ### Building Qiskit C++ Qiskit C++ only has C++ header files. There is nothing to do to build the SDK. @@ -93,9 +95,9 @@ $ cmake -DQISKIT_ROOT=Path_to_qiskit .. $ make ``` -If you want to build sampler or transpiler example, you will need one of qiskit-ibm-runtime C or QRMI. +If you want to build sampler or transpiler example, you will need one of qiskit-ibm-runtime C or QRMI or SQC. -Then example can be built by setting `QISKIT_IBM_RUNTIME_C_ROOT` or `QRMI_ROOT` to cmake. +Then example can be built by setting `QISKIT_IBM_RUNTIME_C_ROOT` or `QRMI_ROOT` or `SQC_ROOT` to cmake. ```shell-session $ cd samples @@ -105,6 +107,18 @@ $ cmake -DQISKIT_ROOT=Path_to_qiskit -DQISKIT_IBM_RUNTIME_C_ROOT="path to qiskit $ make ``` +If you use SQC, you also need to set `SQC_LINK_OPTIONS`. + +```shell-session +$ cmake -DQISKIT_ROOT=Path_to_qiskit -DSQC_ROOT="path to SQC" -DSQC_LINK_OPTIONS="SQC link options" .. +``` + +The format of `SQC_LINK_OPTIONS` is assumued to be as follows, for example. For required options, please refer the the SQC documentation. + +``` +"-lsqc_api -lsqc_rpc ... -pthread" +``` + To run sampler example, set your account information in `$HOME/.qiskit/qiskit-ibm.json` (see https://github.com/Qiskit/qiskit-ibm-runtime?tab=readme-ov-file#save-your-account-on-disk) or setting following environment variables to access Quantum hardware. ``` From 9acc91584dc0e292b2d201abb0253ca64b89ac68 Mon Sep 17 00:00:00 2001 From: Ryo Wakizaka Date: Tue, 9 Dec 2025 17:05:19 +0900 Subject: [PATCH 19/26] Fix bugs --- src/providers/sqc_backend.hpp | 64 +++++++++++++++-------------------- 1 file changed, 28 insertions(+), 36 deletions(-) diff --git a/src/providers/sqc_backend.hpp b/src/providers/sqc_backend.hpp index fee8a1e..2bc866f 100644 --- a/src/providers/sqc_backend.hpp +++ b/src/providers/sqc_backend.hpp @@ -31,11 +31,10 @@ namespace Qiskit { namespace providers { /// @brief Convert a qiskit quantum circuit to a SQC circuit. -/// @param A SQC circuit where a result is stored /// @param An original qiskit circuit -/// @note This function destroys the original SQC circuit data. +/// @return a SQC circuit equivalent to the given qiskit circuit /// @note Currently parameterized circuits are not supported. -bool qk_circ_to_sqc_circ(sqcQC* qc_handle, circuit::QuantumCircuit& qk_circ); +std::shared_ptr qk_circ_to_sqc_circ(circuit::QuantumCircuit& qk_circ); /// @class SQCBackend /// @brief Backend class using SQC. @@ -82,7 +81,7 @@ class SQCBackend : public BackendV2 { nlohmann::ordered_json target_json; target_json["configuration"] = nlohmann::ordered_json::parse(qc_handle->backend_config_json); target_json["properties"] = nlohmann::ordered_json::parse(qc_handle->backend_props_json); - auto target = std::shared_ptr(); + auto target = std::make_shared(); if(!target->from_json(target_json)) { std::cerr << "Failed to create a target from json files" << std::endl; return nullptr; @@ -102,13 +101,13 @@ class SQCBackend : public BackendV2 { // Create a sqcQC from a qiskit circuit const uint_t qasm_len = qasm3_str.size() + 500; - std::unique_ptr sqc_circ(sqcQuantumCircuit(0), &sqcDestroyQuantumCircuit); - sqc_circ->qasm = (char*)malloc(qasm_len); - if(!qk_circ_to_sqc_circ(sqc_circ.get(), circuit)) + auto sqc_circ = qk_circ_to_sqc_circ(circuit); + if(!sqc_circ) { std::cerr << "Error: Failed to convert a given qiskit circuit to a SQC circuit." << std::endl; return nullptr; } + sqc_circ->qasm = (char*)malloc(qasm_len); sqcConvQASMtoMemory(sqc_circ.get(), backend_type_, sqc_circ->qasm, qasm_len); std::unique_ptr run_options(new sqcRunOptions); @@ -133,22 +132,15 @@ class SQCBackend : public BackendV2 { }; -bool qk_circ_to_sqc_circ(sqcQC* qc_handle, circuit::QuantumCircuit& qk_circ) +std::shared_ptr qk_circ_to_sqc_circ(circuit::QuantumCircuit& qk_circ) { - if(qc_handle == NULL) - { - std::cerr << "Error: Given SQC handle is null." << std::endl; - return false; - } if(qk_circ.num_instructions() > MAX_N_GATES) { std::cerr << "Error: The number of a given circuit exceeds the limit of SQC." << std::endl; return false; } - qc_handle->qubits = static_cast(qk_circ.num_qubits()); - qc_handle->ngates = static_cast(qk_circ.num_instructions()); - + auto sqc_circ = std::shared_ptr(sqcQuantumCircuit(circuit.num_qubits()), sqcDestroyQuantumCircuit); for(int i = 0; i < static_cast(qk_circ.num_instructions()); ++i) { const auto circ_instr = qk_circ[i]; const auto& instr_name = circ_instr.instruction().name(); @@ -157,94 +149,94 @@ bool qk_circ_to_sqc_circ(sqcQC* qc_handle, circuit::QuantumCircuit& qk_circ) if(instr_name == "measure") { - sqcMeasure(qc_handle, qubits[0], clbits[0], NULL); + sqcMeasure(sqc_circ, qubits[0], clbits[0], NULL); } else if(instr_name == "h") { - sqcHGate(qc_handle, qubits[0]); + sqcHGate(sqc_circ, qubits[0]); } else if(instr_name == "cx") { - sqcCXGate(qc_handle, qubits[0], qubits[1]); + sqcCXGate(sqc_circ, qubits[0], qubits[1]); } else if(instr_name == "cz") { - sqcCXGate(qc_handle, qubits[0], qubits[1]); + sqcCZGate(sqc_circ, qubits[0], qubits[1]); } else if(instr_name == "rz") { - sqcRZGate(qc_handle, qubits[0], qubits[1]); + sqcRZGate(sqc_circ, qubits[0], qubits[1]); } else if(instr_name == "s") { - sqcSGate(qc_handle, qubits[0]); + sqcSGate(sqc_circ, qubits[0]); } else if(instr_name == "sdg") { - sqcSdgGate(qc_handle, qubits[0]); + sqcSdgGate(sqc_circ, qubits[0]); } else if(instr_name == "rx") { const auto& instr = circ_instr.instruction(); assert(instr.params().size() == 1); - sqcRXGate(qc_handle, instr.params()[0], qubits[0]); + sqcRXGate(sqc_circ, instr.params()[0], qubits[0]); } else if(instr_name == "ry") { const auto& instr = circ_instr.instruction(); assert(instr.params().size() == 1); - sqcRZGate(qc_handle, instr.params()[0], qubits[0]); + sqcRYGate(sqc_circ, instr.params()[0], qubits[0]); } else if(instr_name == "x") { - sqcXGate(qc_handle, qubits[0]); + sqcXGate(sqc_circ, qubits[0]); } else if(instr_name == "z") { - sqcZGate(qc_handle, qubits[0]); + sqcZGate(sqc_circ, qubits[0]); } else if(instr_name == "p") { const auto& instr = circ_instr.instruction(); - sqcU1Gate(qc_handle, instr.params()[0], qubits[0]); + sqcU1Gate(sqc_circ, instr.params()[0], qubits[0]); } else if(instr_name == "reset") { - sqcReset(qc_handle, qubits[0]); + sqcReset(sqc_circ, qubits[0]); } else if(instr_name == "barrier") { for(auto qubit : qubits) { - sqcBarrier(qc_handle, qubit); + sqcBarrier(sqc_circ, qubit); } } else if(instr_name == "ecr") { - sqcECRGate(qc_handle, qubits[0], qubits[1]); + sqcECRGate(sqc_circ, qubits[0], qubits[1]); } else if(instr_name == "sx") { - sqcSXGate(qc_handle, qubits[0]); + sqcSXGate(sqc_circ, qubits[0]); } else if(instr_name == "id") { - sqcIDGate(qc_handle, qubits[0]); + sqcIDGate(sqc_circ, qubits[0]); } else if(instr_name == "delay") { // TODO std::cerr << "Error (WIP): The delay operation is not support now." << std::endl; - return false; + return nullptr; } else { std::cerr << "Error: An instruction " << instr_name << " is not supported in SQC." << std::endl; - return false; + return nullptr; } } - return true; + return sqc_circ; } From 953a989385609a6f5b05a2074b8832454223d797 Mon Sep 17 00:00:00 2001 From: Ryo Wakizaka Date: Tue, 9 Dec 2025 17:09:39 +0900 Subject: [PATCH 20/26] Fix type error --- src/providers/sqc_backend.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/providers/sqc_backend.hpp b/src/providers/sqc_backend.hpp index 2bc866f..0bbd418 100644 --- a/src/providers/sqc_backend.hpp +++ b/src/providers/sqc_backend.hpp @@ -137,7 +137,7 @@ std::shared_ptr qk_circ_to_sqc_circ(circuit::QuantumCircuit& qk_circ) if(qk_circ.num_instructions() > MAX_N_GATES) { std::cerr << "Error: The number of a given circuit exceeds the limit of SQC." << std::endl; - return false; + return nullptr; } auto sqc_circ = std::shared_ptr(sqcQuantumCircuit(circuit.num_qubits()), sqcDestroyQuantumCircuit); From a3e93cf3f1e83b983a6e8caaf69281e2e60f70e2 Mon Sep 17 00:00:00 2001 From: Ryo Wakizaka Date: Tue, 9 Dec 2025 17:16:03 +0900 Subject: [PATCH 21/26] Fix --- src/providers/sqc_backend.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/providers/sqc_backend.hpp b/src/providers/sqc_backend.hpp index 0bbd418..d1e7191 100644 --- a/src/providers/sqc_backend.hpp +++ b/src/providers/sqc_backend.hpp @@ -140,7 +140,7 @@ std::shared_ptr qk_circ_to_sqc_circ(circuit::QuantumCircuit& qk_circ) return nullptr; } - auto sqc_circ = std::shared_ptr(sqcQuantumCircuit(circuit.num_qubits()), sqcDestroyQuantumCircuit); + std::shared_ptr sqc_circ(sqcQuantumCircuit(qk_circ.num_qubits()), sqcDestroyQuantumCircuit); for(int i = 0; i < static_cast(qk_circ.num_instructions()); ++i) { const auto circ_instr = qk_circ[i]; const auto& instr_name = circ_instr.instruction().name(); From d604c1074253b28af4775f51ff4a9f64c790af58 Mon Sep 17 00:00:00 2001 From: Ryo Wakizaka Date: Tue, 9 Dec 2025 17:29:24 +0900 Subject: [PATCH 22/26] Fix pointer types --- src/providers/sqc_backend.hpp | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/providers/sqc_backend.hpp b/src/providers/sqc_backend.hpp index d1e7191..5d90373 100644 --- a/src/providers/sqc_backend.hpp +++ b/src/providers/sqc_backend.hpp @@ -149,79 +149,79 @@ std::shared_ptr qk_circ_to_sqc_circ(circuit::QuantumCircuit& qk_circ) if(instr_name == "measure") { - sqcMeasure(sqc_circ, qubits[0], clbits[0], NULL); + sqcMeasure(sqc_circ.get(), qubits[0], clbits[0], NULL); } else if(instr_name == "h") { - sqcHGate(sqc_circ, qubits[0]); + sqcHGate(sqc_circ.get(), qubits[0]); } else if(instr_name == "cx") { - sqcCXGate(sqc_circ, qubits[0], qubits[1]); + sqcCXGate(sqc_circ.get(), qubits[0], qubits[1]); } else if(instr_name == "cz") { - sqcCZGate(sqc_circ, qubits[0], qubits[1]); + sqcCZGate(sqc_circ.get(), qubits[0], qubits[1]); } else if(instr_name == "rz") { - sqcRZGate(sqc_circ, qubits[0], qubits[1]); + sqcRZGate(sqc_circ.get(), qubits[0], qubits[1]); } else if(instr_name == "s") { - sqcSGate(sqc_circ, qubits[0]); + sqcSGate(sqc_circ.get(), qubits[0]); } else if(instr_name == "sdg") { - sqcSdgGate(sqc_circ, qubits[0]); + sqcSdgGate(sqc_circ.get(), qubits[0]); } else if(instr_name == "rx") { const auto& instr = circ_instr.instruction(); assert(instr.params().size() == 1); - sqcRXGate(sqc_circ, instr.params()[0], qubits[0]); + sqcRXGate(sqc_circ.get(), instr.params()[0], qubits[0]); } else if(instr_name == "ry") { const auto& instr = circ_instr.instruction(); assert(instr.params().size() == 1); - sqcRYGate(sqc_circ, instr.params()[0], qubits[0]); + sqcRYGate(sqc_circ.get(), instr.params()[0], qubits[0]); } else if(instr_name == "x") { - sqcXGate(sqc_circ, qubits[0]); + sqcXGate(sqc_circ.get(), qubits[0]); } else if(instr_name == "z") { - sqcZGate(sqc_circ, qubits[0]); + sqcZGate(sqc_circ.get(), qubits[0]); } else if(instr_name == "p") { const auto& instr = circ_instr.instruction(); - sqcU1Gate(sqc_circ, instr.params()[0], qubits[0]); + sqcU1Gate(sqc_circ.get(), instr.params()[0], qubits[0]); } else if(instr_name == "reset") { - sqcReset(sqc_circ, qubits[0]); + sqcReset(sqc_circ.get(), qubits[0]); } else if(instr_name == "barrier") { for(auto qubit : qubits) { - sqcBarrier(sqc_circ, qubit); + sqcBarrier(sqc_circ.get(), qubit); } } else if(instr_name == "ecr") { - sqcECRGate(sqc_circ, qubits[0], qubits[1]); + sqcECRGate(sqc_circ.get(), qubits[0], qubits[1]); } else if(instr_name == "sx") { - sqcSXGate(sqc_circ, qubits[0]); + sqcSXGate(sqc_circ.get(), qubits[0]); } else if(instr_name == "id") { - sqcIDGate(sqc_circ, qubits[0]); + sqcIDGate(sqc_circ.get(), qubits[0]); } else if(instr_name == "delay") { From 6b2c0192a3e4e0c6178abd7224fdc4d607a634c5 Mon Sep 17 00:00:00 2001 From: Ryo Wakizaka Date: Wed, 10 Dec 2025 16:18:39 +0900 Subject: [PATCH 23/26] Set qasm data directly --- src/providers/sqc_backend.hpp | 127 +--------------------------------- 1 file changed, 2 insertions(+), 125 deletions(-) diff --git a/src/providers/sqc_backend.hpp b/src/providers/sqc_backend.hpp index 5d90373..04d9b74 100644 --- a/src/providers/sqc_backend.hpp +++ b/src/providers/sqc_backend.hpp @@ -30,11 +30,6 @@ namespace Qiskit { namespace providers { -/// @brief Convert a qiskit quantum circuit to a SQC circuit. -/// @param An original qiskit circuit -/// @return a SQC circuit equivalent to the given qiskit circuit -/// @note Currently parameterized circuits are not supported. -std::shared_ptr qk_circ_to_sqc_circ(circuit::QuantumCircuit& qk_circ); /// @class SQCBackend /// @brief Backend class using SQC. @@ -99,16 +94,8 @@ class SQCBackend : public BackendV2 { const auto qasm3_str = circuit.to_qasm3(); std::cout << "run qasm3: \n" << qasm3_str << std::endl; - // Create a sqcQC from a qiskit circuit - const uint_t qasm_len = qasm3_str.size() + 500; - auto sqc_circ = qk_circ_to_sqc_circ(circuit); - if(!sqc_circ) - { - std::cerr << "Error: Failed to convert a given qiskit circuit to a SQC circuit." << std::endl; - return nullptr; - } - sqc_circ->qasm = (char*)malloc(qasm_len); - sqcConvQASMtoMemory(sqc_circ.get(), backend_type_, sqc_circ->qasm, qasm_len); + std::shared_ptr sqc_circ(sqcQuantumCircuit(circuit.num_qubits()), sqcDestroyQuantumCircuit); + sqc_circ->qasm = strdup(qasm3_str.c_str()); std::unique_ptr run_options(new sqcRunOptions); sqcInitializeRunOpt(run_options.get()); @@ -132,118 +119,8 @@ class SQCBackend : public BackendV2 { }; -std::shared_ptr qk_circ_to_sqc_circ(circuit::QuantumCircuit& qk_circ) -{ - if(qk_circ.num_instructions() > MAX_N_GATES) - { - std::cerr << "Error: The number of a given circuit exceeds the limit of SQC." << std::endl; - return nullptr; - } - - std::shared_ptr sqc_circ(sqcQuantumCircuit(qk_circ.num_qubits()), sqcDestroyQuantumCircuit); - for(int i = 0; i < static_cast(qk_circ.num_instructions()); ++i) { - const auto circ_instr = qk_circ[i]; - const auto& instr_name = circ_instr.instruction().name(); - const auto& qubits = circ_instr.qubits(); - const auto& clbits = circ_instr.clbits(); - - if(instr_name == "measure") - { - sqcMeasure(sqc_circ.get(), qubits[0], clbits[0], NULL); - } - else if(instr_name == "h") - { - sqcHGate(sqc_circ.get(), qubits[0]); - } - else if(instr_name == "cx") - { - sqcCXGate(sqc_circ.get(), qubits[0], qubits[1]); - } - else if(instr_name == "cz") - { - sqcCZGate(sqc_circ.get(), qubits[0], qubits[1]); - } - else if(instr_name == "rz") - { - sqcRZGate(sqc_circ.get(), qubits[0], qubits[1]); - } - else if(instr_name == "s") - { - sqcSGate(sqc_circ.get(), qubits[0]); - } - else if(instr_name == "sdg") - { - sqcSdgGate(sqc_circ.get(), qubits[0]); - } - else if(instr_name == "rx") - { - const auto& instr = circ_instr.instruction(); - assert(instr.params().size() == 1); - sqcRXGate(sqc_circ.get(), instr.params()[0], qubits[0]); - } - else if(instr_name == "ry") - { - const auto& instr = circ_instr.instruction(); - assert(instr.params().size() == 1); - sqcRYGate(sqc_circ.get(), instr.params()[0], qubits[0]); - } - else if(instr_name == "x") - { - sqcXGate(sqc_circ.get(), qubits[0]); - } - else if(instr_name == "z") - { - sqcZGate(sqc_circ.get(), qubits[0]); - } - else if(instr_name == "p") - { - const auto& instr = circ_instr.instruction(); - sqcU1Gate(sqc_circ.get(), instr.params()[0], qubits[0]); - } - else if(instr_name == "reset") - { - sqcReset(sqc_circ.get(), qubits[0]); - } - else if(instr_name == "barrier") - { - for(auto qubit : qubits) - { - sqcBarrier(sqc_circ.get(), qubit); - } - } - else if(instr_name == "ecr") - { - sqcECRGate(sqc_circ.get(), qubits[0], qubits[1]); - } - else if(instr_name == "sx") - { - sqcSXGate(sqc_circ.get(), qubits[0]); - } - else if(instr_name == "id") - { - sqcIDGate(sqc_circ.get(), qubits[0]); - } - else if(instr_name == "delay") - { - // TODO - std::cerr << "Error (WIP): The delay operation is not support now." << std::endl; - return nullptr; - } - else - { - std::cerr << "Error: An instruction " << instr_name << " is not supported in SQC." << std::endl; - return nullptr; - } - } - - return sqc_circ; -} - - } // namespace providers } // namespace Qiskit #endif //__qiskitcpp_providers_SQC_backend_def_hpp__ - - From 95ecbca764357dd7af7819dec91d6941107d4d78 Mon Sep 17 00:00:00 2001 From: Ryo Wakizaka Date: Wed, 10 Dec 2025 17:05:27 +0900 Subject: [PATCH 24/26] Use SQC_LIBS in CMakeLists.txt --- README.md | 10 ++-------- samples/CMakeLists.txt | 6 +++--- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 44dd22d..a439bc0 100644 --- a/README.md +++ b/README.md @@ -103,17 +103,11 @@ Then example can be built by setting `QISKIT_IBM_RUNTIME_C_ROOT` or `QRMI_ROOT` $ cd samples $ mkdir build $ cd build -$ cmake -DQISKIT_ROOT=Path_to_qiskit -DQISKIT_IBM_RUNTIME_C_ROOT="path to qiskit-ibm-runtime C" or -DQRMI_ROOT="path to QRMI" .. +$ cmake -DQISKIT_ROOT=Path_to_qiskit -DQISKIT_IBM_RUNTIME_C_ROOT="path to qiskit-ibm-runtime C" or -DQRMI_ROOT="path to QRMI" or -DSQC_ROOT="path to SQC" .. $ make ``` -If you use SQC, you also need to set `SQC_LINK_OPTIONS`. - -```shell-session -$ cmake -DQISKIT_ROOT=Path_to_qiskit -DSQC_ROOT="path to SQC" -DSQC_LINK_OPTIONS="SQC link options" .. -``` - -The format of `SQC_LINK_OPTIONS` is assumued to be as follows, for example. For required options, please refer the the SQC documentation. +You also need to set the library options to the environment variable `SQC_LIBS` before cmake if you use SQC. The format of `SQC_LIBS` is assumued to be as follows, for example. For required options, please refer the the SQC documentation. ``` "-lsqc_api -lsqc_rpc ... -pthread" diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index 327f4f8..b69cb01 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -68,9 +68,9 @@ function(add_application APP_NAME CPP_FILE) elseif(SQC_ROOT) target_link_libraries(${APP_NAME} PRIVATE - "-L${QISKIT_ROOT}/dist/c/lib -L${SQC_ROOT}/lib -L${SQC_ROOT}/lib64 -Wl,-rpath ${QISKIT_ROOT}/dist/c/lib $ENV{SQC_LINK_OPTIONS}" qiskit nlohmann_json::nlohmann_json + "-L${QISKIT_ROOT}/dist/c/lib -L${SQC_ROOT}/lib -L${SQC_ROOT}/lib64 -Wl,-rpath ${QISKIT_ROOT}/dist/c/lib -Wl,-rpath ${SQC_ROOT}/lib -Wl,-rpath ${SQC_ROOT}/lib64" qiskit nlohmann_json::nlohmann_json $ENV{SQC_LIBS} ) - target_compile_options(${APP_NAME} PRIVATE "-DSQC_ROOT=${SQC_ROOT} -DSQC_LINK_OPTIONS=${SQC_LINK_OPTIONS}") + target_compile_options(${APP_NAME} PRIVATE "-DSQC_ROOT=${SQC_ROOT}") else() target_link_libraries(${APP_NAME} PRIVATE @@ -102,7 +102,7 @@ endfunction() add_application(circuit_test circuit_test.cpp) add_application(observable_test observable_test.cpp) -if(QRMI_ROOT OR QISKIT_IBM_RUNTIME_C_ROOT OR (SQC_ROOT AND SQC_LINK_OPTIONS)) +if(QRMI_ROOT OR QISKIT_IBM_RUNTIME_C_ROOT OR SQC_ROOT) add_application(sampler_test sampler_test.cpp) add_application(transpile_test transpile_test.cpp) endif() From d30888f1939163e2a3c39fefabce7517855032ce Mon Sep 17 00:00:00 2001 From: Ryo Wakizaka Date: Wed, 10 Dec 2025 17:18:41 +0900 Subject: [PATCH 25/26] Use malloc instead of new --- src/providers/sqc_backend.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/providers/sqc_backend.hpp b/src/providers/sqc_backend.hpp index 04d9b74..2f1f556 100644 --- a/src/providers/sqc_backend.hpp +++ b/src/providers/sqc_backend.hpp @@ -103,7 +103,7 @@ class SQCBackend : public BackendV2 { run_options->qubits = sqc_circ->qubits; run_options->outFormat = SQC_OUT_RAW; // @TODO - std::shared_ptr result(new sqcOut, [](sqcOut* out) { sqcFreeOut(out, SQC_OUT_RAW); }); + std::shared_ptr result((sqcOut*)malloc(sizeof(sqcOut)), [](sqcOut* out) { sqcFreeOut(out, SQC_OUT_RAW); }); int error_code = sqcQCRun(sqc_circ.get(), backend_type_, *run_options, result.get()); if(error_code != SQC_RESULT_OK) From 2efb85c1e7b3638c70dae8a5ea76b88413a826ac Mon Sep 17 00:00:00 2001 From: Ryo Wakizaka Date: Fri, 12 Dec 2025 02:06:23 +0900 Subject: [PATCH 26/26] Fix the format of QASM3 for SQC --- src/providers/sqc_backend.hpp | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/providers/sqc_backend.hpp b/src/providers/sqc_backend.hpp index 2f1f556..6699186 100644 --- a/src/providers/sqc_backend.hpp +++ b/src/providers/sqc_backend.hpp @@ -18,6 +18,7 @@ #define __qiskitcpp_providers_SQC_backend_def_hpp__ #include +#include #include "utils/types.hpp" #include "transpiler/target.hpp" @@ -30,6 +31,7 @@ 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. @@ -94,6 +96,15 @@ class SQCBackend : public BackendV2 { const auto qasm3_str = circuit.to_qasm3(); std::cout << "run qasm3: \n" << qasm3_str << std::endl; + // special modification of QASM3 for SQC + std::string sqc_qasm3_str = qasm3_str; + static const std::regex re(R"(\r\n|\r|\n)"); + sqc_qasm3_str = std::regex_replace(sqc_qasm3_str, re, std::string("\\n")); + sqc_qasm3_str = replace_all(sqc_qasm3_str, "\"", "\\\""); + sqc_qasm3_str.insert(0, "\""); + sqc_qasm3_str.append("\""); + std::cout << "qasm3 for SQC: \n" << sqc_qasm3_str << std::endl; + std::shared_ptr sqc_circ(sqcQuantumCircuit(circuit.num_qubits()), sqcDestroyQuantumCircuit); sqc_circ->qasm = strdup(qasm3_str.c_str()); @@ -101,7 +112,7 @@ class SQCBackend : public BackendV2 { sqcInitializeRunOpt(run_options.get()); run_options->nshots = shots; run_options->qubits = sqc_circ->qubits; - run_options->outFormat = SQC_OUT_RAW; // @TODO + run_options->outFormat = SQC_OUT_RAW; // Currently SQC supports the raw format only std::shared_ptr result((sqcOut*)malloc(sizeof(sqcOut)), [](sqcOut* out) { sqcFreeOut(out, SQC_OUT_RAW); }); int error_code = sqcQCRun(sqc_circ.get(), backend_type_, *run_options, result.get()); @@ -119,6 +130,25 @@ class SQCBackend : public BackendV2 { }; +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(); + } + return out; +} + + } // namespace providers } // namespace Qiskit