Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -93,18 +95,24 @@ $ 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
$ 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
```

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"
```

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.

```
Expand Down
13 changes: 12 additions & 1 deletion samples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ function(add_application APP_NAME CPP_FILE)
PUBLIC
${QISKIT_ROOT}/target/release
${QRMI_ROOT}/target/release
${SQC_ROOT}/lib
${SQC_ROOT}/lib64
${QISKIT_IBM_RUNTIME_C_ROOT}/build/cargo/debug
)
if(QRMI_ROOT)
Expand All @@ -44,6 +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}")
#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}")
Expand All @@ -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}/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}")
else()
target_link_libraries(${APP_NAME}
PRIVATE
Expand All @@ -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}/include
${SAMPLES_PATH}
${CMAKE_CURRENT_SOURCE_DIR}/../src
nlohmann_json::nlohmann_json
Expand All @@ -91,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)
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()
126 changes: 126 additions & 0 deletions src/providers/sqc_backend.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/*
# 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 <memory>

#include "utils/types.hpp"
#include "transpiler/target.hpp"
#include "primitives/containers/sampler_pub.hpp"
#include "providers/sqc_job.hpp"

#include "sqc_ecode.h"
#include "sqc_api.h"

namespace Qiskit {
namespace providers {


/// @class SQCBackend
/// @brief Backend class using SQC.
class SQCBackend : public BackendV2 {
private:
const sqcBackend backend_type_;
std::shared_ptr<transpiler::Target> target_;

public:
/// @brief Create a new SQCBackend. Internally this initializes SQC.
SQCBackend()
: SQCBackend("unspecified")
{}

/// @brief Create a new SQCBackend object
/// @param backend_name a resource name for backend.
SQCBackend(const std::string name)
: BackendV2(name),
backend_type_(SQC_RPC_SCHED_QC_TYPE_IBM_DACC),
target_(nullptr)
{}

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)
std::shared_ptr<transpiler::Target> target(void) override
{
if(target_) return target_;

// Create a dummy circuit to get target json files
std::unique_ptr<sqcQC, decltype(&sqcDestroyQuantumCircuit)> 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::make_shared<transpiler::Target>();
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.
/// @return SQCJob
std::shared_ptr<providers::Job> run(std::vector<primitives::SamplerPub>& input_pubs, uint_t shots) override
{
auto circuit = input_pubs[0].circuit();
const auto qasm3_str = circuit.to_qasm3();
std::cout << "run qasm3: \n" << qasm3_str << std::endl;

std::shared_ptr<sqcQC> sqc_circ(sqcQuantumCircuit(circuit.num_qubits()), sqcDestroyQuantumCircuit);
sqc_circ->qasm = strdup(qasm3_str.c_str());

std::unique_ptr<sqcRunOptions> run_options(new sqcRunOptions);
sqcInitializeRunOpt(run_options.get());
run_options->nshots = shots;
run_options->qubits = sqc_circ->qubits;
run_options->outFormat = SQC_OUT_RAW; // @TODO

std::shared_ptr<sqcOut> 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)
{
std::cerr << "Error: Failed to run a SQC circuit." << std::endl;
return nullptr;
}

auto results_json = nlohmann::ordered_json::parse(result->result);

return std::make_shared<SQCJob>(results_json);
}
};


} // namespace providers
} // namespace Qiskit


#endif //__qiskitcpp_providers_SQC_backend_def_hpp__
104 changes: 104 additions & 0 deletions src/providers/sqc_job.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/*
# 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_hpp__
#define __qiskitcpp_providers_SQC_job_hpp__

#include <nlohmann/json.hpp>

#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 SQCBackend
SQCJob()
: SQCJob(std::string{""})
{}

/// @brief Create a new SQCBackend object
SQCJob(const std::string& job_id)
: 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_ = other.num_results_;
results_ = other.results_;
}

~SQCJob() {}

/// @brief Return the status of the job.
/// @return JobStatus enum.
providers::JobStatus status(void) override
{
/// @todo Wait SQC API for making the status request API public.
return providers::JobStatus::DONE;
}


/// @brief Return the number of results in this job
/// @return number of results
uint_t num_results(void) override
{
return num_results_;
}

/// @brief get sampler pub result
/// @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 (index >= num_results_)
return false;

result.from_json(results_["results"][index]);

return true;
}
};

} // namespace providers
} // namespace Qiskit


#endif //__qiskitcpp_providers_SQC_job_hpp__


2 changes: 2 additions & 0 deletions src/service/qiskit_runtime_service.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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__
Expand Down
59 changes: 59 additions & 0 deletions src/service/qiskit_runtime_service_sqc.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
# 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:
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()
{
sqcFinalize(init_options_);
sqcFreeInitOptions(init_options_);
}

/// @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(name);
}
};

} // namespace service
} // namespace Qiskit

#endif