From 0de759ef371f4b9110b0412e8de3fc7058430cdb Mon Sep 17 00:00:00 2001 From: eliotheinrich <38039898+eliotheinrich@users.noreply.github.com> Date: Thu, 23 Nov 2023 20:48:35 -0500 Subject: [PATCH 1/2] Fix extended stabilizer thread safety in apply_ops_parallel (#1993) * Extended stabilizer simulator no longer shares RngEngine amongst states when ops are applied in parallel * Added release note * Fixed ugly cast --------- Co-authored-by: Jun Doi --- ...fix_extstabilizer_thread_safety-c85e926c7ecb8dfb.yaml | 6 ++++++ .../extended_stabilizer/extended_stabilizer_state.hpp | 9 ++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 releasenotes/notes/fix_extstabilizer_thread_safety-c85e926c7ecb8dfb.yaml diff --git a/releasenotes/notes/fix_extstabilizer_thread_safety-c85e926c7ecb8dfb.yaml b/releasenotes/notes/fix_extstabilizer_thread_safety-c85e926c7ecb8dfb.yaml new file mode 100644 index 0000000000..2551b8bc47 --- /dev/null +++ b/releasenotes/notes/fix_extstabilizer_thread_safety-c85e926c7ecb8dfb.yaml @@ -0,0 +1,6 @@ +fixes: + - | + Extended stabilizer simulation was sharing a single copy of RngEngine amongst + parallelized states in ``ExtendedStabilizer::State::apply_ops_parallel``, + leading to thread safety issue. Now, a new RngEngine is seeded for each parallel + state. \ No newline at end of file diff --git a/src/simulators/extended_stabilizer/extended_stabilizer_state.hpp b/src/simulators/extended_stabilizer/extended_stabilizer_state.hpp index 86947f9b5a..be6a8af609 100644 --- a/src/simulators/extended_stabilizer/extended_stabilizer_state.hpp +++ b/src/simulators/extended_stabilizer/extended_stabilizer_state.hpp @@ -463,6 +463,12 @@ template void State::apply_ops_parallel(InputIterator first, InputIterator last, ExperimentResult &result, RngEngine &rng) { const int_t NUM_STATES = BaseState::qreg_.get_num_states(); + + std::vector rng_seeds(NUM_STATES); + for (int_t i = 0; i < NUM_STATES; i++) { + rng_seeds[i] = rng.rand_int(0, SIZE_MAX); + } + #pragma omp parallel for if (BaseState::qreg_.check_omp_threshold() && \ BaseState::threads_ > 1) \ num_threads(BaseState::threads_) @@ -470,10 +476,11 @@ void State::apply_ops_parallel(InputIterator first, InputIterator last, if (!BaseState::qreg_.check_eps(i)) { continue; } + RngEngine local_rng(rng_seeds[i]); for (auto it = first; it != last; it++) { switch (it->type) { case Operations::OpType::gate: - apply_gate(*it, rng, i); + apply_gate(*it, local_rng, i); break; case Operations::OpType::barrier: case Operations::OpType::qerror_loc: From 3e8ba713afb529512dbaaf76265a4264781abc98 Mon Sep 17 00:00:00 2001 From: Ikko Hamamura Date: Fri, 24 Nov 2023 11:39:49 +0900 Subject: [PATCH 2/2] add note (#1992) Co-authored-by: Jun Doi --- qiskit_aer/primitives/estimator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit_aer/primitives/estimator.py b/qiskit_aer/primitives/estimator.py index 14f5749469..17bdfa7ba1 100644 --- a/qiskit_aer/primitives/estimator.py +++ b/qiskit_aer/primitives/estimator.py @@ -91,7 +91,7 @@ def __init__( transpile_options: Options passed to transpile. run_options: Options passed to run. approximation: If True, it calculates expectation values with normal distribution - approximation. + approximation. Note that this appproximation ignores readout errors. skip_transpilation: If True, transpilation is skipped. abelian_grouping: Whether the observable should be grouped into commuting. If approximation is True, this parameter is ignored and assumed to be False.