Skip to content

Commit 1703a76

Browse files
authored
Add functions to handle multiple cregs and bitcounts (#120)
* Fix registers, add functions to get data by register name * add releasenote
1 parent edb7e19 commit 1703a76

File tree

11 files changed

+362
-43
lines changed

11 files changed

+362
-43
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
features:
3+
- |
4+
Sampler pub result can return separate `BitArray` for each classical registers.
5+
6+
`BitArray` adds new functions.
7+
`bitcount()` returns number of 1 bits in each bitstrings.
8+
`get_counts()` and `get_bitstrings()` can have a list of index which element should be included in the map of counts
9+
`get_bitstring` is renamed by `get_bitstrings`
10+

samples/sampler_test.cpp

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "service/qiskit_runtime_service.hpp"
2626
#include "compiler/transpiler.hpp"
2727

28+
using namespace Qiskit;
2829
using namespace Qiskit::circuit;
2930
using namespace Qiskit::providers;
3031
using namespace Qiskit::primitives;
@@ -36,18 +37,21 @@ using Sampler = BackendSamplerV2;
3637
int main()
3738
{
3839
int num_qubits = 10;
39-
QuantumCircuit circ(num_qubits, num_qubits);
40+
auto qreg = QuantumRegister(num_qubits);
41+
auto creg = ClassicalRegister(num_qubits, std::string("meas"));
42+
auto ctest = ClassicalRegister(num_qubits, std::string("test"));
43+
QuantumCircuit circ(std::vector<QuantumRegister>({qreg,}), std::vector<ClassicalRegister>({creg, ctest}));
44+
45+
// test measure all
46+
circ.measure(qreg, ctest);
4047

4148
// GHZ circuit
4249
circ.h(0);
4350
for (int i = 0; i < num_qubits - 1; i++)
4451
{
4552
circ.cx(i, i + 1);
4653
}
47-
for (int i = 0; i < num_qubits; i++)
48-
{
49-
circ.measure(i, i);
50-
}
54+
circ.measure(qreg, creg);
5155

5256
// set $HONE/.qiskit/qiskit-ibm.json
5357
// by using Qiskit IBM Runtime
@@ -57,7 +61,7 @@ int main()
5761
// QISKIT_IBM_TOKEN = "your API key"
5862
// QISKIT_IBM_INSTANCE = "your CRN"
5963
auto service = QiskitRuntimeService();
60-
auto backend = service.backend("ibm_torino");
64+
auto backend = service.backend("ibm_fez");
6165
auto sampler = Sampler(backend, 100);
6266

6367
auto transpiled_circ = transpile(circ, backend);
@@ -68,16 +72,43 @@ int main()
6872
auto result = job->result();
6973

7074
auto pub_result = result[0];
71-
auto hex = pub_result.data().get_hexstring();
75+
auto meas_bits = pub_result.data("meas");
76+
auto bits = meas_bits.get_bitstrings();
7277
std::cout << " ===== samples for pub[0] =====" << std::endl;
73-
for (auto h : hex)
78+
for (auto b : bits)
79+
{
80+
std::cout << b << ", ";
81+
}
82+
std::cout << std::endl;
83+
84+
std::cout << " --- test bits ---" << std::endl;
85+
auto test_bits = pub_result.data("test");
86+
bits = test_bits.get_bitstrings();
87+
for (auto b : bits)
7488
{
75-
std::cout << h << ", ";
89+
std::cout << b << ", ";
7690
}
7791
std::cout << std::endl;
7892

7993
std::cout << " ===== counts for pub[0] =====" << std::endl;
80-
auto count = pub_result.data().get_counts();
94+
auto count = meas_bits.get_counts();
95+
for (auto c : count)
96+
{
97+
std::cout << c.first << " : " << c.second << std::endl;
98+
}
99+
100+
101+
auto bitcounts = test_bits.bitcount();
102+
reg_t zero_index;
103+
zero_index.reserve(bitcounts.size());
104+
for (uint_t i = 0; i < bitcounts.size(); i++) {
105+
if (bitcounts[i] == 0) {
106+
zero_index.push_back(i);
107+
}
108+
}
109+
110+
std::cout << " ===== counts for pub[0] whose test bit are 0 =====" << std::endl;
111+
count = meas_bits.get_counts(zero_index);
81112
for (auto c : count)
82113
{
83114
std::cout << c.first << " : " << c.second << std::endl;

src/circuit/quantumcircuit_def.hpp

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ class QuantumCircuit
8888
/// @param qregs A list of QuantumRegister
8989
/// @param cregs A list of ClassicalRegister
9090
/// @param global_phase The global phase of the circuit, measured in radians
91-
QuantumCircuit(std::vector<QuantumRegister> &qregs, std::vector<ClassicalRegister> &cregs, const double global_phase = 0.0);
91+
QuantumCircuit(std::vector<QuantumRegister> qregs, std::vector<ClassicalRegister> cregs, const double global_phase = 0.0);
9292

9393
/// @brief Create a new reference to Quantum Circuit
9494
/// @details Copy constructor of QuantumCircuit does not copy the circuit,
@@ -122,6 +122,34 @@ class QuantumCircuit
122122
return num_clbits_;
123123
}
124124

125+
/// @brief Return number of qregs
126+
/// @return number of qregs
127+
uint_t num_qregs(void) const
128+
{
129+
return qregs_.size();
130+
}
131+
132+
/// @brief Return number of cregs
133+
/// @return number of cregs
134+
uint_t num_cregs(void) const
135+
{
136+
return cregs_.size();
137+
}
138+
139+
/// @brief Return a list of qregs
140+
/// @return reference to a list of qregs
141+
const std::vector<QuantumRegister>& qregs(void) const
142+
{
143+
return qregs_;
144+
}
145+
146+
/// @brief Return a list of cregs
147+
/// @return reference to a list of cregs
148+
const std::vector<ClassicalRegister>& cregs(void) const
149+
{
150+
return cregs_;
151+
}
152+
125153
std::shared_ptr<rust_circuit> get_rust_circuit(const bool update = true)
126154
{
127155
if (update)
@@ -133,9 +161,10 @@ class QuantumCircuit
133161
/// @return copied circuit
134162
QuantumCircuit copy(void);
135163

136-
/// @brief set circuit reference of Rust's circuit
164+
/// @brief set circuit reference of Qiskit circuit
137165
/// @param circ smart pointer to RUst circuit
138-
void from_rust_circuit(std::shared_ptr<rust_circuit> circ, const std::vector<uint32_t> &map);
166+
/// @param map layout mapping
167+
void set_qiskit_circuit(std::shared_ptr<rust_circuit> circ, const std::vector<uint32_t> &map);
139168

140169
/// @brief set target to this circuit
141170
/// @param target smart pointer to target

src/circuit/quantumcircuit_impl.hpp

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ QuantumCircuit::QuantumCircuit(const uint_t num_qubits, const uint_t num_clbits,
4747
qregs_[0] = qr;
4848
cregs_[0] = cr;
4949

50-
rust_circuit_ = std::shared_ptr<rust_circuit>(qk_circuit_new((std::uint32_t)num_qubits_, (std::uint32_t)num_clbits_), qk_circuit_free);
50+
rust_circuit_ = std::shared_ptr<rust_circuit>(qk_circuit_new(0, 0), qk_circuit_free);
5151
qk_circuit_add_quantum_register(rust_circuit_.get(), qregs_[0].get_register().get());
5252
qk_circuit_add_classical_register(rust_circuit_.get(), cregs_[0].get_register().get());
5353

@@ -69,7 +69,7 @@ QuantumCircuit::QuantumCircuit(QuantumRegister &qreg, ClassicalRegister &creg, c
6969
qregs_[0] = qreg;
7070
cregs_[0] = creg;
7171

72-
rust_circuit_ = std::shared_ptr<rust_circuit>(qk_circuit_new((std::uint32_t)num_qubits_, (std::uint32_t)num_clbits_), qk_circuit_free);
72+
rust_circuit_ = std::shared_ptr<rust_circuit>(qk_circuit_new(0, 0), qk_circuit_free);
7373

7474
qk_circuit_add_quantum_register(rust_circuit_.get(), qregs_[0].get_register().get());
7575
qk_circuit_add_classical_register(rust_circuit_.get(), cregs_[0].get_register().get());
@@ -80,7 +80,7 @@ QuantumCircuit::QuantumCircuit(QuantumRegister &qreg, ClassicalRegister &creg, c
8080
}
8181
}
8282

83-
QuantumCircuit::QuantumCircuit(std::vector<QuantumRegister> &qregs, std::vector<ClassicalRegister> &cregs, const double global_phase)
83+
QuantumCircuit::QuantumCircuit(std::vector<QuantumRegister> qregs, std::vector<ClassicalRegister> cregs, const double global_phase)
8484
{
8585
num_qubits_ = 0;
8686
num_clbits_ = 0;
@@ -105,7 +105,7 @@ QuantumCircuit::QuantumCircuit(std::vector<QuantumRegister> &qregs, std::vector<
105105
num_clbits_ += cregs[i].size();
106106
}
107107

108-
rust_circuit_ = std::shared_ptr<rust_circuit>(qk_circuit_new((std::uint32_t)num_qubits_, (std::uint32_t)num_clbits_), qk_circuit_free);
108+
rust_circuit_ = std::shared_ptr<rust_circuit>(qk_circuit_new(0, 0), qk_circuit_free);
109109

110110
for (uint_t i = 0; i < qregs_.size(); i++)
111111
{
@@ -158,20 +158,14 @@ QuantumCircuit QuantumCircuit::copy(void)
158158
return copied;
159159
}
160160

161-
void QuantumCircuit::from_rust_circuit(std::shared_ptr<rust_circuit> circ, const std::vector<uint32_t> &map)
161+
void QuantumCircuit::set_qiskit_circuit(std::shared_ptr<rust_circuit> circ, const std::vector<uint32_t> &map)
162162
{
163163
if (rust_circuit_)
164164
rust_circuit_.reset();
165165
rust_circuit_ = circ;
166166
num_qubits_ = qk_circuit_num_qubits(circ.get());
167167
num_clbits_ = qk_circuit_num_clbits(circ.get());
168168

169-
qregs_.resize(1);
170-
cregs_.resize(1);
171-
172-
qregs_[0].resize(num_qubits_);
173-
cregs_[0].resize(num_clbits_);
174-
175169
qubit_map_.resize(map.size());
176170
for (int i = 0; i < map.size(); i++)
177171
{

src/circuit/register.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ class Register
150150

151151
/// @brief Return the name of this register
152152
/// @return the name of this register
153-
std::string name() { return name_; }
153+
const std::string& name() const { return name_; }
154154

155155
void set_base_index(uint_t base)
156156
{

src/compiler/transpiler.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@ circuit::QuantumCircuit transpile(circuit::QuantumCircuit &circ, providers::Back
5959
std::vector<uint32_t> layout_map(qk_transpile_layout_num_output_qubits(result.layout));
6060
qk_transpile_layout_final_layout(result.layout, false, layout_map.data());
6161

62-
circuit::QuantumCircuit transpiled;
63-
transpiled.from_rust_circuit(std::shared_ptr<rust_circuit>(result.circuit, qk_circuit_free), layout_map);
62+
circuit::QuantumCircuit transpiled = circ;
63+
transpiled.set_qiskit_circuit(std::shared_ptr<rust_circuit>(result.circuit, qk_circuit_free), layout_map);
6464
transpiled.set_target(target);
6565

6666
qk_transpile_layout_free(result.layout);

src/primitives/containers/bit_array.hpp

Lines changed: 93 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -83,18 +83,39 @@ class BitArray {
8383
// from bitstring
8484
void from_bitstring(const std::vector<std::string>& samples);
8585

86+
/// @brief Return subsets of the BitArray
87+
/// @param start_bit start bit index of subset
88+
/// @param num_bits number of bits in a subset
89+
/// @return A new BitArray
90+
BitArray get_subset(const uint_t start_bit, const uint_t num_bits);
91+
92+
/// @brief Return a list of bitstrings.
93+
/// @return A list of bitstrings.
94+
std::vector<std::string> get_bitstrings(void);
95+
8696
/// @brief Return a list of bitstrings.
97+
/// @param index a list of index to be stored in the output list
8798
/// @return A list of bitstrings.
88-
std::vector<std::string> get_bitstring(void);
99+
std::vector<std::string> get_bitstrings(reg_t& index);
89100

90101
/// @brief Return a list of hex string
91102
/// @return A list of hex string.
92-
std::vector<std::string> get_hexstring(void);
103+
std::vector<std::string> get_hexstrings(void);
104+
105+
/// @brief Return a list of hex string.
106+
/// @param index a list of index to be stored in the output list
107+
/// @return A list of hex string.
108+
std::vector<std::string> get_hexstrings(reg_t& index);
93109

94110
/// @brief Return a counts dictionary with bitstring keys.
95111
/// @return A counts dictionary with bitstring keys.
96112
std::unordered_map<std::string, uint_t> get_counts(void);
97113

114+
/// @brief Return a counts dictionary with bitstring keys.
115+
/// @param index a list of index to be stored in the output map
116+
/// @return A counts dictionary with bitstring keys.
117+
std::unordered_map<std::string, uint_t> get_counts(reg_t& index);
118+
98119
/// @brief Set pub samples from json
99120
/// @param input JSON input
100121
void from_json(nlohmann::ordered_json& input);
@@ -103,6 +124,11 @@ class BitArray {
103124
/// @param index an index to be set
104125
/// @param input a sample in a hex string format
105126
void set_hexstring(uint_t index, std::string& input);
127+
128+
/// @brief Return a list of bit counts
129+
/// @return A list of interger counts of bits appears in each shot
130+
reg_t bitcount(void);
131+
106132
};
107133

108134
void BitArray::from_samples(const reg_t& samples, uint_t num_bits)
@@ -132,7 +158,7 @@ void BitArray::from_bitstring(const std::vector<std::string>& samples)
132158
num_bits_ = array_[0].size();
133159
}
134160

135-
std::vector<std::string> BitArray::get_bitstring(void)
161+
std::vector<std::string> BitArray::get_bitstrings(void)
136162
{
137163
std::vector<std::string> ret(array_.size());
138164
for (uint_t i = 0; i < array_.size(); i++) {
@@ -141,7 +167,20 @@ std::vector<std::string> BitArray::get_bitstring(void)
141167
return ret;
142168
}
143169

144-
std::vector<std::string> BitArray::get_hexstring(void)
170+
std::vector<std::string> BitArray::get_bitstrings(reg_t& index)
171+
{
172+
uint_t size = std::min(array_.size(), index.size());
173+
std::vector<std::string> ret(size);
174+
175+
for (uint_t i = 0; i < size; i++) {
176+
uint_t pos = index[i];
177+
if (pos < array_.size())
178+
ret[i] = array_[pos].to_string();
179+
}
180+
return ret;
181+
}
182+
183+
std::vector<std::string> BitArray::get_hexstrings(void)
145184
{
146185
std::vector<std::string> ret(array_.size());
147186
for (uint_t i = 0; i < array_.size(); i++) {
@@ -150,6 +189,20 @@ std::vector<std::string> BitArray::get_hexstring(void)
150189
return ret;
151190
}
152191

192+
std::vector<std::string> BitArray::get_hexstrings(reg_t& index)
193+
{
194+
uint_t size = std::min(array_.size(), index.size());
195+
std::vector<std::string> ret(size);
196+
197+
for (uint_t i = 0; i < size; i++) {
198+
uint_t pos = index[i];
199+
if (pos < array_.size())
200+
ret[i] = array_[pos].to_hex_string();
201+
}
202+
return ret;
203+
}
204+
205+
153206
std::unordered_map<std::string, uint_t> BitArray::get_counts(void)
154207
{
155208
std::unordered_map<std::string, uint_t> ret;
@@ -159,10 +212,23 @@ std::unordered_map<std::string, uint_t> BitArray::get_counts(void)
159212
return ret;
160213
}
161214

215+
std::unordered_map<std::string, uint_t> BitArray::get_counts(reg_t& index)
216+
{
217+
uint_t size = std::min(array_.size(), index.size());
218+
std::unordered_map<std::string, uint_t> ret;
219+
220+
for (uint_t i = 0; i < size; i++) {
221+
uint_t pos = index[i];
222+
if (pos < array_.size())
223+
ret[array_[pos].to_string()]++;
224+
}
225+
return ret;
226+
}
227+
162228
void BitArray::from_json(nlohmann::ordered_json& input)
163229
{
164-
auto samples = input["data"]["c"]["samples"];
165-
auto num_bits = input["data"]["c"]["num_bits"];
230+
auto samples = input["samples"];
231+
auto num_bits = input["num_bits"];
166232
auto num_shots = samples.size();
167233
if (num_bits_ == 0)
168234
num_bits_ = num_bits;
@@ -178,6 +244,27 @@ void BitArray::set_hexstring(uint_t index, std::string& input)
178244
array_[index].from_hex_string(input);
179245
}
180246

247+
BitArray BitArray::get_subset(const uint_t start_bit, const uint_t num_bits)
248+
{
249+
BitArray ret;
250+
ret.allocate(array_.size(), num_bits);
251+
252+
for (uint_t i = 0; i < array_.size(); i++) {
253+
ret.array_[i] = array_[i].get_subset(start_bit, num_bits);
254+
}
255+
256+
return ret;
257+
}
258+
259+
reg_t BitArray::bitcount(void)
260+
{
261+
reg_t count(array_.size());
262+
for (uint_t i = 0; i < array_.size(); i++) {
263+
count[i] = array_[i].popcount();
264+
}
265+
return count;
266+
}
267+
181268

182269

183270
} // namespace primitives

0 commit comments

Comments
 (0)