From 14dbe7e25dcf0b05170e76e6ad6f8c95ee46fbe5 Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Mon, 15 Apr 2024 17:47:16 +0900 Subject: [PATCH 01/18] Fix noise sampling on shot-branching --- src/framework/operations.hpp | 13 ++-- src/noise/noise_model.hpp | 86 ++++++++++++++----------- src/simulators/batch_shots_executor.hpp | 8 +-- src/simulators/multi_state_executor.hpp | 29 ++++++--- src/simulators/shot_branching.hpp | 21 ++++-- src/transpile/fusion.hpp | 6 +- 6 files changed, 99 insertions(+), 64 deletions(-) diff --git a/src/framework/operations.hpp b/src/framework/operations.hpp index ea8b68da1a..c6575a2a55 100644 --- a/src/framework/operations.hpp +++ b/src/framework/operations.hpp @@ -383,7 +383,6 @@ enum class OpType { superop, roerror, noise_switch, - sample_noise, // Save instructions save_state, save_expval, @@ -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; @@ -640,6 +636,9 @@ struct Op { // Save DataSubType save_type = DataSubType::single; + // runtime noise sampling + bool sample_noise = false; + // runtime parameter bind bool has_bind_params = false; }; @@ -1319,8 +1318,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.sample_noise = src.sample_noise; + op.binary_op = src.binary_op; + op.expr = src.expr; if (src.params.size() > 0) { uint_t stride = src.params.size() / num_params; diff --git a/src/noise/noise_model.hpp b/src/noise/noise_model.hpp index 23dbccc9bd..3d17313699 100644 --- a/src/noise/noise_model.hpp +++ b/src/noise/noise_model.hpp @@ -65,7 +65,7 @@ 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; // Enable superop sampling method // This will cause all QuantumErrors stored in the noise model @@ -151,14 +151,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, @@ -176,9 +174,6 @@ class NoiseModel { const std::vector &op_qubits, const std::vector &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; @@ -245,7 +240,8 @@ class NoiseModel { std::unordered_set enabled_methods_ = std::unordered_set({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_; }; @@ -281,10 +277,32 @@ 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, +NoiseModel::NoiseOps NoiseModel::sample_noise_at_runtime(const Operations::Op &op, RngEngine &rng) const { - auto noise_ops = - sample_noise_op(op, rng, Method::circuit, circ_mapping_, false); +// auto noise_ops = +// sample_noise_op(op, rng, Method::circuit, circ_mapping_, false); + + // Return operator set + NoiseOps noise_before; + NoiseOps noise_after; + // 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_); + } + + // Combine errors + auto &noise_ops = noise_before; + noise_ops.reserve(noise_before.size() + noise_after.size() + 1); + 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())); // If original op is conditional, make all the noise operations also // conditional @@ -355,6 +373,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; @@ -518,21 +537,26 @@ 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())); @@ -655,8 +679,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; @@ -714,11 +737,8 @@ 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(), @@ -734,8 +754,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; @@ -783,12 +802,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 @@ -800,13 +815,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) { diff --git a/src/simulators/batch_shots_executor.hpp b/src/simulators/batch_shots_executor.hpp index 612e5ed289..8b12b2ee6d 100644 --- a/src/simulators/batch_shots_executor.hpp +++ b/src/simulators/batch_shots_executor.hpp @@ -506,13 +506,13 @@ void BatchShotsExecutor::apply_ops_batched_shots_for_group( #endif for (auto op = first; op != last; ++op) { - if (op->type == Operations::OpType::sample_noise) { + if (op->sample_noise) { if (op->expr) { for (uint_t j = Base::top_state_of_group_[i_group]; j < Base::top_state_of_group_[i_group + 1]; j++) { Base::states_[j].qreg().enable_batch(false); Base::states_[j].qreg().read_measured_data(Base::states_[j].creg()); - std::vector nops = noise.sample_noise_loc( + std::vector nops = noise.sample_noise_at_runtime( *op, rng[j - Base::top_state_of_group_[i_group]]); for (uint_t k = 0; k < nops.size(); k++) { Base::states_[j].apply_op( @@ -533,7 +533,7 @@ void BatchShotsExecutor::apply_ops_batched_shots_for_group( if (num_inner_threads > 1) { #pragma omp parallel for reduction(+: count_ops,non_pauli_gate_count) num_threads(num_inner_threads) for (int_t j = 0; j < (int_t)count; j++) { - noise_ops[j] = noise.sample_noise_loc(*op, rng[j]); + noise_ops[j] = noise.sample_noise_at_runtime(*op, rng[j]); if (!(noise_ops[j].size() == 0 || (noise_ops[j].size() == 1 && noise_ops[j][0].name == "id"))) { @@ -550,7 +550,7 @@ void BatchShotsExecutor::apply_ops_batched_shots_for_group( } } else { for (uint_t j = 0; j < count; j++) { - noise_ops[j] = noise.sample_noise_loc(*op, rng[j]); + noise_ops[j] = noise.sample_noise_at_runtime(*op, rng[j]); if (!(noise_ops[j].size() == 0 || (noise_ops[j].size() == 1 && noise_ops[j][0].name == "id"))) { diff --git a/src/simulators/multi_state_executor.hpp b/src/simulators/multi_state_executor.hpp index 3f180bea1b..9c2a444013 100644 --- a/src/simulators/multi_state_executor.hpp +++ b/src/simulators/multi_state_executor.hpp @@ -531,11 +531,21 @@ void MultiStateExecutor::run_circuit_with_shot_branching( int_t iadd = 0; int_t num_add = branches[istate]->additional_ops().size(); while (iadd < num_add) { - if (apply_branching_op(*branches[istate], + bool branch_op = false; + if (branches[istate]->additional_ops()[iadd].sample_noise) { + branch_op = branches[istate]->apply_runtime_noise_sampling( + state.creg(), + branches[istate]->additional_ops()[iadd], + noise); + } + else{ + branch_op = apply_branching_op(*branches[istate], branches[istate]->additional_ops()[iadd], - par_results[i].begin(), false)) { - // check if there are new branches - if (branches[istate]->num_branches() > 0) { + par_results[i].begin(), false); + } + // check if there are new branches + if (branch_op){ + if(branches[istate]->num_branches() > 0) { // if there are additional ops remaining, queue them on new // branches for (uint_t k = iadd + 1; @@ -581,14 +591,13 @@ void MultiStateExecutor::run_circuit_with_shot_branching( if (branches[istate]->apply_control_flow(state.creg(), measure_seq)) continue; - // runtime noise sampling - if (op->type == Operations::OpType::sample_noise) { + if (op->has_bind_params) { + // runtime parameterizaion + apply_runtime_parameterization(*branches[istate], *op); + } else if (op->sample_noise) { + // runtime noise sampling branches[istate]->apply_runtime_noise_sampling(state.creg(), *op, noise); - } - // runtime parameterizaion - else if (op->has_bind_params) { - apply_runtime_parameterization(*branches[istate], *op); } else { if (!apply_branching_op(*branches[istate], *op, par_results[i].begin(), diff --git a/src/simulators/shot_branching.hpp b/src/simulators/shot_branching.hpp index 0d81f707a4..8e94c83bb1 100644 --- a/src/simulators/shot_branching.hpp +++ b/src/simulators/shot_branching.hpp @@ -246,16 +246,16 @@ void Branch::advance_iterator(void) { bool Branch::apply_runtime_noise_sampling(const ClassicalRegister &creg, const Operations::Op &op, const Noise::NoiseModel &noise) { - if (op.type != Operations::OpType::sample_noise) - return false; - uint_t nshots = num_shots(); reg_t shot_map(nshots); std::vector> noises; + if (!op.sample_noise) + return false; + for (uint_t i = 0; i < nshots; i++) { std::vector noise_ops = - noise.sample_noise_loc(op, shots_[i]); + noise.sample_noise_at_runtime(op, shots_[i]); // search same noise ops int_t pos = -1; @@ -264,6 +264,11 @@ bool Branch::apply_runtime_noise_sampling(const ClassicalRegister &creg, continue; bool same = true; for (uint_t k = 0; k < noise_ops.size(); k++) { + if (noise_ops[k].sample_noise){ + noise_ops[k].sample_noise = false; + continue; //skip original op + } + if (noise_ops[k].type != noises[j][k].type || noise_ops[k].name != noises[j][k].name) same = false; @@ -323,6 +328,14 @@ bool Branch::apply_runtime_noise_sampling(const ClassicalRegister &creg, } } + if(noises.size() == 0){ + for (uint_t k = 0; k < noise_ops.size(); k++) { + if (noise_ops[k].sample_noise){ + noise_ops[k].sample_noise = false; + } + } + } + if (pos < 0) { // if not found, add noise ops to the list shot_map[i] = noises.size(); noises.push_back(noise_ops); diff --git a/src/transpile/fusion.hpp b/src/transpile/fusion.hpp index c65160fed9..9948c640dc 100644 --- a/src/transpile/fusion.hpp +++ b/src/transpile/fusion.hpp @@ -174,7 +174,7 @@ class UnitaryFusion : public FusionMethod { }; virtual bool can_apply(const op_t &op, uint_t max_fused_qubits) const { - if (op.conditional) + if (op.conditional || op.sample_noise) return false; switch (op.type) { case optype_t::matrix: @@ -221,7 +221,7 @@ class SuperOpFusion : public UnitaryFusion { }; virtual bool can_apply(const op_t &op, uint_t max_fused_qubits) const { - if (op.conditional) + if (op.conditional || op.sample_noise) return false; switch (op.type) { case optype_t::kraus: @@ -271,7 +271,7 @@ class KrausFusion : public UnitaryFusion { }; virtual bool can_apply(const op_t &op, uint_t max_fused_qubits) const { - if (op.conditional) + if (op.conditional || op.sample_noise) return false; switch (op.type) { case optype_t::kraus: From 8b0038fe09e531a756ea3d2b77adfc2c6483481c Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Mon, 15 Apr 2024 17:53:55 +0900 Subject: [PATCH 02/18] format --- src/framework/operations.hpp | 2 +- src/noise/noise_model.hpp | 23 ++++++++++++----------- src/simulators/multi_state_executor.hpp | 19 +++++++++---------- src/simulators/shot_branching.hpp | 8 ++++---- 4 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/framework/operations.hpp b/src/framework/operations.hpp index c6575a2a55..955159cc02 100644 --- a/src/framework/operations.hpp +++ b/src/framework/operations.hpp @@ -636,7 +636,7 @@ struct Op { // Save DataSubType save_type = DataSubType::single; - // runtime noise sampling + // runtime noise sampling bool sample_noise = false; // runtime parameter bind diff --git a/src/noise/noise_model.hpp b/src/noise/noise_model.hpp index 3d17313699..9ca4953925 100644 --- a/src/noise/noise_model.hpp +++ b/src/noise/noise_model.hpp @@ -65,7 +65,8 @@ class NoiseModel { const Method method = Method::circuit, bool sample_at_runtime = false) const; - NoiseOps sample_noise_at_runtime(const Operations::Op &op, RngEngine &rng) const; + NoiseOps sample_noise_at_runtime(const Operations::Op &op, + RngEngine &rng) const; // Enable superop sampling method // This will cause all QuantumErrors stored in the noise model @@ -277,10 +278,11 @@ Circuit NoiseModel::sample_noise(const Circuit &circ, RngEngine &rng, return sample_noise_circuit(circ, rng, method, sample_at_runtime); } -NoiseModel::NoiseOps NoiseModel::sample_noise_at_runtime(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 { + // auto noise_ops = + // sample_noise_op(op, rng, Method::circuit, circ_mapping_, false); // Return operator set NoiseOps noise_before; @@ -289,8 +291,8 @@ NoiseModel::NoiseOps NoiseModel::sample_noise_at_runtime(const Operations::Op &o 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_); + 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_); @@ -546,7 +548,8 @@ NoiseModel::sample_noise_helper(const Operations::Op &op, RngEngine &rng, sample_readout_noise(op, noise_after, rng, mapping); } - if (sample_at_runtime && (noise_before.size() > 0 || noise_after.size() > 0)){ + if (sample_at_runtime && + (noise_before.size() > 0 || noise_after.size() > 0)) { NoiseOps ret(1); ret[0] = op; ret[0].sample_noise = true; @@ -737,8 +740,7 @@ void NoiseModel::sample_local_quantum_noise(const Operations::Op &op, : iter_default->second; for (auto &pos : error_positions) { NoiseOps noise_ops; - 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(), @@ -815,7 +817,6 @@ void NoiseModel::sample_nonlocal_quantum_noise( } } - cmatrix_t NoiseModel::op2superop(const Operations::Op &op) const { switch (op.type) { case Operations::OpType::superop: diff --git a/src/simulators/multi_state_executor.hpp b/src/simulators/multi_state_executor.hpp index 9c2a444013..cbb22b0a20 100644 --- a/src/simulators/multi_state_executor.hpp +++ b/src/simulators/multi_state_executor.hpp @@ -534,18 +534,17 @@ void MultiStateExecutor::run_circuit_with_shot_branching( bool branch_op = false; if (branches[istate]->additional_ops()[iadd].sample_noise) { branch_op = branches[istate]->apply_runtime_noise_sampling( - state.creg(), - branches[istate]->additional_ops()[iadd], - noise); - } - else{ - branch_op = apply_branching_op(*branches[istate], - branches[istate]->additional_ops()[iadd], - par_results[i].begin(), false); + state.creg(), branches[istate]->additional_ops()[iadd], + noise); + } else { + branch_op = apply_branching_op( + *branches[istate], + branches[istate]->additional_ops()[iadd], + par_results[i].begin(), false); } // check if there are new branches - if (branch_op){ - if(branches[istate]->num_branches() > 0) { + if (branch_op) { + if (branches[istate]->num_branches() > 0) { // if there are additional ops remaining, queue them on new // branches for (uint_t k = iadd + 1; diff --git a/src/simulators/shot_branching.hpp b/src/simulators/shot_branching.hpp index 8e94c83bb1..c647cfc6d3 100644 --- a/src/simulators/shot_branching.hpp +++ b/src/simulators/shot_branching.hpp @@ -264,9 +264,9 @@ bool Branch::apply_runtime_noise_sampling(const ClassicalRegister &creg, continue; bool same = true; for (uint_t k = 0; k < noise_ops.size(); k++) { - if (noise_ops[k].sample_noise){ + if (noise_ops[k].sample_noise) { noise_ops[k].sample_noise = false; - continue; //skip original op + continue; // skip original op } if (noise_ops[k].type != noises[j][k].type || @@ -328,9 +328,9 @@ bool Branch::apply_runtime_noise_sampling(const ClassicalRegister &creg, } } - if(noises.size() == 0){ + if (noises.size() == 0) { for (uint_t k = 0; k < noise_ops.size(); k++) { - if (noise_ops[k].sample_noise){ + if (noise_ops[k].sample_noise) { noise_ops[k].sample_noise = false; } } From 6eef97010015a503ce29bddc59fa32fdc9c1b5db Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Thu, 18 Apr 2024 11:51:01 +0900 Subject: [PATCH 03/18] fix runtime noise sampling --- src/framework/operations.hpp | 1 + src/noise/noise_model.hpp | 44 ++++++--- src/simulators/batch_shots_executor.hpp | 121 ++++++++++++++++-------- src/simulators/multi_state_executor.hpp | 77 ++------------- src/simulators/shot_branching.hpp | 83 +++++++++++----- 5 files changed, 184 insertions(+), 142 deletions(-) diff --git a/src/framework/operations.hpp b/src/framework/operations.hpp index 955159cc02..c9a5659985 100644 --- a/src/framework/operations.hpp +++ b/src/framework/operations.hpp @@ -1326,6 +1326,7 @@ inline Op bind_parameter(const Op &src, const uint_t iparam, op.sample_noise = src.sample_noise; 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; diff --git a/src/noise/noise_model.hpp b/src/noise/noise_model.hpp index 9ca4953925..4063aaa58a 100644 --- a/src/noise/noise_model.hpp +++ b/src/noise/noise_model.hpp @@ -68,6 +68,11 @@ class NoiseModel { 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 // to calculate their superoperator representations and raise @@ -281,12 +286,29 @@ Circuit NoiseModel::sample_noise(const Circuit &circ, RngEngine &rng, NoiseModel::NoiseOps NoiseModel::sample_noise_at_runtime(const Operations::Op &op, RngEngine &rng) const { - // auto noise_ops = - // sample_noise_op(op, rng, Method::circuit, circ_mapping_, false); - // 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_); @@ -298,24 +320,20 @@ NoiseModel::sample_noise_at_runtime(const Operations::Op &op, sample_readout_noise(op, noise_after, rng, circ_mapping_); } - // Combine errors - auto &noise_ops = noise_before; - noise_ops.reserve(noise_before.size() + noise_after.size() + 1); - 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())); - // 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, diff --git a/src/simulators/batch_shots_executor.hpp b/src/simulators/batch_shots_executor.hpp index 8b12b2ee6d..bdfdd5fdbd 100644 --- a/src/simulators/batch_shots_executor.hpp +++ b/src/simulators/batch_shots_executor.hpp @@ -99,6 +99,9 @@ class BatchShotsExecutor : public virtual MultiStateExecutor { InputIterator last_meas, uint_t shots, uint_t i_group, ResultItr result, std::vector &rng); + + // check if ops contains pauli ops + bool check_pauli_only(std::vector &ops); }; template @@ -526,55 +529,87 @@ void BatchShotsExecutor::apply_ops_batched_shots_for_group( // sample error here uint_t count = Base::num_states_in_group_[i_group]; - std::vector> noise_ops(count); + std::vector> noise_ops_before(count); + std::vector> noise_ops_after(count); - uint_t count_ops = 0; - uint_t non_pauli_gate_count = 0; + uint_t count_ops_before = 0; + uint_t count_ops_after = 0; + bool pauli_only_before = true; + bool pauli_only_after = true; if (num_inner_threads > 1) { -#pragma omp parallel for reduction(+: count_ops,non_pauli_gate_count) num_threads(num_inner_threads) +#pragma omp parallel for reduction(+: count_ops_before, count_ops_after) reduction(&: pauli_only_before, pauli_only_after) num_threads(num_inner_threads) for (int_t j = 0; j < (int_t)count; j++) { - noise_ops[j] = noise.sample_noise_at_runtime(*op, rng[j]); - - if (!(noise_ops[j].size() == 0 || - (noise_ops[j].size() == 1 && noise_ops[j][0].name == "id"))) { - count_ops++; - for (uint_t k = 0; k < noise_ops[j].size(); k++) { - if (noise_ops[j][k].name != "id" && noise_ops[j][k].name != "x" && - noise_ops[j][k].name != "y" && noise_ops[j][k].name != "z" && - noise_ops[j][k].name != "pauli") { - non_pauli_gate_count++; - break; - } - } + noise.sample_noise_at_runtime(*op, noise_ops_before[j], + noise_ops_after[j], rng[j]); + + pauli_only_before &= check_pauli_only(noise_ops_before[j]); + pauli_only_after &= check_pauli_only(noise_ops_after[j]); + + if (!(noise_ops_before[j].size() == 0 || + (noise_ops_before[j].size() == 1 && + noise_ops_before[j][0].name == "id"))) { + count_ops_before++; + } + if (!(noise_ops_after[j].size() == 0 || + (noise_ops_after[j].size() == 1 && + noise_ops_after[j][0].name == "id"))) { + count_ops_after++; } } } else { for (uint_t j = 0; j < count; j++) { - noise_ops[j] = noise.sample_noise_at_runtime(*op, rng[j]); - - if (!(noise_ops[j].size() == 0 || - (noise_ops[j].size() == 1 && noise_ops[j][0].name == "id"))) { - count_ops++; - for (uint_t k = 0; k < noise_ops[j].size(); k++) { - if (noise_ops[j][k].name != "id" && noise_ops[j][k].name != "x" && - noise_ops[j][k].name != "y" && noise_ops[j][k].name != "z" && - noise_ops[j][k].name != "pauli") { - non_pauli_gate_count++; - break; - } - } + noise.sample_noise_at_runtime(*op, noise_ops_before[j], + noise_ops_after[j], rng[j]); + + pauli_only_before &= check_pauli_only(noise_ops_before[j]); + pauli_only_after &= check_pauli_only(noise_ops_after[j]); + + if (!(noise_ops_before[j].size() == 0 || + (noise_ops_before[j].size() == 1 && + noise_ops_before[j][0].name == "id"))) { + count_ops_before++; + } + if (!(noise_ops_after[j].size() == 0 || + (noise_ops_after[j].size() == 1 && + noise_ops_after[j][0].name == "id"))) { + count_ops_after++; } } } - if (count_ops == 0) { - continue; // do nothing + // noise before op + if (count_ops_before > 0) { + if (pauli_only_before) { // optimization for Pauli error + Base::states_[istate].qreg().apply_batched_pauli_ops( + noise_ops_before); + } else { + // otherwise execute each circuit + apply_batched_noise_ops(i_group, noise_ops_before, result_it, rng); + } } - if (non_pauli_gate_count == 0) { // optimization for Pauli error - Base::states_[istate].qreg().apply_batched_pauli_ops(noise_ops); - } else { - // otherwise execute each circuit - apply_batched_noise_ops(i_group, noise_ops, result_it, rng); + // apply base op + if (!apply_batched_op(istate, *op, result_it, rng, + final_ops && (op + 1 == last))) { + // call apply_op for each state + for (uint_t j = 0; j < Base::num_states_in_group_[i_group]; j++) { + uint_t is = Base::top_state_of_group_[i_group] + j; + uint_t ip = (Base::global_state_index_ + is) / + Base::num_shots_per_bind_param_; + Base::states_[is].qreg().enable_batch(false); + Base::states_[is].qreg().read_measured_data(Base::states_[is].creg()); + Base::states_[is].apply_op(*op, *(result_it + ip), rng[j], + final_ops && (op + 1 == last)); + Base::states_[is].qreg().enable_batch(true); + } + } + // noise after op + if (count_ops_after > 0) { + if (pauli_only_after) { // optimization for Pauli error + Base::states_[istate].qreg().apply_batched_pauli_ops(noise_ops_after); + } else { + // otherwise execute each circuit + apply_batched_noise_ops(i_group, noise_ops_after, result_it, rng); + } } } else { if (!op->expr && apply_batched_op(istate, *op, result_it, rng, @@ -596,6 +631,18 @@ void BatchShotsExecutor::apply_ops_batched_shots_for_group( } } +template +bool BatchShotsExecutor::check_pauli_only( + std::vector &ops) { + for (uint_t k = 0; k < ops.size(); k++) { + if (ops[k].name != "id" && ops[k].name != "x" && ops[k].name != "y" && + ops[k].name != "z" && ops[k].name != "pauli") { + return false; + } + } + return true; +} + template void BatchShotsExecutor::apply_batched_noise_ops( const int_t i_group, const std::vector> &ops, diff --git a/src/simulators/multi_state_executor.hpp b/src/simulators/multi_state_executor.hpp index cbb22b0a20..7f80ae2645 100644 --- a/src/simulators/multi_state_executor.hpp +++ b/src/simulators/multi_state_executor.hpp @@ -468,7 +468,7 @@ void MultiStateExecutor::run_circuit_with_shot_branching( // initial state waiting_branches.push_back(std::make_shared()); waiting_branches[0]->set_shots(shots_storage); - waiting_branches[0]->op_iterator() = first; + waiting_branches[0]->set_iterator(first); if (Base::num_bind_params_ > 1) { waiting_branches[0]->set_param_index(global_state_index_ + ishot, Base::num_shots_per_bind_param_); @@ -494,7 +494,7 @@ void MultiStateExecutor::run_circuit_with_shot_branching( break; uint_t sid = top_state + i; waiting_branches[i]->state_index() = sid; - waiting_branches[i]->op_iterator() = first; + waiting_branches[i]->set_iterator(first); branches.push_back(waiting_branches[i]); // initialize state @@ -514,7 +514,7 @@ void MultiStateExecutor::run_circuit_with_shot_branching( while (num_active_states > 0) { // loop until all branches execute all ops // functor for ops execution auto apply_ops_func = [this, &branches, &noise, &par_results, measure_seq, - last, par_shots, num_active_states](int_t i) { + last, par_shots](int_t i) { uint_t istate, state_end; istate = branches.size() * i / par_shots; state_end = branches.size() * (i + 1) / par_shots; @@ -524,65 +524,9 @@ void MultiStateExecutor::run_circuit_with_shot_branching( for (; istate < state_end; istate++) { state_t &state = states_[branches[istate]->state_index()]; - while (branches[istate]->op_iterator() != measure_seq || - branches[istate]->additional_ops().size() > 0) { - // execute additional ops first if avaiable - if (branches[istate]->additional_ops().size() > 0) { - int_t iadd = 0; - int_t num_add = branches[istate]->additional_ops().size(); - while (iadd < num_add) { - bool branch_op = false; - if (branches[istate]->additional_ops()[iadd].sample_noise) { - branch_op = branches[istate]->apply_runtime_noise_sampling( - state.creg(), branches[istate]->additional_ops()[iadd], - noise); - } else { - branch_op = apply_branching_op( - *branches[istate], - branches[istate]->additional_ops()[iadd], - par_results[i].begin(), false); - } - // check if there are new branches - if (branch_op) { - if (branches[istate]->num_branches() > 0) { - // if there are additional ops remaining, queue them on new - // branches - for (uint_t k = iadd + 1; - k < branches[istate]->additional_ops().size(); k++) { - for (uint_t l = 0; l < branches[istate]->num_branches(); - l++) - branches[istate]->branches()[l]->add_op_after_branch( - branches[istate]->additional_ops()[k]); - } - branches[istate]->remove_empty_branches(); - state.creg() = branches[istate]->creg(); - - // if there are some branches still remaining - if (branches[istate]->num_branches() > 0) { - nbranch += branches[istate]->num_branches(); - break; - } - iadd = 0; - num_add = branches[istate]->additional_ops().size(); - } - } else { - state.apply_op(branches[istate]->additional_ops()[iadd], - par_results[i][0], dummy_rng, false); - } - iadd++; - } - branches[istate]->clear_additional_ops(); - // if there are some branches still remaining - if (branches[istate]->num_branches() > 0) { - nbranch += branches[istate]->num_branches(); - break; - } - } + while (branches[istate]->op_iterator() != measure_seq) { OpItr op = branches[istate]->op_iterator(); - if (op == measure_seq) - break; - // then execute ops if (!state.creg().check_conditional(*op)) { branches[istate]->advance_iterator(); continue; @@ -590,13 +534,14 @@ void MultiStateExecutor::run_circuit_with_shot_branching( if (branches[istate]->apply_control_flow(state.creg(), measure_seq)) continue; - if (op->has_bind_params) { - // runtime parameterizaion - apply_runtime_parameterization(*branches[istate], *op); - } else if (op->sample_noise) { + branches[istate]->advance_iterator(); + if (op->sample_noise) { // runtime noise sampling branches[istate]->apply_runtime_noise_sampling(state.creg(), *op, noise); + } else if (op->has_bind_params) { + // runtime parameterizaion + apply_runtime_parameterization(*branches[istate], *op); } else { if (!apply_branching_op(*branches[istate], *op, par_results[i].begin(), @@ -606,7 +551,6 @@ void MultiStateExecutor::run_circuit_with_shot_branching( } } - branches[istate]->advance_iterator(); if (branches[istate]->num_branches() > 0) { branches[istate]->remove_empty_branches(); state.creg() = branches[istate]->creg(); @@ -680,8 +624,7 @@ void MultiStateExecutor::run_circuit_with_shot_branching( // check if there are remaining ops num_active_states = 0; for (uint_t i = 0; i < branches.size(); i++) { - if (branches[i]->op_iterator() != measure_seq || - branches[i]->additional_ops().size() > 0) + if (branches[i]->op_iterator() != measure_seq) num_active_states++; } } diff --git a/src/simulators/shot_branching.hpp b/src/simulators/shot_branching.hpp index c647cfc6d3..4b82123efa 100644 --- a/src/simulators/shot_branching.hpp +++ b/src/simulators/shot_branching.hpp @@ -39,6 +39,7 @@ class Branch { // additional operations applied after shot branching std::vector additional_ops_; + uint_t additional_op_pos_; // mark for control flow std::unordered_map flow_marks_; @@ -50,7 +51,7 @@ class Branch { std::vector> branches_; public: - Branch(void) {} + Branch(void) { additional_op_pos_ = 0; } ~Branch() { shots_.clear(); additional_ops_.clear(); @@ -61,22 +62,27 @@ class Branch { creg_ = src.creg_; iter_ = src.iter_; flow_marks_ = src.flow_marks_; + additional_ops_ = src.additional_ops_; + additional_op_pos_ = src.additional_op_pos_; } uint_t &state_index(void) { return state_index_; } uint_t &root_state_index(void) { return root_state_index_; } ClassicalRegister &creg(void) { return creg_; } std::vector &rng_shots(void) { return shots_; } - OpItr &op_iterator(void) { return iter_; } std::unordered_map &marks(void) { return flow_marks_; } uint_t num_branches(void) { return branches_.size(); } std::vector> &branches(void) { return branches_; } + void set_iterator(OpItr &iter) { iter_ = iter; } + OpItr op_iterator(void); + uint_t num_shots(void) { return shots_.size(); } void clear(void) { shots_.clear(); additional_ops_.clear(); branches_.clear(); + additional_op_pos_ = 0; } void clear_branch(void) { branches_.clear(); } @@ -91,16 +97,22 @@ class Branch { void add_op_after_branch(Operations::Op &op) { additional_ops_.push_back(op); } - void copy_ops_after_branch(std::vector &ops) { - additional_ops_ = ops; + void add_ops_after_branch(std::vector &ops) { + additional_ops_.insert(additional_ops_.end(), ops.begin(), ops.end()); + } + void clear_additional_ops(void) { + additional_ops_.clear(); + additional_op_pos_ = 0; } - void clear_additional_ops(void) { additional_ops_.clear(); } std::vector &additional_ops(void) { return additional_ops_; } void branch_shots(reg_t &shots, int_t nbranch); bool apply_control_flow(ClassicalRegister &creg, OpItr last) { + if (additional_ops_.size() > 0) + return false; + if (iter_->type == Operations::OpType::mark) { flow_marks_[iter_->string_params[0]] = iter_; iter_++; @@ -219,7 +231,7 @@ void Branch::branch_shots_by_params(void) { branches_.resize(param_index_.size()); for (uint_t i = 0; i < param_index_.size(); i++) { - branches_[i] = std::make_shared(); + branches_[i] = std::make_shared(*this); branches_[i]->creg_ = creg_; branches_[i]->iter_ = iter_; branches_[i]->flow_marks_ = flow_marks_; @@ -236,11 +248,20 @@ void Branch::branch_shots_by_params(void) { } } -void Branch::advance_iterator(void) { - iter_++; - for (uint_t i = 0; i < branches_.size(); i++) { - branches_[i]->iter_++; +OpItr Branch::op_iterator(void) { + if (additional_ops_.size() > additional_op_pos_) { + OpItr it = additional_ops_.cbegin(); + it += additional_op_pos_; + return it; } + return iter_; +} + +void Branch::advance_iterator(void) { + if (additional_ops_.size() > additional_op_pos_) + additional_op_pos_++; + else + iter_++; } bool Branch::apply_runtime_noise_sampling(const ClassicalRegister &creg, @@ -347,37 +368,49 @@ bool Branch::apply_runtime_noise_sampling(const ClassicalRegister &creg, creg_ = creg; branch_shots(shot_map, noises.size()); for (uint_t i = 0; i < noises.size(); i++) { - branches_[i]->copy_ops_after_branch(noises[i]); + branches_[i]->add_ops_after_branch(noises[i]); } return true; } void Branch::remove_empty_branches(void) { - int_t istart = 0; + // find first branch that has at least one shot + int_t iroot = -1; for (uint_t j = 0; j < branches_.size(); j++) { if (branches_[j]->num_shots() > 0) { - // copy shots to the root - shots_ = branches_[j]->rng_shots(); - param_index_ = branches_[j]->param_index_; - param_shots_ = branches_[j]->param_shots_; - additional_ops_ = branches_[j]->additional_ops(); - creg_ = branches_[j]->creg(); - branches_[j].reset(); - istart = j + 1; + iroot = j; break; } branches_[j].reset(); } - std::vector> new_branches; + // copy shots to the root + shots_ = branches_[iroot]->rng_shots(); + param_index_ = branches_[iroot]->param_index_; + param_shots_ = branches_[iroot]->param_shots_; + creg_ = branches_[iroot]->creg(); - for (uint_t j = istart; j < branches_.size(); j++) { - if (branches_[j]->num_shots() > 0) - new_branches.push_back(branches_[j]); - else + std::vector> new_branches; + for (uint_t j = iroot; j < branches_.size(); j++) { + if (branches_[j]->num_shots() > 0) { + // update additional ops if there are remaining additional ops + if (additional_ops_.size() > additional_op_pos_) { + branches_[j]->additional_ops_.insert( + branches_[j]->additional_ops_.end(), + additional_ops_.begin() + additional_op_pos_, + additional_ops_.end()); + } + if (j != iroot) + new_branches.push_back(branches_[j]); + } else branches_[j].reset(); } + + additional_ops_ = branches_[iroot]->additional_ops_; + additional_op_pos_ = 0; + branches_[iroot].reset(); + branches_ = new_branches; } From 9fb84a5ac4f4e50cf0696eed9079a7a18209d36a Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Thu, 18 Apr 2024 14:26:37 +0900 Subject: [PATCH 04/18] remove copying branch --- src/simulators/shot_branching.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/simulators/shot_branching.hpp b/src/simulators/shot_branching.hpp index 4b82123efa..8b9803df60 100644 --- a/src/simulators/shot_branching.hpp +++ b/src/simulators/shot_branching.hpp @@ -231,7 +231,7 @@ void Branch::branch_shots_by_params(void) { branches_.resize(param_index_.size()); for (uint_t i = 0; i < param_index_.size(); i++) { - branches_[i] = std::make_shared(*this); + branches_[i] = std::make_shared(); branches_[i]->creg_ = creg_; branches_[i]->iter_ = iter_; branches_[i]->flow_marks_ = flow_marks_; From 5ec50d55049d074605209b348f4d68d0becd02da Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Thu, 18 Apr 2024 18:57:11 +0900 Subject: [PATCH 05/18] fix batch GPU --- src/simulators/batch_shots_executor.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/simulators/batch_shots_executor.hpp b/src/simulators/batch_shots_executor.hpp index bdfdd5fdbd..addb30cee8 100644 --- a/src/simulators/batch_shots_executor.hpp +++ b/src/simulators/batch_shots_executor.hpp @@ -587,8 +587,8 @@ void BatchShotsExecutor::apply_ops_batched_shots_for_group( apply_batched_noise_ops(i_group, noise_ops_before, result_it, rng); } } - // apply base op - if (!apply_batched_op(istate, *op, result_it, rng, + // apply original op + if (op->expr || !apply_batched_op(istate, *op, result_it, rng, final_ops && (op + 1 == last))) { // call apply_op for each state for (uint_t j = 0; j < Base::num_states_in_group_[i_group]; j++) { From 413e49a375442a98d820618eeac60558b27c74aa Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Fri, 19 Apr 2024 10:33:07 +0900 Subject: [PATCH 06/18] format --- src/simulators/batch_shots_executor.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/simulators/batch_shots_executor.hpp b/src/simulators/batch_shots_executor.hpp index addb30cee8..8e829f753f 100644 --- a/src/simulators/batch_shots_executor.hpp +++ b/src/simulators/batch_shots_executor.hpp @@ -589,7 +589,7 @@ void BatchShotsExecutor::apply_ops_batched_shots_for_group( } // apply original op if (op->expr || !apply_batched_op(istate, *op, result_it, rng, - final_ops && (op + 1 == last))) { + final_ops && (op + 1 == last))) { // call apply_op for each state for (uint_t j = 0; j < Base::num_states_in_group_[i_group]; j++) { uint_t is = Base::top_state_of_group_[i_group] + j; From 8f2ff144f1446ff95d62ebb57f90a400bb5aa872 Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Fri, 19 Apr 2024 10:56:17 +0900 Subject: [PATCH 07/18] set initial value to Op structure --- src/framework/operations.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/framework/operations.hpp b/src/framework/operations.hpp index c9a5659985..811afe20cd 100644 --- a/src/framework/operations.hpp +++ b/src/framework/operations.hpp @@ -611,10 +611,10 @@ struct Op { // Conditional Operations bool conditional = false; // is gate conditional gate - uint_t conditional_reg; // (opt) the (single) register location to look up for - // conditional + uint_t conditional_reg = 0; // (opt) the (single) register location to look + // up for conditional BinaryOp binary_op; // (opt) boolean function relation - std::shared_ptr expr; // (opt) classical expression + std::shared_ptr expr = nullptr; // (opt) classical expression // Measurement reg_t memory; // (opt) register operation it acts on (measure) From e8183061a81ab5d5ee766662baf267bc21067d0f Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Fri, 19 Apr 2024 10:59:41 +0900 Subject: [PATCH 08/18] format --- src/framework/operations.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/framework/operations.hpp b/src/framework/operations.hpp index 811afe20cd..5bff6821cc 100644 --- a/src/framework/operations.hpp +++ b/src/framework/operations.hpp @@ -610,10 +610,10 @@ struct Op { string_params; // used for label, control-flow, and boolean functions // Conditional Operations - bool conditional = false; // is gate conditional gate + bool conditional = false; // is gate conditional gate uint_t conditional_reg = 0; // (opt) the (single) register location to look // up for conditional - BinaryOp binary_op; // (opt) boolean function relation + BinaryOp binary_op; // (opt) boolean function relation std::shared_ptr expr = nullptr; // (opt) classical expression // Measurement From 7ecf68212a343ec683ce58e1a4339906945f60e5 Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Fri, 19 Apr 2024 11:04:38 +0900 Subject: [PATCH 09/18] format --- src/framework/operations.hpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/framework/operations.hpp b/src/framework/operations.hpp index 5bff6821cc..1e8053669e 100644 --- a/src/framework/operations.hpp +++ b/src/framework/operations.hpp @@ -610,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 = 0; // (opt) the (single) register location to look - // up for conditional - BinaryOp binary_op; // (opt) boolean function relation - std::shared_ptr expr = nullptr; // (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 expr = nullptr; // Measurement reg_t memory; // (opt) register operation it acts on (measure) From fda34e88f1b18e298d4e46492bf59de83b010466 Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Fri, 19 Apr 2024 11:45:25 +0900 Subject: [PATCH 10/18] test --- src/simulators/multi_state_executor.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/simulators/multi_state_executor.hpp b/src/simulators/multi_state_executor.hpp index 7f80ae2645..ab8486529c 100644 --- a/src/simulators/multi_state_executor.hpp +++ b/src/simulators/multi_state_executor.hpp @@ -568,7 +568,7 @@ void MultiStateExecutor::run_circuit_with_shot_branching( // apply ops until some branch operations are executed in some branches uint_t nbranch = Utils::apply_omp_parallel_for_reduction_int( - (par_shots > 1 && branches.size() > 1 && shot_omp_parallel_), 0, + false, 0, par_shots, apply_ops_func, par_shots); // repeat until new branch is available From 09ed171bdfc4e5189242d767bb5b6a8f7886264d Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Fri, 19 Apr 2024 11:50:45 +0900 Subject: [PATCH 11/18] test --- src/simulators/multi_state_executor.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/simulators/multi_state_executor.hpp b/src/simulators/multi_state_executor.hpp index ab8486529c..89f6c4dee7 100644 --- a/src/simulators/multi_state_executor.hpp +++ b/src/simulators/multi_state_executor.hpp @@ -568,8 +568,7 @@ void MultiStateExecutor::run_circuit_with_shot_branching( // apply ops until some branch operations are executed in some branches uint_t nbranch = Utils::apply_omp_parallel_for_reduction_int( - false, 0, - par_shots, apply_ops_func, par_shots); + false, 0, par_shots, apply_ops_func, par_shots); // repeat until new branch is available if (nbranch > 0) { From 87572dcf9fee378dbfc5a727d41fd16972c5dd94 Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Fri, 19 Apr 2024 13:48:29 +0900 Subject: [PATCH 12/18] fix use of additional_ops.size() --- src/simulators/multi_state_executor.hpp | 3 ++- src/simulators/shot_branching.hpp | 5 +++- .../statevector/statevector_executor.hpp | 23 +++++++++++-------- .../tensor_network/tensor_net_executor.hpp | 23 +++++++++++-------- 4 files changed, 32 insertions(+), 22 deletions(-) diff --git a/src/simulators/multi_state_executor.hpp b/src/simulators/multi_state_executor.hpp index 89f6c4dee7..7f80ae2645 100644 --- a/src/simulators/multi_state_executor.hpp +++ b/src/simulators/multi_state_executor.hpp @@ -568,7 +568,8 @@ void MultiStateExecutor::run_circuit_with_shot_branching( // apply ops until some branch operations are executed in some branches uint_t nbranch = Utils::apply_omp_parallel_for_reduction_int( - false, 0, par_shots, apply_ops_func, par_shots); + (par_shots > 1 && branches.size() > 1 && shot_omp_parallel_), 0, + par_shots, apply_ops_func, par_shots); // repeat until new branch is available if (nbranch > 0) { diff --git a/src/simulators/shot_branching.hpp b/src/simulators/shot_branching.hpp index 8b9803df60..e8a68c045a 100644 --- a/src/simulators/shot_branching.hpp +++ b/src/simulators/shot_branching.hpp @@ -50,6 +50,8 @@ class Branch { // branches from this std::vector> branches_; + // this flag is used for initialize op + bool initialize_after_reset_ = false; public: Branch(void) { additional_op_pos_ = 0; } ~Branch() { @@ -73,6 +75,7 @@ class Branch { std::unordered_map &marks(void) { return flow_marks_; } uint_t num_branches(void) { return branches_.size(); } std::vector> &branches(void) { return branches_; } + bool& initialize_after_reset(void) { return initialize_after_reset_; } void set_iterator(OpItr &iter) { iter_ = iter; } OpItr op_iterator(void); @@ -110,7 +113,7 @@ class Branch { void branch_shots(reg_t &shots, int_t nbranch); bool apply_control_flow(ClassicalRegister &creg, OpItr last) { - if (additional_ops_.size() > 0) + if (additional_ops_.size() > additional_op_pos_) return false; if (iter_->type == Operations::OpType::mark) { diff --git a/src/simulators/statevector/statevector_executor.hpp b/src/simulators/statevector/statevector_executor.hpp index 826642fc6a..bf8a5e3399 100644 --- a/src/simulators/statevector/statevector_executor.hpp +++ b/src/simulators/statevector/statevector_executor.hpp @@ -1647,19 +1647,22 @@ void Executor::apply_initialize(CircuitExecutor::Branch &root, } } - if (root.additional_ops().size() == 0) { + if (!root.initialize_after_reset()) { apply_reset(root, qubits); - Operations::Op op; - op.type = OpType::initialize; - op.name = "initialize"; - op.qubits = qubits; - op.params = params; - for (uint_t i = 0; i < root.num_branches(); i++) { - root.branches()[i]->add_op_after_branch(op); + if (root.num_branches().size() > 0) { + Operations::Op op; + op.type = OpType::initialize; + op.name = "initialize"; + op.qubits = qubits; + op.params = params; + for (uint_t i = 0; i < root.num_branches(); i++) { + root.branches()[i]->add_op_after_branch(op); + root.branches()[i]->initialize_after_reset() = true; + } + return; // initialization will be done in next call because of shot + // branching in reset } - return; // initialization will be done in next call because of shot - // branching in reset } Base::states_[root.state_index()].qreg().initialize_component(qubits, params); diff --git a/src/simulators/tensor_network/tensor_net_executor.hpp b/src/simulators/tensor_network/tensor_net_executor.hpp index 5bcc47532f..b08798294f 100644 --- a/src/simulators/tensor_network/tensor_net_executor.hpp +++ b/src/simulators/tensor_network/tensor_net_executor.hpp @@ -276,19 +276,22 @@ void Executor::apply_initialize(CircuitExecutor::Branch &root, } } - if (root.additional_ops().size() == 0) { + if (!root.initialize_after_reset()) { apply_reset(root, qubits); - Operations::Op op; - op.type = OpType::initialize; - op.name = "initialize"; - op.qubits = qubits; - op.params = params; - for (uint_t i = 0; i < root.num_branches(); i++) { - root.branches()[i]->add_op_after_branch(op); + if (root.num_branches().size() > 0) { + Operations::Op op; + op.type = OpType::initialize; + op.name = "initialize"; + op.qubits = qubits; + op.params = params; + for (uint_t i = 0; i < root.num_branches(); i++) { + root.branches()[i]->add_op_after_branch(op); + root.branches()[i]->initialize_after_reset() = true; + } + return; // initialization will be done in next call because of shot + // branching in reset } - return; // initialization will be done in next call because of shot - // branching in reset } Base::states_[root.state_index()].qreg().initialize_component(qubits, params); From b67d1eddd15092ba1d6f4a89adaa6f19f8abdaab Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Fri, 19 Apr 2024 13:55:24 +0900 Subject: [PATCH 13/18] fix error --- src/simulators/shot_branching.hpp | 3 ++- src/simulators/statevector/statevector_executor.hpp | 2 +- src/simulators/tensor_network/tensor_net_executor.hpp | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/simulators/shot_branching.hpp b/src/simulators/shot_branching.hpp index e8a68c045a..d160ca93fc 100644 --- a/src/simulators/shot_branching.hpp +++ b/src/simulators/shot_branching.hpp @@ -52,6 +52,7 @@ class Branch { // this flag is used for initialize op bool initialize_after_reset_ = false; + public: Branch(void) { additional_op_pos_ = 0; } ~Branch() { @@ -75,7 +76,7 @@ class Branch { std::unordered_map &marks(void) { return flow_marks_; } uint_t num_branches(void) { return branches_.size(); } std::vector> &branches(void) { return branches_; } - bool& initialize_after_reset(void) { return initialize_after_reset_; } + bool &initialize_after_reset(void) { return initialize_after_reset_; } void set_iterator(OpItr &iter) { iter_ = iter; } OpItr op_iterator(void); diff --git a/src/simulators/statevector/statevector_executor.hpp b/src/simulators/statevector/statevector_executor.hpp index bf8a5e3399..26b00e801e 100644 --- a/src/simulators/statevector/statevector_executor.hpp +++ b/src/simulators/statevector/statevector_executor.hpp @@ -1650,7 +1650,7 @@ void Executor::apply_initialize(CircuitExecutor::Branch &root, if (!root.initialize_after_reset()) { apply_reset(root, qubits); - if (root.num_branches().size() > 0) { + if (root.num_branches() > 0) { Operations::Op op; op.type = OpType::initialize; op.name = "initialize"; diff --git a/src/simulators/tensor_network/tensor_net_executor.hpp b/src/simulators/tensor_network/tensor_net_executor.hpp index b08798294f..cd147e0797 100644 --- a/src/simulators/tensor_network/tensor_net_executor.hpp +++ b/src/simulators/tensor_network/tensor_net_executor.hpp @@ -279,7 +279,7 @@ void Executor::apply_initialize(CircuitExecutor::Branch &root, if (!root.initialize_after_reset()) { apply_reset(root, qubits); - if (root.num_branches().size() > 0) { + if (root.num_branches() > 0) { Operations::Op op; op.type = OpType::initialize; op.name = "initialize"; From 996e3e6b8bc2134b883c34ff8157d73896f8895b Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Fri, 19 Apr 2024 14:02:41 +0900 Subject: [PATCH 14/18] fix remove_empty_branches --- src/simulators/shot_branching.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/simulators/shot_branching.hpp b/src/simulators/shot_branching.hpp index d160ca93fc..e68f1ea468 100644 --- a/src/simulators/shot_branching.hpp +++ b/src/simulators/shot_branching.hpp @@ -394,6 +394,7 @@ void Branch::remove_empty_branches(void) { param_index_ = branches_[iroot]->param_index_; param_shots_ = branches_[iroot]->param_shots_; creg_ = branches_[iroot]->creg(); + initialize_after_reset_ = branches_[iroot]->initialize_after_reset_; std::vector> new_branches; for (uint_t j = iroot; j < branches_.size(); j++) { From f549045ed900adcc3e61b0950b6a5abe1421d739 Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Fri, 19 Apr 2024 15:03:07 +0900 Subject: [PATCH 15/18] test --- src/simulators/shot_branching.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/simulators/shot_branching.hpp b/src/simulators/shot_branching.hpp index e68f1ea468..23c55bb4cf 100644 --- a/src/simulators/shot_branching.hpp +++ b/src/simulators/shot_branching.hpp @@ -415,6 +415,7 @@ void Branch::remove_empty_branches(void) { additional_ops_ = branches_[iroot]->additional_ops_; additional_op_pos_ = 0; branches_[iroot].reset(); + branches_.clear(); branches_ = new_branches; } From 5592671f20389f6ea1e91a958a342809882349f8 Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Fri, 19 Apr 2024 15:27:17 +0900 Subject: [PATCH 16/18] test --- src/simulators/multi_state_executor.hpp | 1 + src/simulators/shot_branching.hpp | 6 ------ 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/simulators/multi_state_executor.hpp b/src/simulators/multi_state_executor.hpp index 7f80ae2645..6ec202d26d 100644 --- a/src/simulators/multi_state_executor.hpp +++ b/src/simulators/multi_state_executor.hpp @@ -484,6 +484,7 @@ void MultiStateExecutor::run_circuit_with_shot_branching( reg_t num_shots_saved(Base::num_bind_params_, 0); + shot_omp_parallel_ = false; // loop until all local shots are simulated while (waiting_branches.size() > 0) { uint_t num_active_states = 1; diff --git a/src/simulators/shot_branching.hpp b/src/simulators/shot_branching.hpp index 23c55bb4cf..ab6805ec25 100644 --- a/src/simulators/shot_branching.hpp +++ b/src/simulators/shot_branching.hpp @@ -104,12 +104,6 @@ class Branch { void add_ops_after_branch(std::vector &ops) { additional_ops_.insert(additional_ops_.end(), ops.begin(), ops.end()); } - void clear_additional_ops(void) { - additional_ops_.clear(); - additional_op_pos_ = 0; - } - - std::vector &additional_ops(void) { return additional_ops_; } void branch_shots(reg_t &shots, int_t nbranch); From 57f8eace84e7ae49e1185a5f7fb579f7056cb507 Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Fri, 19 Apr 2024 15:27:27 +0900 Subject: [PATCH 17/18] test --- src/simulators/multi_state_executor.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/simulators/multi_state_executor.hpp b/src/simulators/multi_state_executor.hpp index 6ec202d26d..82b618f039 100644 --- a/src/simulators/multi_state_executor.hpp +++ b/src/simulators/multi_state_executor.hpp @@ -484,7 +484,7 @@ void MultiStateExecutor::run_circuit_with_shot_branching( reg_t num_shots_saved(Base::num_bind_params_, 0); - shot_omp_parallel_ = false; + shot_omp_parallel_ = false; // loop until all local shots are simulated while (waiting_branches.size() > 0) { uint_t num_active_states = 1; From 04d9d43fdffaba4b57c5a54a1cc276f9e082f309 Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Fri, 19 Apr 2024 15:50:48 +0900 Subject: [PATCH 18/18] test --- src/framework/operations.hpp | 1 - src/simulators/multi_state_executor.hpp | 1 - 2 files changed, 2 deletions(-) diff --git a/src/framework/operations.hpp b/src/framework/operations.hpp index 1e8053669e..484dd3660a 100644 --- a/src/framework/operations.hpp +++ b/src/framework/operations.hpp @@ -1326,7 +1326,6 @@ inline Op bind_parameter(const Op &src, const uint_t iparam, op.string_params = src.string_params; op.conditional = src.conditional; op.conditional_reg = src.conditional_reg; - op.sample_noise = src.sample_noise; op.binary_op = src.binary_op; op.expr = src.expr; op.has_bind_params = false; diff --git a/src/simulators/multi_state_executor.hpp b/src/simulators/multi_state_executor.hpp index 82b618f039..7f80ae2645 100644 --- a/src/simulators/multi_state_executor.hpp +++ b/src/simulators/multi_state_executor.hpp @@ -484,7 +484,6 @@ void MultiStateExecutor::run_circuit_with_shot_branching( reg_t num_shots_saved(Base::num_bind_params_, 0); - shot_omp_parallel_ = false; // loop until all local shots are simulated while (waiting_branches.size() > 0) { uint_t num_active_states = 1;