Skip to content

Commit

Permalink
Fix noise sampling on shot-branching (Qiskit#2098)
Browse files Browse the repository at this point in the history
* Fix noise sampling on shot-branching

* format

* fix runtime noise sampling

* remove copying branch

* fix batch GPU

* format

* set initial value to Op structure

* format

* format

* test

* test

* fix use of additional_ops.size()

* fix error

* fix remove_empty_branches

* test

* test

* test

* test
  • Loading branch information
doichanj committed Apr 25, 2024
1 parent 687e0f1 commit 879e388
Show file tree
Hide file tree
Showing 8 changed files with 288 additions and 203 deletions.
26 changes: 17 additions & 9 deletions src/framework/operations.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,6 @@ enum class OpType {
superop,
roerror,
noise_switch,
sample_noise,
// Save instructions
save_state,
save_expval,
Expand Down Expand Up @@ -532,9 +531,6 @@ inline std::ostream &operator<<(std::ostream &stream, const OpType &type) {
case OpType::qerror_loc:
stream << "qerror_loc";
break;
case OpType::sample_noise:
stream << "sample_noise";
break;
case OpType::noise_switch:
stream << "noise_switch";
break;
Expand Down Expand Up @@ -614,11 +610,14 @@ struct Op {
string_params; // used for label, control-flow, and boolean functions

// Conditional Operations
bool conditional = false; // is gate conditional gate
uint_t conditional_reg; // (opt) the (single) register location to look up for
// conditional
BinaryOp binary_op; // (opt) boolean function relation
std::shared_ptr<CExpr> expr; // (opt) classical expression
// is gate conditional gate
bool conditional = false;
// (opt) the (single) register location to look up for conditional
uint_t conditional_reg = 0;
// (opt) boolean function relation
BinaryOp binary_op;
// (opt) classical expression
std::shared_ptr<CExpr> expr = nullptr;

// Measurement
reg_t memory; // (opt) register operation it acts on (measure)
Expand All @@ -640,6 +639,9 @@ struct Op {
// Save
DataSubType save_type = DataSubType::single;

// runtime noise sampling
bool sample_noise = false;

// runtime parameter bind
bool has_bind_params = false;
};
Expand Down Expand Up @@ -1319,8 +1321,14 @@ inline Op bind_parameter(const Op &src, const uint_t iparam,
op.type = src.type;
op.name = src.name;
op.qubits = src.qubits;
op.regs = src.regs;
op.int_params = src.int_params;
op.string_params = src.string_params;
op.conditional = src.conditional;
op.conditional_reg = src.conditional_reg;
op.binary_op = src.binary_op;
op.expr = src.expr;
op.has_bind_params = false;

if (src.params.size() > 0) {
uint_t stride = src.params.size() / num_params;
Expand Down
113 changes: 70 additions & 43 deletions src/noise/noise_model.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,13 @@ class NoiseModel {
const Method method = Method::circuit,
bool sample_at_runtime = false) const;

NoiseOps sample_noise_loc(const Operations::Op &op, RngEngine &rng) const;
NoiseOps sample_noise_at_runtime(const Operations::Op &op,
RngEngine &rng) const;

void sample_noise_at_runtime(const Operations::Op &op,
NoiseModel::NoiseOps &noise_before,
NoiseModel::NoiseOps &noise_after,
RngEngine &rng) const;

// Enable superop sampling method
// This will cause all QuantumErrors stored in the noise model
Expand Down Expand Up @@ -151,14 +157,12 @@ class NoiseModel {
void sample_local_quantum_noise(const Operations::Op &op,
NoiseOps &noise_before, NoiseOps &noise_after,
RngEngine &rng, const Method method,
const reg_t &mapping,
bool sample_at_runtime) const;
const reg_t &mapping) const;

void sample_nonlocal_quantum_noise(const Operations::Op &op,
NoiseOps &noise_ops, NoiseOps &noise_after,
RngEngine &rng, const Method method,
const reg_t &mapping,
bool sample_at_runtime) const;
const reg_t &mapping) const;

// Sample noise for the current operation
NoiseOps sample_noise_helper(const Operations::Op &op, RngEngine &rng,
Expand All @@ -176,9 +180,6 @@ class NoiseModel {
const std::vector<reg_t> &op_qubits,
const std::vector<reg_t> &noise_qubits);

// create loc noise
NoiseOps create_noise_loc(const Operations::Op &op) const;

// Flags which say whether the local or nonlocal error tables are used
bool local_quantum_errors_ = false;
bool nonlocal_quantum_errors_ = false;
Expand Down Expand Up @@ -245,7 +246,8 @@ class NoiseModel {
std::unordered_set<Method> enabled_methods_ =
std::unordered_set<Method>({Method::circuit});

// saved qubit mapping for runtime loc
// saved qubit mapping and method for runtime noise sampling
mutable Method circ_method_;
mutable reg_t circ_mapping_;
};

Expand Down Expand Up @@ -281,21 +283,57 @@ Circuit NoiseModel::sample_noise(const Circuit &circ, RngEngine &rng,
return sample_noise_circuit(circ, rng, method, sample_at_runtime);
}

NoiseModel::NoiseOps NoiseModel::sample_noise_loc(const Operations::Op &op,
RngEngine &rng) const {
auto noise_ops =
sample_noise_op(op, rng, Method::circuit, circ_mapping_, false);
NoiseModel::NoiseOps
NoiseModel::sample_noise_at_runtime(const Operations::Op &op,
RngEngine &rng) const {
// Return operator set
NoiseOps noise_before;
NoiseOps noise_after;

sample_noise_at_runtime(op, noise_before, noise_after, rng);

// Combine errors
auto &noise_ops = noise_before;
noise_ops.reserve(noise_before.size() + noise_after.size() + 1);
Operations::Op op_sampled = op;
op_sampled.sample_noise = false;
noise_ops.push_back(op_sampled);
noise_ops.insert(noise_ops.end(),
std::make_move_iterator(noise_after.begin()),
std::make_move_iterator(noise_after.end()));

return noise_ops;
}

void NoiseModel::sample_noise_at_runtime(const Operations::Op &op,
NoiseModel::NoiseOps &noise_before,
NoiseModel::NoiseOps &noise_after,
RngEngine &rng) const {
// Apply local errors first
sample_local_quantum_noise(op, noise_before, noise_after, rng, circ_method_,
circ_mapping_);
// Apply nonlocal errors second
sample_nonlocal_quantum_noise(op, noise_before, noise_after, rng,
circ_method_, circ_mapping_);
// Apply readout error to measure ops
if (op.type == Operations::OpType::measure) {
sample_readout_noise(op, noise_after, rng, circ_mapping_);
}

// If original op is conditional, make all the noise operations also
// conditional
if (op.conditional) {
for (auto &noise_op : noise_ops) {
for (auto &noise_op : noise_before) {
noise_op.conditional = op.conditional;
noise_op.conditional_reg = op.conditional_reg;
noise_op.binary_op = op.binary_op;
}
for (auto &noise_op : noise_after) {
noise_op.conditional = op.conditional;
noise_op.conditional_reg = op.conditional_reg;
noise_op.binary_op = op.binary_op;
}
}
return noise_ops;
}

Circuit NoiseModel::sample_noise_circuit(const Circuit &circ, RngEngine &rng,
Expand Down Expand Up @@ -355,6 +393,7 @@ Circuit NoiseModel::sample_noise_circuit(const Circuit &circ, RngEngine &rng,
noisy_circ.set_params();
if (sample_at_runtime) {
noisy_circ.can_sample = false;
circ_method_ = method;
circ_mapping_ = mapping;
}
return noisy_circ;
Expand Down Expand Up @@ -518,21 +557,27 @@ NoiseModel::sample_noise_helper(const Operations::Op &op, RngEngine &rng,
NoiseOps noise_after;
// Apply local errors first
sample_local_quantum_noise(op, noise_before, noise_after, rng, method,
mapping, sample_at_runtime);
mapping);
// Apply nonlocal errors second
sample_nonlocal_quantum_noise(op, noise_before, noise_after, rng, method,
mapping, sample_at_runtime);
mapping);
// Apply readout error to measure ops
if (op.type == Operations::OpType::measure) {
sample_readout_noise(op, noise_after, rng, mapping);
}

if (sample_at_runtime &&
(noise_before.size() > 0 || noise_after.size() > 0)) {
NoiseOps ret(1);
ret[0] = op;
ret[0].sample_noise = true;
return ret;
}

// Combine errors
auto &noise_ops = noise_before;
noise_ops.reserve(noise_before.size() + noise_after.size() + 1);
if (op.type != Operations::OpType::sample_noise) {
noise_ops.push_back(op);
}
noise_ops.push_back(op);
noise_ops.insert(noise_ops.end(),
std::make_move_iterator(noise_after.begin()),
std::make_move_iterator(noise_after.end()));
Expand Down Expand Up @@ -655,8 +700,7 @@ void NoiseModel::sample_local_quantum_noise(const Operations::Op &op,
NoiseOps &noise_before,
NoiseOps &noise_after,
RngEngine &rng, const Method method,
const reg_t &mapping,
bool sample_at_runtime) const {
const reg_t &mapping) const {
// If no errors are defined pass
if (local_quantum_errors_ == false)
return;
Expand Down Expand Up @@ -714,11 +758,7 @@ void NoiseModel::sample_local_quantum_noise(const Operations::Op &op,
: iter_default->second;
for (auto &pos : error_positions) {
NoiseOps noise_ops;
if (sample_at_runtime)
noise_ops = create_noise_loc(op);
else
noise_ops =
quantum_errors_[pos].sample_noise(op_qubits, rng, method);
noise_ops = quantum_errors_[pos].sample_noise(op_qubits, rng, method);
// Duplicate same sampled error operations
if (quantum_errors_[pos].errors_after())
noise_after.insert(noise_after.end(), noise_ops.begin(),
Expand All @@ -734,8 +774,7 @@ void NoiseModel::sample_local_quantum_noise(const Operations::Op &op,

void NoiseModel::sample_nonlocal_quantum_noise(
const Operations::Op &op, NoiseOps &noise_before, NoiseOps &noise_after,
RngEngine &rng, const Method method, const reg_t &mapping,
bool sample_at_runtime) const {
RngEngine &rng, const Method method, const reg_t &mapping) const {
// If no errors are defined pass
if (nonlocal_quantum_errors_ == false)
return;
Expand Down Expand Up @@ -783,12 +822,8 @@ void NoiseModel::sample_nonlocal_quantum_noise(
auto &error_positions = target_pair.second;
for (auto &pos : error_positions) {
NoiseOps ops;
if (sample_at_runtime)
ops = create_noise_loc(op);
else {
ops = quantum_errors_[pos].sample_noise(string2reg(target_qubits),
rng, method);
}
ops = quantum_errors_[pos].sample_noise(string2reg(target_qubits),
rng, method);
if (quantum_errors_[pos].errors_after())
noise_after.insert(noise_after.end(), ops.begin(), ops.end());
else
Expand All @@ -800,14 +835,6 @@ void NoiseModel::sample_nonlocal_quantum_noise(
}
}

NoiseModel::NoiseOps
NoiseModel::create_noise_loc(const Operations::Op &op) const {
NoiseOps ops(1);
ops[0] = op;
ops[0].type = Operations::OpType::sample_noise;
return ops;
}

cmatrix_t NoiseModel::op2superop(const Operations::Op &op) const {
switch (op.type) {
case Operations::OpType::superop:
Expand Down
Loading

0 comments on commit 879e388

Please sign in to comment.