|
| 1 | +/* |
| 2 | +# This code is part of Qiskit. |
| 3 | +# |
| 4 | +# (C) Copyright IBM 2025. |
| 5 | +# |
| 6 | +# This code is licensed under the Apache License, Version 2.0. You may |
| 7 | +# obtain a copy of this license in the LICENSE.txt file in the root directory |
| 8 | +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. |
| 9 | +# |
| 10 | +# Any modifications or derivative works of this code must retain this |
| 11 | +# copyright notice, and modified files need to carry a notice indicating |
| 12 | +# that they have been altered from the originals. |
| 13 | +*/ |
| 14 | + |
| 15 | +// SQC Backend |
| 16 | + |
| 17 | +#ifndef __qiskitcpp_providers_SQC_backend_def_hpp__ |
| 18 | +#define __qiskitcpp_providers_SQC_backend_def_hpp__ |
| 19 | + |
| 20 | +#include <memory> |
| 21 | +#include <regex> |
| 22 | + |
| 23 | +#include "utils/types.hpp" |
| 24 | +#include "transpiler/target.hpp" |
| 25 | +#include "primitives/containers/sampler_pub.hpp" |
| 26 | +#include "providers/sqc_job.hpp" |
| 27 | + |
| 28 | +#include "sqc_ecode.h" |
| 29 | +#include "sqc_api.h" |
| 30 | + |
| 31 | +namespace Qiskit { |
| 32 | +namespace providers { |
| 33 | + |
| 34 | +std::string replace_all(std::string s, const std::string& from, const std::string& to); |
| 35 | + |
| 36 | +/// @class SQCBackend |
| 37 | +/// @brief Backend class using SQC. |
| 38 | +class SQCBackend : public BackendV2 { |
| 39 | +private: |
| 40 | + const sqcBackend backend_type_; |
| 41 | + std::shared_ptr<transpiler::Target> target_; |
| 42 | + |
| 43 | +public: |
| 44 | + /// @brief Create a new SQCBackend. Internally this initializes SQC. |
| 45 | + SQCBackend() |
| 46 | + : SQCBackend("unspecified") |
| 47 | + {} |
| 48 | + |
| 49 | + /// @brief Create a new SQCBackend object |
| 50 | + /// @param backend_name a resource name for backend. |
| 51 | + SQCBackend(const std::string name) |
| 52 | + : BackendV2(name), |
| 53 | + backend_type_(SQC_RPC_SCHED_QC_TYPE_IBM_DACC), |
| 54 | + target_(nullptr) |
| 55 | + {} |
| 56 | + |
| 57 | + SQCBackend(const SQCBackend& other) |
| 58 | + : BackendV2(other.name_), |
| 59 | + backend_type_(other.backend_type_), |
| 60 | + target_(other.target_) |
| 61 | + {} |
| 62 | + |
| 63 | + ~SQCBackend() {} |
| 64 | + |
| 65 | + /// @brief Return a target properties for this backend. |
| 66 | + /// @return a target class (nullptr) |
| 67 | + std::shared_ptr<transpiler::Target> target(void) override |
| 68 | + { |
| 69 | + if(target_) return target_; |
| 70 | + |
| 71 | + // Create a dummy circuit to get target json files |
| 72 | + std::unique_ptr<sqcQC, decltype(&sqcDestroyQuantumCircuit)> qc_handle(sqcQuantumCircuit(0), &sqcDestroyQuantumCircuit); |
| 73 | + if(sqcIbmdTranspileInfo(qc_handle.get(), backend_type_) != SQC_RESULT_OK) { |
| 74 | + std::cerr << "Failed to get the target information" << std::endl; |
| 75 | + return nullptr; |
| 76 | + } |
| 77 | + |
| 78 | + nlohmann::ordered_json target_json; |
| 79 | + target_json["configuration"] = nlohmann::ordered_json::parse(qc_handle->backend_config_json); |
| 80 | + target_json["properties"] = nlohmann::ordered_json::parse(qc_handle->backend_props_json); |
| 81 | + auto target = std::make_shared<transpiler::Target>(); |
| 82 | + if(!target->from_json(target_json)) { |
| 83 | + std::cerr << "Failed to create a target from json files" << std::endl; |
| 84 | + return nullptr; |
| 85 | + } |
| 86 | + target_ = target; |
| 87 | + |
| 88 | + return target_; |
| 89 | + } |
| 90 | + |
| 91 | + /// @brief Run and collect samples from each pub. |
| 92 | + /// @return SQCJob |
| 93 | + std::shared_ptr<providers::Job> run(std::vector<primitives::SamplerPub>& input_pubs, uint_t shots) override |
| 94 | + { |
| 95 | + auto circuit = input_pubs[0].circuit(); |
| 96 | + const auto qasm3_str = circuit.to_qasm3(); |
| 97 | + std::cout << "run qasm3: \n" << qasm3_str << std::endl; |
| 98 | + |
| 99 | + // special modification of QASM3 for SQC |
| 100 | + std::string sqc_qasm3_str = qasm3_str; |
| 101 | + static const std::regex re(R"(\r\n|\r|\n)"); |
| 102 | + sqc_qasm3_str = std::regex_replace(sqc_qasm3_str, re, std::string("\\n")); |
| 103 | + sqc_qasm3_str = replace_all(sqc_qasm3_str, "\"", "\\\""); |
| 104 | + sqc_qasm3_str.insert(0, "\""); |
| 105 | + sqc_qasm3_str.append("\""); |
| 106 | + std::cout << "qasm3 for SQC: \n" << sqc_qasm3_str << std::endl; |
| 107 | + |
| 108 | + std::shared_ptr<sqcQC> sqc_circ(sqcQuantumCircuit(circuit.num_qubits()), sqcDestroyQuantumCircuit); |
| 109 | + sqc_circ->qasm = strdup(sqc_qasm3_str.c_str()); |
| 110 | + |
| 111 | + std::unique_ptr<sqcRunOptions> run_options(new sqcRunOptions); |
| 112 | + sqcInitializeRunOpt(run_options.get()); |
| 113 | + run_options->nshots = shots; |
| 114 | + run_options->qubits = sqc_circ->qubits; |
| 115 | + run_options->outFormat = SQC_OUT_RAW; // Currently SQC supports the raw format only |
| 116 | + |
| 117 | + std::shared_ptr<sqcOut> result((sqcOut*)malloc(sizeof(sqcOut)), [](sqcOut* out) { sqcFreeOut(out, SQC_OUT_RAW); }); |
| 118 | + int error_code = sqcQCRun(sqc_circ.get(), backend_type_, *run_options, result.get()); |
| 119 | + |
| 120 | + if(error_code != SQC_RESULT_OK) |
| 121 | + { |
| 122 | + std::cerr << "Error: Failed to run a SQC circuit." << std::endl; |
| 123 | + return nullptr; |
| 124 | + } |
| 125 | + |
| 126 | + auto results_json = nlohmann::ordered_json::parse(result->result); |
| 127 | + |
| 128 | + return std::make_shared<SQCJob>(results_json); |
| 129 | + } |
| 130 | +}; |
| 131 | + |
| 132 | + |
| 133 | +std::string replace_all(std::string s, const std::string& from, const std::string& to) { |
| 134 | + if (from.empty()) return s; |
| 135 | + std::string out; |
| 136 | + out.reserve(s.size()); |
| 137 | + std::size_t pos = 0; |
| 138 | + while (true) { |
| 139 | + std::size_t found = s.find(from, pos); |
| 140 | + if (found == std::string::npos) { |
| 141 | + out.append(s, pos, std::string::npos); |
| 142 | + break; |
| 143 | + } |
| 144 | + out.append(s, pos, found - pos); |
| 145 | + out.append(to); |
| 146 | + pos = found + from.size(); |
| 147 | + } |
| 148 | + return out; |
| 149 | +} |
| 150 | + |
| 151 | + |
| 152 | +} // namespace providers |
| 153 | +} // namespace Qiskit |
| 154 | + |
| 155 | + |
| 156 | +#endif //__qiskitcpp_providers_SQC_backend_def_hpp__ |
0 commit comments