Skip to content

Commit 8f420e7

Browse files
authored
Fix number of qubits in transpiled circuits (#113)
* fix append * Use target qubits for transpiled circuit * add definition of RZZ gate * remove rzz gate support from target * Fix hex string in bitarray * fix get_counts returns binary string
1 parent b953987 commit 8f420e7

10 files changed

Lines changed: 90 additions & 23 deletions

File tree

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ endfunction()
8282

8383
add_application(circuit_test tests/circuit_test.cpp)
8484
add_application(observable_test tests/observable_test.cpp)
85+
8586
if(QRMI_ROOT)
8687
add_application(sampler_test tests/sampler_test.cpp)
8788
add_application(transpile_test tests/transpile_test.cpp)

src/circuit/quantumcircuit_def.hpp

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "circuit/quantumregister.hpp"
2929
#include "circuit/library/standard_gates/standard_gates.hpp"
3030
#include "circuit/circuitinstruction.hpp"
31+
#include "transpiler/target.hpp"
3132

3233
#include <complex>
3334
#include "qiskit.h"
@@ -60,6 +61,7 @@ class QuantumCircuit {
6061
std::vector<ClassicalRegister> cregs_;
6162

6263
std::shared_ptr<rust_circuit> rust_circuit_ = nullptr;
64+
std::shared_ptr<transpiler::Target> target_ = nullptr;
6365

6466
std::shared_ptr<ControlFlowOp> pending_control_flow_op_ = nullptr;
6567
public:
@@ -96,11 +98,23 @@ class QuantumCircuit {
9698

9799
/// @brief Return number of qubits
98100
/// @return number of qubits
99-
uint_t num_qubits(void) const { return num_qubits_; }
101+
uint_t num_qubits(void) const
102+
{
103+
if (target_) {
104+
return target_->num_qubits();
105+
}
106+
return num_qubits_;
107+
}
100108

101109
/// @brief Return number of classical bits
102110
/// @return number of classical bits
103-
uint_t num_clbits(void) const { return num_clbits_; }
111+
uint_t num_clbits(void) const
112+
{
113+
if (target_) {
114+
return target_->num_qubits();
115+
}
116+
return num_clbits_;
117+
}
104118

105119
std::shared_ptr<rust_circuit> get_rust_circuit(const bool update = true)
106120
{
@@ -117,6 +131,11 @@ class QuantumCircuit {
117131
/// @param circ smart pointer to RUst circuit
118132
void from_rust_circuit(std::shared_ptr<rust_circuit> circ);
119133

134+
/// @brief set target to this circuit
135+
/// @param target smart pointer to target
136+
/// @details target is set for transpiled circuit
137+
void set_target(std::shared_ptr<transpiler::Target> target);
138+
120139
/// @brief set global phase
121140
/// @param phase global phase value
122141
void global_phase(const double phase);

src/circuit/quantumcircuit_impl.hpp

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ QuantumCircuit::QuantumCircuit(const QuantumCircuit& circ)
127127
cregs_ = circ.cregs_;
128128

129129
rust_circuit_ = circ.rust_circuit_;
130+
target_ = circ.target_;
130131
}
131132

132133
QuantumCircuit QuantumCircuit::copy(void)
@@ -141,6 +142,8 @@ QuantumCircuit QuantumCircuit::copy(void)
141142
copied.qregs_ = qregs_;
142143
copied.cregs_ = cregs_;
143144

145+
copied.target_ = target_;
146+
144147
return copied;
145148
}
146149

@@ -169,8 +172,17 @@ QuantumCircuit::~QuantumCircuit()
169172
if (rust_circuit_){
170173
rust_circuit_.reset();
171174
}
175+
if (target_) {
176+
target_.reset();
177+
}
178+
}
179+
180+
void QuantumCircuit::set_target(std::shared_ptr<transpiler::Target> target)
181+
{
182+
target_ = target;
172183
}
173184

185+
174186
void QuantumCircuit::get_qubits(reg_t& bits)
175187
{
176188
bits.clear();
@@ -1254,6 +1266,13 @@ std::string QuantumCircuit::to_qasm3(void)
12541266
qasm3 << " h _gate_q_1;" << std::endl;
12551267
qasm3 << "}" << std::endl;
12561268
break;
1269+
case QkGate_RZZ:
1270+
qasm3 << "gate rzz(p0) _gate_q_0, _gate_q_1 {" << std::endl;
1271+
qasm3 << " cx _gate_q_0, _gate_q_1;" << std::endl;
1272+
qasm3 << " rz(p0) _gate_q_1;" << std::endl;
1273+
qasm3 << " cx _gate_q_0, _gate_q_1;" << std::endl;
1274+
qasm3 << "}" << std::endl;
1275+
break;
12571276
case QkGate_RCCX:
12581277
qasm3 << "gate rccx _gate_q_0, _gate_q_1, _gate_q_2 {" << std::endl;
12591278
qasm3 << " h _gate_q_2;" << std::endl;
@@ -1375,8 +1394,8 @@ std::string QuantumCircuit::to_qasm3(void)
13751394
// registers
13761395
std::string creg_name = "c";
13771396
std::string qreg_name = "q";
1378-
qasm3 << "bit[" << num_clbits_ << "] " << creg_name << ";" << std::endl;
1379-
qasm3 << "qubit[" << num_qubits_ << "] " << qreg_name << ";" << std::endl;
1397+
qasm3 << "bit[" << num_clbits() << "] " << creg_name << ";" << std::endl;
1398+
qasm3 << "qubit[" << num_qubits() << "] " << qreg_name << ";" << std::endl;
13801399

13811400
// save ops
13821401
uint_t nops;

src/compiler/transpiler.hpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ namespace compiler {
3434
circuit::QuantumCircuit transpile(circuit::QuantumCircuit& circ, providers::BackendV2& backend, int optimization_level = 2, double approximation_degree = 1.0, int seed_transpiler = -1)
3535
{
3636
auto target = backend.target();
37-
if (!target.is_set()) {
37+
if (target == nullptr) {
3838
return circ;
3939
}
4040

@@ -46,15 +46,18 @@ circuit::QuantumCircuit transpile(circuit::QuantumCircuit& circ, providers::Back
4646
QkTranspileResult result;
4747
char* error;
4848

49-
QkExitCode ret = qk_transpile(circ.get_rust_circuit().get(), target.rust_target(), &options, &result, &error);
49+
QkExitCode ret = qk_transpile(circ.get_rust_circuit().get(), target->rust_target(), &options, &result, &error);
5050
if (ret != QkExitCode_Success) {
5151
std::cerr << "transpile error (" << ret << ") : "<< error << std::endl;
52+
target.reset();
5253
return circ;
5354
}
5455
circuit::QuantumCircuit transpiled;
5556
transpiled.from_rust_circuit(std::shared_ptr<rust_circuit>(result.circuit, qk_circuit_free));
57+
transpiled.set_target(target);
5658

5759
qk_transpile_layout_free(result.layout);
60+
target.reset();
5861

5962
return transpiled;
6063
}

src/primitives/containers/bit_array.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ std::unordered_map<std::string, uint_t> BitArray::get_counts(void)
136136
{
137137
std::unordered_map<std::string, uint_t> ret;
138138
for (int_t i = 0; i < array_.size(); i++) {
139-
ret[array_[i].to_hex_string()]++;
139+
ret[array_[i].to_string()]++;
140140
}
141141
return ret;
142142
}

src/providers/backend.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ class BackendV2 {
6161

6262
/// @brief Return a target properties for this backend
6363
/// @return a target class
64-
virtual transpiler::Target target(void) = 0;
64+
virtual std::shared_ptr<transpiler::Target> target(void) = 0;
6565

6666
/// @brief Run and collect samples from each pub.
6767
/// @param pubs An iterable of pub-like objects.

src/providers/qrmi_backend.hpp

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ class QRMIBackend : public BackendV2 {
4444
std::string primitive_name_ = "sampler";
4545
std::string acc_token_;
4646
std::shared_ptr<QrmiQuantumResource> qrmi_ = nullptr;
47+
std::shared_ptr<transpiler::Target> target_ = nullptr;
4748
public:
4849
/// @brief Create a new QRMIBackend
4950
QRMIBackend() {}
@@ -66,18 +67,23 @@ class QRMIBackend : public BackendV2 {
6667

6768
/// @brief Return a target properties for this backend
6869
/// @return a target class
69-
transpiler::Target target(void) override
70+
std::shared_ptr<transpiler::Target> target(void) override
7071
{
72+
if (target_) {
73+
return target_;
74+
}
7175
transpiler::Target target;
7276

7377
char *target_str = NULL;
7478
QrmiReturnCode rc = qrmi_resource_target(qrmi_.get(), &target_str);
75-
if (rc == QRMI_RETURN_CODE_SUCCESS) {
76-
nlohmann::ordered_json json_target = nlohmann::ordered_json::parse(target_str);
77-
qrmi_string_free((char *)target_str);
78-
target.from_json(json_target);
79+
if (rc != QRMI_RETURN_CODE_SUCCESS) {
80+
return nullptr;
7981
}
80-
return target;
82+
nlohmann::ordered_json json_target = nlohmann::ordered_json::parse(target_str);
83+
qrmi_string_free((char *)target_str);
84+
target_ = std::make_shared<transpiler::Target>();
85+
target_->from_json(json_target);
86+
return target_;
8187
}
8288

8389
/// @brief Run and collect samples from each pub.
@@ -186,6 +192,7 @@ class QRMIBackend : public BackendV2 {
186192
qrmi_resource_task_stop(qrmi_.get(), job_id.c_str());
187193
return ret;
188194
}
195+
189196
};
190197

191198
} // namespace providers

src/transpiler/target.hpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ class Target {
5151
qk_target_free(target_);
5252
}
5353
}
54-
const bool is_set(void) const
54+
bool is_set(void) const
5555
{
5656
return is_set_;
5757
}
@@ -67,6 +67,13 @@ class Target {
6767
return backend_name_;
6868
}
6969

70+
/// @brief number of qubits
71+
/// @return number of qubits
72+
uint_t num_qubits(void) const
73+
{
74+
return num_qubits_;
75+
}
76+
7077
/// @brief basis gates for this target
7178
/// @return a list of basis gates in string
7279
const std::vector<std::string>& basis_gates(void) const
@@ -116,6 +123,11 @@ bool Target::from_json(nlohmann::ordered_json& input)
116123
std::unordered_map<std::string, QkTargetEntry*> property_map;
117124
for (auto& prop : backend_properties["gates"]) {
118125
std::string gate = prop["gate"];
126+
if (gate == "rzz") {
127+
// TODO: Add RZZ support when we have angle wrapping in
128+
// Qiskit's target and C transpiler.
129+
continue;
130+
}
119131
std::vector<uint32_t> qubits = prop["qubits"];
120132
double duration = 0.0;
121133
double error = 0.0;

src/utils/bitvector.hpp

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ void BitVector::from_hex_string(const std::string &src, const uint_t base) {
170170
}
171171
allocate(size*4, base);
172172

173-
for (int_t i = 0; i < src.size(); i++) {
173+
for (int_t i = 0; i < size; i++) {
174174
char c = src[src.size() - 1 - i];
175175
uint_t h = 0;
176176
if (c >= '0' && c <= '9') {
@@ -180,8 +180,8 @@ void BitVector::from_hex_string(const std::string &src, const uint_t base) {
180180
} else if(c >= 'A' && c <= 'F') {
181181
h = (uint_t)(c - 'A') + 10;
182182
}
183-
uint_t pos = i % (REG_SIZE >> 4);
184-
bits_[i / (REG_SIZE >> 4)] |= (h << (pos << 4));
183+
uint_t pos = i % (REG_SIZE >> 2);
184+
bits_[i / (REG_SIZE >> 2)] |= (h << (pos << 2));
185185
}
186186
}
187187

@@ -229,14 +229,19 @@ std::string BitVector::to_string(void) {
229229
}
230230

231231
std::string BitVector::to_hex_string(void) {
232+
uint_t size = size_/4;
232233
std::string str = "0x";
233-
for (uint_t i = 0; i < size_/4; i++) {
234-
uint_t pos = i % (REG_SIZE >> 4);
235-
uint_t val = (bits_[(size_/4 - 1 - i) / (REG_SIZE >> 4)] >> (pos << 4)) & 0xf;
234+
for (uint_t i = 0; i < size; i++) {
235+
str += '0';
236+
}
237+
for (uint_t i = 0; i < size; i++) {
238+
uint_t pos = i % (REG_SIZE >> 2);
239+
uint_t val = (bits_[i / (REG_SIZE >> 2)] >> (pos << 2)) & 15;
240+
236241
if (val < 10) {
237-
str += ('0' + val);
242+
str[str.size() - 1 - i] = ('0' + val);
238243
} else {
239-
str += ('a' + (val - 10));
244+
str[str.size() - 1 - i] = ('a' + (val - 10));
240245
}
241246
}
242247
return str;

tests/transpile_test.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ int main()
4444
for (int i=0;i<9;i++) {
4545
circ.cx(i, i+1);
4646
}
47+
circ.rzz(0.1, 0, 1);
4748
for (int i=0;i<10;i++) {
4849
circ.measure(i,i);
4950
}

0 commit comments

Comments
 (0)