From b56c1d7a5ecefe713620782a7fc9a4db7ea25fe0 Mon Sep 17 00:00:00 2001 From: Craig Gidney Date: Sat, 19 Aug 2023 16:29:21 -0700 Subject: [PATCH] Refactor RNG ownership semantics (#611) - Change `stim::TableauSimulator`'s constructor to require a move-reference for its rng - Change `stim::FrameSimulator`'s constructor to require a move-reference for its rng - Change `stim::FrameSimulator`'s RNG from a reference to a normal object owned by the simulator - Replace SHARED_TEST_RNG method with INDEPENDENT_TEST_RNG method - Rewrite all tests to use INDEPENDENT_TEST_RNG, fixing potential overlaps in randomness - Also fix some `pybind11::args args` -> `const pybind11::args &args` warnings - Also fix some int vs size_t comparison warnings Fixes https://github.com/quantumlib/Stim/issues/353 --- glue/javascript/common.js.cc | 11 - glue/javascript/common.js.h | 2 - glue/javascript/pauli_string.js.cc | 3 +- glue/javascript/tableau.js.cc | 3 +- glue/javascript/tableau_simulator.js.cc | 2 +- src/stim/circuit/gate_data.test.cc | 10 +- src/stim/circuit/stabilizer_flow.test.cc | 3 +- src/stim/cmd/command_gen.test.cc | 3 +- src/stim/cmd/command_sample.cc | 3 +- src/stim/dem/detector_error_model.pybind.cc | 2 +- src/stim/io/measure_record_reader.test.cc | 17 +- src/stim/mem/simd_bit_table.h | 3 + src/stim/mem/simd_bit_table.test.cc | 12 +- src/stim/mem/simd_bits.test.cc | 32 +- src/stim/mem/simd_bits_range_ref.inl | 4 +- src/stim/mem/simd_bits_range_ref.test.cc | 28 +- src/stim/mem/simd_util.test.cc | 10 +- src/stim/mem/simd_word.test.cc | 2 +- src/stim/probability_util.test.cc | 11 +- src/stim/py/base.pybind.cc | 6 +- src/stim/py/base.pybind.h | 2 +- .../py/compiled_detector_sampler.pybind.cc | 7 +- .../py/compiled_detector_sampler.pybind.h | 3 +- .../py/compiled_measurement_sampler.pybind.cc | 12 +- .../py/compiled_measurement_sampler.pybind.h | 4 +- .../count_determined_measurements.inl | 3 +- src/stim/simulators/dem_sampler.test.cc | 4 +- src/stim/simulators/error_analyzer.test.cc | 2 +- src/stim/simulators/frame_simulator.h | 4 +- src/stim/simulators/frame_simulator.inl | 4 +- src/stim/simulators/frame_simulator.perf.cc | 19 +- src/stim/simulators/frame_simulator.test.cc | 215 ++++++++------ src/stim/simulators/frame_simulator_util.inl | 16 +- .../simulators/frame_simulator_util.test.cc | 30 +- .../measurements_to_detection_events.inl | 7 +- .../sparse_rev_frame_tracker.test.cc | 2 +- src/stim/simulators/tableau_simulator.h | 4 +- src/stim/simulators/tableau_simulator.inl | 4 +- src/stim/simulators/tableau_simulator.perf.cc | 3 +- .../simulators/tableau_simulator.pybind.cc | 74 ++--- src/stim/simulators/tableau_simulator.test.cc | 274 ++++++++++-------- src/stim/stabilizers/conversions.inl | 6 +- src/stim/stabilizers/conversions.test.cc | 20 +- src/stim/stabilizers/pauli_string.pybind.cc | 2 +- src/stim/stabilizers/pauli_string.test.cc | 3 +- src/stim/stabilizers/tableau.pybind.cc | 6 +- src/stim/stabilizers/tableau.test.cc | 54 ++-- src/stim/test_util.test.cc | 5 +- src/stim/test_util.test.h | 2 +- 49 files changed, 526 insertions(+), 432 deletions(-) diff --git a/glue/javascript/common.js.cc b/glue/javascript/common.js.cc index 7b13631e8..084ed9098 100644 --- a/glue/javascript/common.js.cc +++ b/glue/javascript/common.js.cc @@ -2,17 +2,6 @@ using namespace stim; -static bool shared_rng_initialized; -static std::mt19937_64 shared_rng; - -std::mt19937_64 &JS_BIND_SHARED_RNG() { - if (!shared_rng_initialized) { - shared_rng = externally_seeded_rng(); - shared_rng_initialized = true; - } - return shared_rng; -} - uint32_t js_val_to_uint32_t(const emscripten::val &val) { double v = val.as(); double f = floor(v); diff --git a/glue/javascript/common.js.h b/glue/javascript/common.js.h index b8b825bd2..bf2710717 100644 --- a/glue/javascript/common.js.h +++ b/glue/javascript/common.js.h @@ -5,8 +5,6 @@ #include "stim/probability_util.h" -std::mt19937_64 &JS_BIND_SHARED_RNG(); - template emscripten::val vec_to_js_array(const std::vector &items) { emscripten::val result = emscripten::val::array(); diff --git a/glue/javascript/pauli_string.js.cc b/glue/javascript/pauli_string.js.cc index fe5620cd7..f700eafe4 100644 --- a/glue/javascript/pauli_string.js.cc +++ b/glue/javascript/pauli_string.js.cc @@ -21,7 +21,8 @@ ExposedPauliString::ExposedPauliString(const emscripten::val &arg) : pauli_strin } ExposedPauliString ExposedPauliString::random(size_t n) { - return ExposedPauliString(PauliString::random(n, JS_BIND_SHARED_RNG())); + auto rng = externally_seeded_rng(); + return ExposedPauliString(PauliString::random(n, rng)); } ExposedPauliString ExposedPauliString::times(const ExposedPauliString &other) const { diff --git a/glue/javascript/tableau.js.cc b/glue/javascript/tableau.js.cc index c29ade7d6..e31a2cbb6 100644 --- a/glue/javascript/tableau.js.cc +++ b/glue/javascript/tableau.js.cc @@ -14,7 +14,8 @@ ExposedTableau::ExposedTableau(int n) : tableau(n) { } ExposedTableau ExposedTableau::random(int n) { - return ExposedTableau(Tableau::random(n, JS_BIND_SHARED_RNG())); + auto rng = externally_seeded_rng(); + return ExposedTableau(Tableau::random(n, rng)); } ExposedTableau ExposedTableau::from_named_gate(const std::string &name) { diff --git a/glue/javascript/tableau_simulator.js.cc b/glue/javascript/tableau_simulator.js.cc index c4c087d1d..7fb6d8e19 100644 --- a/glue/javascript/tableau_simulator.js.cc +++ b/glue/javascript/tableau_simulator.js.cc @@ -58,7 +58,7 @@ static JsCircuitInstruction args_to_target_pairs(TableauSimulator>, std::vector>> circuit_outp if (circuit.count_measurements() > 1) { throw std::invalid_argument("count_measurements > 1"); } - TableauSimulator sim1(SHARED_TEST_RNG(), circuit.count_qubits(), -1); - TableauSimulator sim2(SHARED_TEST_RNG(), circuit.count_qubits(), +1); + TableauSimulator sim1(INDEPENDENT_TEST_RNG(), circuit.count_qubits(), -1); + TableauSimulator sim2(INDEPENDENT_TEST_RNG(), circuit.count_qubits(), +1); sim1.expand_do_circuit(circuit); sim2.expand_do_circuit(circuit); return {sim1.canonical_stabilizers(), sim2.canonical_stabilizers()}; @@ -163,7 +163,8 @@ TEST_EACH_WORD_SIZE_W(gate_data, stabilizer_flows_are_correct, { Circuit c; c.safe_append(g.id, targets, {}); - auto r = check_if_circuit_has_stabilizer_flows(256, SHARED_TEST_RNG(), c, flows); + auto rng = INDEPENDENT_TEST_RNG(); + auto r = check_if_circuit_has_stabilizer_flows(256, rng, c, flows); for (uint32_t fk = 0; fk < (uint32_t)flows.size(); fk++) { EXPECT_TRUE(r[fk]) << "gate " << g.name << " has an unsatisfied flow: " << flows[fk]; } @@ -171,6 +172,7 @@ TEST_EACH_WORD_SIZE_W(gate_data, stabilizer_flows_are_correct, { }) TEST_EACH_WORD_SIZE_W(gate_data, stabilizer_flows_are_also_correct_for_decomposed_circuit, { + auto rng = INDEPENDENT_TEST_RNG(); for (const auto &g : GATE_DATA.items) { auto flows = g.flows(); if (flows.empty()) { @@ -194,7 +196,7 @@ TEST_EACH_WORD_SIZE_W(gate_data, stabilizer_flows_are_also_correct_for_decompose } Circuit c(g.extra_data_func().h_s_cx_m_r_decomposition); - auto r = check_if_circuit_has_stabilizer_flows(256, SHARED_TEST_RNG(), c, flows); + auto r = check_if_circuit_has_stabilizer_flows(256, rng, c, flows); for (uint32_t fk = 0; fk < (uint32_t)flows.size(); fk++) { EXPECT_TRUE(r[fk]) << "gate " << g.name << " has a decomposition with an unsatisfied flow: " << flows[fk]; } diff --git a/src/stim/circuit/stabilizer_flow.test.cc b/src/stim/circuit/stabilizer_flow.test.cc index ca0c98b42..f48a5b1ca 100644 --- a/src/stim/circuit/stabilizer_flow.test.cc +++ b/src/stim/circuit/stabilizer_flow.test.cc @@ -23,9 +23,10 @@ using namespace stim; TEST_EACH_WORD_SIZE_W(stabilizer_flow, check_if_circuit_has_stabilizer_flows, { + auto rng = INDEPENDENT_TEST_RNG(); auto results = check_if_circuit_has_stabilizer_flows( 256, - SHARED_TEST_RNG(), + rng, Circuit(R"CIRCUIT( R 4 CX 0 4 1 4 2 4 3 4 diff --git a/src/stim/cmd/command_gen.test.cc b/src/stim/cmd/command_gen.test.cc index 8e98145bf..0dd86ce18 100644 --- a/src/stim/cmd/command_gen.test.cc +++ b/src/stim/cmd/command_gen.test.cc @@ -45,7 +45,8 @@ TEST_EACH_WORD_SIZE_W(command_gen, no_noise_no_detections, { } CircuitGenParameters params(r, d, func.second.first); auto circuit = func.second.second(params).circuit; - auto [det_samples, obs_samples] = sample_batch_detection_events(circuit, 256, SHARED_TEST_RNG()); + auto rng = INDEPENDENT_TEST_RNG(); + auto [det_samples, obs_samples] = sample_batch_detection_events(circuit, 256, rng); EXPECT_FALSE(det_samples.data.not_zero() || obs_samples.data.not_zero()) << "d=" << d << ", r=" << r << ", task=" << func.second.first << ", func=" << func.first; } diff --git a/src/stim/cmd/command_sample.cc b/src/stim/cmd/command_sample.cc index 1b873553a..4a9b52a23 100644 --- a/src/stim/cmd/command_sample.cc +++ b/src/stim/cmd/command_sample.cc @@ -51,7 +51,8 @@ int stim::command_sample(int argc, const char **argv) { if (num_shots == 1 && !skip_reference_sample) { TableauSimulator::sample_stream(in, out, out_format.id, false, rng); - } else if (num_shots > 0) { + } else { + assert(num_shots > 0); auto circuit = Circuit::from_file(in); simd_bits ref(0); if (!skip_reference_sample) { diff --git a/src/stim/dem/detector_error_model.pybind.cc b/src/stim/dem/detector_error_model.pybind.cc index 65dee9125..cf546a7c1 100644 --- a/src/stim/dem/detector_error_model.pybind.cc +++ b/src/stim/dem/detector_error_model.pybind.cc @@ -997,7 +997,7 @@ void stim_pybind::pybind_detector_error_model_methods( c.def( "compile_sampler", [](const DetectorErrorModel &self, const pybind11::object &seed) -> DemSampler { - return DemSampler(self, *make_py_seeded_rng(seed), 1024); + return DemSampler(self, make_py_seeded_rng(seed), 1024); }, pybind11::kw_only(), pybind11::arg("seed") = pybind11::none(), diff --git a/src/stim/io/measure_record_reader.test.cc b/src/stim/io/measure_record_reader.test.cc index 98f1254b0..a5e94f5a7 100644 --- a/src/stim/io/measure_record_reader.test.cc +++ b/src/stim/io/measure_record_reader.test.cc @@ -453,7 +453,8 @@ TEST_EACH_WORD_SIZE_W(MeasureRecordReader, read_records_into_RoundTrip, { size_t n_shots = 100; size_t n_results = 512 - 8; - auto shot_maj_data = simd_bit_table::random(n_shots, n_results, SHARED_TEST_RNG()); + auto rng = INDEPENDENT_TEST_RNG(); + auto shot_maj_data = simd_bit_table::random(n_shots, n_results, rng); auto shot_min_data = shot_maj_data.transposed(); for (const auto &kv : format_name_to_enum_map()) { SampleFormat format = kv.second.id; @@ -556,13 +557,14 @@ TEST_EACH_WORD_SIZE_W(MeasureRecordReader, read_b8_detection_event_data_full_run }) TEST_EACH_WORD_SIZE_W(MeasureRecordReader, start_and_read_entire_record, { + auto rng = INDEPENDENT_TEST_RNG(); size_t n = 512 - 8; size_t no = 5; size_t nd = n - no; // Compute expected data. simd_bits test_data(n); - biased_randomize_bits(0.1, test_data.u64, test_data.u64 + test_data.num_u64_padded(), SHARED_TEST_RNG()); + biased_randomize_bits(0.1, test_data.u64, test_data.u64 + test_data.num_u64_padded(), rng); SparseShot sparse_test_data; sparse_test_data.obs_mask = simd_bits<64>(no); for (size_t k = 0; k < nd; k++) { @@ -660,9 +662,10 @@ TEST_EACH_WORD_SIZE_W(MeasureRecordReader, start_and_read_entire_record_all_zero }) TEST_EACH_WORD_SIZE_W(MeasureRecordReader, start_and_read_entire_record_ptb64_dense, { + auto rng = INDEPENDENT_TEST_RNG(); FILE *f = tmpfile(); - auto saved1 = simd_bits::random(64 * 71, SHARED_TEST_RNG()); - auto saved2 = simd_bits::random(64 * 71, SHARED_TEST_RNG()); + auto saved1 = simd_bits::random(64 * 71, rng); + auto saved2 = simd_bits::random(64 * 71, rng); for (size_t k = 0; k < 64 * 71 / 8; k++) { putc(saved1.u8[k], f); } @@ -689,12 +692,13 @@ TEST_EACH_WORD_SIZE_W(MeasureRecordReader, start_and_read_entire_record_ptb64_de }) TEST_EACH_WORD_SIZE_W(MeasureRecordReader, start_and_read_entire_record_ptb64_sparse, { + auto rng = INDEPENDENT_TEST_RNG(); FILE *tmp = tmpfile(); simd_bit_table ground_truth(71, 64 * 5); { MeasureRecordBatchWriter writer(tmp, 64 * 5, stim::SAMPLE_FORMAT_PTB64); for (size_t k = 0; k < 71; k++) { - ground_truth[k].randomize(64 * 5, SHARED_TEST_RNG()); + ground_truth[k].randomize(64 * 5, rng); writer.batch_write_bit(ground_truth[k]); } writer.write_end(); @@ -719,6 +723,7 @@ TEST_EACH_WORD_SIZE_W(MeasureRecordReader, start_and_read_entire_record_ptb64_sp }) TEST_EACH_WORD_SIZE_W(MeasureRecordReader, read_file_data_into_shot_table_vs_write_table, { + auto rng = INDEPENDENT_TEST_RNG(); for (const auto &format_data : format_name_to_enum_map()) { SampleFormat format = format_data.second.id; size_t num_shots = 500; @@ -729,7 +734,7 @@ TEST_EACH_WORD_SIZE_W(MeasureRecordReader, read_file_data_into_shot_table_vs_wri simd_bit_table expected(num_shots, bits_per_shot); for (size_t shot = 0; shot < num_shots; shot++) { - expected[shot].randomize(bits_per_shot, SHARED_TEST_RNG()); + expected[shot].randomize(bits_per_shot, rng); } simd_bit_table expected_transposed = expected.transposed(); diff --git a/src/stim/mem/simd_bit_table.h b/src/stim/mem/simd_bit_table.h index 0bb2969bf..e2ee5a6be 100644 --- a/src/stim/mem/simd_bit_table.h +++ b/src/stim/mem/simd_bit_table.h @@ -108,6 +108,9 @@ struct simd_bit_table { /// Returns a subset of the table. simd_bit_table slice_maj(size_t maj_start_bit, size_t maj_stop_bit) const; + /// Returns a copy of a column of the table. + simd_bits read_across_majors_at_minor_index(size_t major_start, size_t major_stop, size_t minor_index) const; + /// Concatenates the contents of the two tables, along the major axis. simd_bit_table concat_major(const simd_bit_table &second, size_t n_first, size_t n_second) const; /// Overwrites a range of the table with a range from another table with the same minor size. diff --git a/src/stim/mem/simd_bit_table.test.cc b/src/stim/mem/simd_bit_table.test.cc index 3abd0fbfd..5e6537a12 100644 --- a/src/stim/mem/simd_bit_table.test.cc +++ b/src/stim/mem/simd_bit_table.test.cc @@ -200,18 +200,19 @@ TEST_EACH_WORD_SIZE_W(simd_bit_table, transposed, { }) TEST_EACH_WORD_SIZE_W(simd_bit_table, random, { - auto t = simd_bit_table::random(100, 90, SHARED_TEST_RNG()); + auto rng = INDEPENDENT_TEST_RNG(); + auto t = simd_bit_table::random(100, 90, rng); ASSERT_NE(t[99], simd_bits(90)); ASSERT_EQ(t[100], simd_bits(90)); t = t.transposed(); ASSERT_NE(t[89], simd_bits(100)); ASSERT_EQ(t[90], simd_bits(100)); - ASSERT_NE( - simd_bit_table::random(10, 10, SHARED_TEST_RNG()), simd_bit_table::random(10, 10, SHARED_TEST_RNG())); + ASSERT_NE(simd_bit_table::random(10, 10, rng), simd_bit_table::random(10, 10, rng)); }) TEST_EACH_WORD_SIZE_W(simd_bit_table, slice_maj, { - auto m = simd_bit_table::random(100, 64, SHARED_TEST_RNG()); + auto rng = INDEPENDENT_TEST_RNG(); + auto m = simd_bit_table::random(100, 64, rng); auto s = m.slice_maj(5, 15); ASSERT_EQ(s[0], m[5]); ASSERT_EQ(s[9], m[14]); @@ -291,7 +292,8 @@ TEST(simd_bit_table, lg) { } TEST_EACH_WORD_SIZE_W(simd_bit_table, destructive_resize, { - simd_bit_table table = table.random(5, 7, SHARED_TEST_RNG()); + auto rng = INDEPENDENT_TEST_RNG(); + simd_bit_table table = table.random(5, 7, rng); const uint8_t *prev_pointer = table.data.u8; table.destructive_resize(5, 7); ASSERT_EQ(table.data.u8, prev_pointer); diff --git a/src/stim/mem/simd_bits.test.cc b/src/stim/mem/simd_bits.test.cc index 6cdfcefed..62b9eb9c9 100644 --- a/src/stim/mem/simd_bits.test.cc +++ b/src/stim/mem/simd_bits.test.cc @@ -123,7 +123,8 @@ TEST_EACH_WORD_SIZE_W(simd_bits, str, { TEST_EACH_WORD_SIZE_W(simd_bits, randomize, { simd_bits d(1024); - d.randomize(64 + 57, SHARED_TEST_RNG()); + auto rng = INDEPENDENT_TEST_RNG(); + d.randomize(64 + 57, rng); uint64_t mask = (1ULL << 57) - 1; // Randomized. ASSERT_NE(d.u64[0], 0); @@ -138,7 +139,7 @@ TEST_EACH_WORD_SIZE_W(simd_bits, randomize, { for (size_t k = 0; k < d.num_u64_padded(); k++) { d.u64[k] = UINT64_MAX; } - d.randomize(64 + 57, SHARED_TEST_RNG()); + d.randomize(64 + 57, rng); // Randomized. ASSERT_NE(d.u64[0], 0); ASSERT_NE(d.u64[0], SIZE_MAX); @@ -151,8 +152,9 @@ TEST_EACH_WORD_SIZE_W(simd_bits, randomize, { }) TEST_EACH_WORD_SIZE_W(simd_bits, xor_assignment, { - simd_bits m0 = simd_bits::random(512, SHARED_TEST_RNG()); - simd_bits m1 = simd_bits::random(512, SHARED_TEST_RNG()); + auto rng = INDEPENDENT_TEST_RNG(); + simd_bits m0 = simd_bits::random(512, rng); + simd_bits m1 = simd_bits::random(512, rng); simd_bits m2(512); m2 ^= m0; ASSERT_EQ(m0, m2); @@ -284,7 +286,7 @@ TEST_EACH_WORD_SIZE_W(simd_bits, right_shift_assignment, { }) TEST_EACH_WORD_SIZE_W(simd_bits, fuzz_right_shift_assignment, { - auto rng = SHARED_TEST_RNG(); + auto rng = INDEPENDENT_TEST_RNG(); for (int i = 0; i < 5; i++) { std::uniform_int_distribution dist_bits(1, 1200); int num_bits = dist_bits(rng); @@ -334,7 +336,7 @@ TEST_EACH_WORD_SIZE_W(simd_bits, left_shift_assignment, { }) TEST_EACH_WORD_SIZE_W(simd_bits, fuzz_left_shift_assignment, { - auto rng = SHARED_TEST_RNG(); + auto rng = INDEPENDENT_TEST_RNG(); for (int i = 0; i < 5; i++) { std::uniform_int_distribution dist_bits(1, 1200); int num_bits = dist_bits(rng); @@ -356,8 +358,9 @@ TEST_EACH_WORD_SIZE_W(simd_bits, fuzz_left_shift_assignment, { TEST_EACH_WORD_SIZE_W(simd_bits, assignment, { simd_bits m0(512); simd_bits m1(512); - m0.randomize(512, SHARED_TEST_RNG()); - m1.randomize(512, SHARED_TEST_RNG()); + auto rng = INDEPENDENT_TEST_RNG(); + m0.randomize(512, rng); + m1.randomize(512, rng); auto old_m1 = m1.u64[0]; ASSERT_NE(m0, m1); m0 = m1; @@ -389,8 +392,9 @@ TEST_EACH_WORD_SIZE_W(simd_bits, swap_with, { simd_bits m1(512); simd_bits m2(512); simd_bits m3(512); - m0.randomize(512, SHARED_TEST_RNG()); - m1.randomize(512, SHARED_TEST_RNG()); + auto rng = INDEPENDENT_TEST_RNG(); + m0.randomize(512, rng); + m1.randomize(512, rng); m2 = m0; m3 = m1; ASSERT_EQ(m0, m2); @@ -402,7 +406,8 @@ TEST_EACH_WORD_SIZE_W(simd_bits, swap_with, { TEST_EACH_WORD_SIZE_W(simd_bits, clear, { simd_bits m0(512); - m0.randomize(512, SHARED_TEST_RNG()); + auto rng = INDEPENDENT_TEST_RNG(); + m0.randomize(512, rng); ASSERT_TRUE(m0.not_zero()); m0.clear(); ASSERT_TRUE(!m0.not_zero()); @@ -471,8 +476,9 @@ TEST_EACH_WORD_SIZE_W(simd_bits, mask_assignment_or, { }) TEST_EACH_WORD_SIZE_W(simd_bits, truncated_overwrite_from, { - simd_bits dat = simd_bits::random(1024, SHARED_TEST_RNG()); - simd_bits mut = simd_bits::random(1024, SHARED_TEST_RNG()); + auto rng = INDEPENDENT_TEST_RNG(); + simd_bits dat = simd_bits::random(1024, rng); + simd_bits mut = simd_bits::random(1024, rng); simd_bits old = mut; mut.truncated_overwrite_from(dat, 455); diff --git a/src/stim/mem/simd_bits_range_ref.inl b/src/stim/mem/simd_bits_range_ref.inl index 4ca657975..46fc514bd 100644 --- a/src/stim/mem/simd_bits_range_ref.inl +++ b/src/stim/mem/simd_bits_range_ref.inl @@ -103,7 +103,7 @@ simd_bits_range_ref simd_bits_range_ref::operator<<=(int offset) { } while (offset >= 64) { incoming_word = 0ULL; - for (int w = 0; w < num_u64_padded(); w++) { + for (size_t w = 0; w < num_u64_padded(); w++) { cur_word = u64[w]; u64[w] = incoming_word; incoming_word = cur_word; @@ -114,7 +114,7 @@ simd_bits_range_ref simd_bits_range_ref::operator<<=(int offset) { return *this; } incoming_word = 0ULL; - for (int w = 0; w < num_u64_padded(); w++) { + for (size_t w = 0; w < num_u64_padded(); w++) { cur_word = u64[w]; u64[w] <<= offset; u64[w] |= incoming_word; diff --git a/src/stim/mem/simd_bits_range_ref.test.cc b/src/stim/mem/simd_bits_range_ref.test.cc index f23f2ae99..235b85d69 100644 --- a/src/stim/mem/simd_bits_range_ref.test.cc +++ b/src/stim/mem/simd_bits_range_ref.test.cc @@ -85,7 +85,8 @@ TEST_EACH_WORD_SIZE_W(simd_bits_range_ref, randomize, { alignas(64) std::array data{}; simd_bits_range_ref ref((bitword *)data.data(), sizeof(data) / sizeof(bitword)); - ref.randomize(64 + 57, SHARED_TEST_RNG()); + auto rng = INDEPENDENT_TEST_RNG(); + ref.randomize(64 + 57, rng); uint64_t mask = (1ULL << 57) - 1; // Randomized. ASSERT_NE(ref.u64[0], 0); @@ -100,7 +101,7 @@ TEST_EACH_WORD_SIZE_W(simd_bits_range_ref, randomize, { for (size_t k = 0; k < ref.num_u64_padded(); k++) { ref.u64[k] = UINT64_MAX; } - ref.randomize(64 + 57, SHARED_TEST_RNG()); + ref.randomize(64 + 57, rng); // Randomized. ASSERT_NE(ref.u64[0], 0); ASSERT_NE(ref.u64[0], SIZE_MAX); @@ -117,8 +118,9 @@ TEST_EACH_WORD_SIZE_W(simd_bits_range_ref, xor_assignment, { simd_bits_range_ref m0((bitword *)&data[0], sizeof(data) / sizeof(bitword) / 3); simd_bits_range_ref m1((bitword *)&data[8], sizeof(data) / sizeof(bitword) / 3); simd_bits_range_ref m2((bitword *)&data[16], sizeof(data) / sizeof(bitword) / 3); - m0.randomize(512, SHARED_TEST_RNG()); - m1.randomize(512, SHARED_TEST_RNG()); + auto rng = INDEPENDENT_TEST_RNG(); + m0.randomize(512, rng); + m1.randomize(512, rng); ASSERT_NE(m0, m1); ASSERT_NE(m0, m2); m2 ^= m0; @@ -133,8 +135,9 @@ TEST_EACH_WORD_SIZE_W(simd_bits_range_ref, assignment, { alignas(64) std::array data{}; simd_bits_range_ref m0((bitword *)&data[0], sizeof(data) / sizeof(bitword) / 2); simd_bits_range_ref m1((bitword *)&data[8], sizeof(data) / sizeof(bitword) / 2); - m0.randomize(512, SHARED_TEST_RNG()); - m1.randomize(512, SHARED_TEST_RNG()); + auto rng = INDEPENDENT_TEST_RNG(); + m0.randomize(512, rng); + m1.randomize(512, rng); auto old_m1 = m1.u64[0]; ASSERT_NE(m0, m1); m0 = m1; @@ -265,8 +268,9 @@ TEST_EACH_WORD_SIZE_W(simd_bits_range_ref, swap_with, { simd_bits_range_ref m1((bitword *)&data[8], sizeof(data) / sizeof(bitword) / 4); simd_bits_range_ref m2((bitword *)&data[16], sizeof(data) / sizeof(bitword) / 4); simd_bits_range_ref m3((bitword *)&data[24], sizeof(data) / sizeof(bitword) / 4); - m0.randomize(512, SHARED_TEST_RNG()); - m1.randomize(512, SHARED_TEST_RNG()); + auto rng = INDEPENDENT_TEST_RNG(); + m0.randomize(512, rng); + m1.randomize(512, rng); m2 = m0; m3 = m1; ASSERT_EQ(m0, m2); @@ -279,7 +283,8 @@ TEST_EACH_WORD_SIZE_W(simd_bits_range_ref, swap_with, { TEST_EACH_WORD_SIZE_W(simd_bits_range_ref, clear, { alignas(64) std::array data{}; simd_bits_range_ref m0((bitword *)&data[0], sizeof(data) / sizeof(bitword)); - m0.randomize(512, SHARED_TEST_RNG()); + auto rng = INDEPENDENT_TEST_RNG(); + m0.randomize(512, rng); ASSERT_TRUE(m0.not_zero()); m0.clear(); ASSERT_TRUE(!m0.not_zero()); @@ -325,8 +330,9 @@ TEST_EACH_WORD_SIZE_W(simd_bits_range_ref, for_each_set_bit, { }) TEST_EACH_WORD_SIZE_W(simd_bits_range_ref, truncated_overwrite_from, { - simd_bits dat = simd_bits::random(1024, SHARED_TEST_RNG()); - simd_bits mut = simd_bits::random(1024, SHARED_TEST_RNG()); + auto rng = INDEPENDENT_TEST_RNG(); + simd_bits dat = simd_bits::random(1024, rng); + simd_bits mut = simd_bits::random(1024, rng); simd_bits old = mut; simd_bits_range_ref(mut).truncated_overwrite_from(dat, 455); diff --git a/src/stim/mem/simd_util.test.cc b/src/stim/mem/simd_util.test.cc index 51860d9cb..1411fc6e6 100644 --- a/src/stim/mem/simd_util.test.cc +++ b/src/stim/mem/simd_util.test.cc @@ -63,7 +63,7 @@ template std::string determine_if_function_performs_bit_permutation_helper( const std::function &)> &func, const std::array &bit_permutation) { size_t area = 1 << A; - auto data = simd_bits::random(area, SHARED_TEST_RNG()); + auto data = simd_bits::random(area, INDEPENDENT_TEST_RNG()); auto expected = simd_bits(area); for (size_t k_in = 0; k_in < area; k_in++) { @@ -103,7 +103,8 @@ template void EXPECT_FUNCTION_PERFORMS_ADDRESS_BIT_PERMUTATION( const std::function &)> &func, const std::array &bit_permutation) { size_t area = 1 << A; - auto data = simd_bits::random(area, SHARED_TEST_RNG()); + auto rng = INDEPENDENT_TEST_RNG(); + auto data = simd_bits::random(area, rng); auto expected = simd_bits(area); for (size_t k_in = 0; k_in < area; k_in++) { @@ -144,7 +145,8 @@ void EXPECT_FUNCTION_PERFORMS_ADDRESS_BIT_PERMUTATION( TEST(simd_util, inplace_transpose_64x64) { constexpr size_t W = 64; - simd_bits data = simd_bits::random(64 * 64, SHARED_TEST_RNG()); + auto rng = INDEPENDENT_TEST_RNG(); + simd_bits data = simd_bits::random(64 * 64, rng); simd_bits copy = data; inplace_transpose_64x64(copy.u64, 1); for (size_t i = 0; i < 64; i++) { @@ -432,7 +434,7 @@ TEST(simd_util, popcnt64) { bits.push_back(i < expected); } for (size_t reps = 0; reps < 100; reps++) { - std::shuffle(bits.begin(), bits.end(), SHARED_TEST_RNG()); + std::shuffle(bits.begin(), bits.end(), INDEPENDENT_TEST_RNG()); uint64_t v = 0; for (size_t i = 0; i < 64; i++) { v |= bits[i] << i; diff --git a/src/stim/mem/simd_word.test.cc b/src/stim/mem/simd_word.test.cc index 6fa3eeb22..5a09de2f6 100644 --- a/src/stim/mem/simd_word.test.cc +++ b/src/stim/mem/simd_word.test.cc @@ -41,7 +41,7 @@ TEST_EACH_WORD_SIZE_W(simd_word_pick, popcount, { bits.push_back(i < expected); } for (size_t reps = 0; reps < 100; reps++) { - std::shuffle(bits.begin(), bits.end(), SHARED_TEST_RNG()); + std::shuffle(bits.begin(), bits.end(), INDEPENDENT_TEST_RNG()); for (size_t i = 0; i < n; i++) { v.p[i >> 6] = 0; } diff --git a/src/stim/probability_util.test.cc b/src/stim/probability_util.test.cc index d54d36f1c..6d455b4aa 100644 --- a/src/stim/probability_util.test.cc +++ b/src/stim/probability_util.test.cc @@ -23,17 +23,19 @@ using namespace stim; TEST(probability_util, sample_hit_indices_corner_cases) { - ASSERT_EQ(sample_hit_indices(0, 100000, SHARED_TEST_RNG()), (std::vector{})); - ASSERT_EQ(sample_hit_indices(1, 10, SHARED_TEST_RNG()), (std::vector{0, 1, 2, 3, 4, 5, 6, 7, 8, 9})); + auto rng = INDEPENDENT_TEST_RNG(); + ASSERT_EQ(sample_hit_indices(0, 100000, rng), (std::vector{})); + ASSERT_EQ(sample_hit_indices(1, 10, rng), (std::vector{0, 1, 2, 3, 4, 5, 6, 7, 8, 9})); } TEST(probability_util, sample_hit_indices) { + auto rng = INDEPENDENT_TEST_RNG(); size_t num_buckets = 10000; size_t num_samples = 100000; double p = 0.001; std::vector buckets(num_buckets, 0); for (size_t k = 0; k < num_samples; k++) { - for (auto bucket : sample_hit_indices(p, num_buckets, SHARED_TEST_RNG())) { + for (auto bucket : sample_hit_indices(p, num_buckets, rng)) { buckets[bucket] += 1; } } @@ -48,11 +50,12 @@ TEST(probability_util, sample_hit_indices) { } TEST_EACH_WORD_SIZE_W(probability_util, biased_random, { + auto rng = INDEPENDENT_TEST_RNG(); std::vector probs{0, 0.01, 0.03, 0.1, 0.4, 0.49, 0.5, 0.6, 0.9, 0.99, 0.999, 1}; simd_bits data(1000000); size_t n = data.num_bits_padded(); for (auto p : probs) { - biased_randomize_bits(p, data.u64, data.u64 + data.num_u64_padded(), SHARED_TEST_RNG()); + biased_randomize_bits(p, data.u64, data.u64 + data.num_u64_padded(), rng); size_t t = 0; for (size_t k = 0; k < data.num_u64_padded(); k++) { t += popcnt64(data.u64[k]); diff --git a/src/stim/py/base.pybind.cc b/src/stim/py/base.pybind.cc index bfc95d634..4bbb363dc 100644 --- a/src/stim/py/base.pybind.cc +++ b/src/stim/py/base.pybind.cc @@ -20,14 +20,14 @@ using namespace stim; -std::shared_ptr stim_pybind::make_py_seeded_rng(const pybind11::object &seed) { +std::mt19937_64 stim_pybind::make_py_seeded_rng(const pybind11::object &seed) { if (seed.is_none()) { - return std::make_shared(externally_seeded_rng()); + return externally_seeded_rng(); } try { uint64_t s = pybind11::cast(seed) ^ INTENTIONAL_VERSION_SEED_INCOMPATIBILITY; - return std::make_shared(s); + return std::mt19937_64(s); } catch (const pybind11::cast_error &) { throw std::invalid_argument("Expected seed to be None or a 64 bit unsigned integer."); } diff --git a/src/stim/py/base.pybind.h b/src/stim/py/base.pybind.h index 712deea30..0697275eb 100644 --- a/src/stim/py/base.pybind.h +++ b/src/stim/py/base.pybind.h @@ -28,7 +28,7 @@ namespace stim_pybind { -std::shared_ptr make_py_seeded_rng(const pybind11::object &seed); +std::mt19937_64 make_py_seeded_rng(const pybind11::object &seed); stim::SampleFormat format_to_enum(const std::string &format); bool normalize_index_or_slice( const pybind11::object &index_or_slice, diff --git a/src/stim/py/compiled_detector_sampler.pybind.cc b/src/stim/py/compiled_detector_sampler.pybind.cc index e68e8ed4e..5b5480270 100644 --- a/src/stim/py/compiled_detector_sampler.pybind.cc +++ b/src/stim/py/compiled_detector_sampler.pybind.cc @@ -25,11 +25,10 @@ using namespace stim; using namespace stim_pybind; -CompiledDetectorSampler::CompiledDetectorSampler(Circuit init_circuit, std::shared_ptr init_prng) +CompiledDetectorSampler::CompiledDetectorSampler(Circuit init_circuit, std::mt19937_64 &&rng) : circuit_stats(init_circuit.compute_stats()), circuit(std::move(init_circuit)), - prng(init_prng), - frame_sim(circuit_stats, FrameSimulatorMode::STORE_DETECTIONS_TO_MEMORY, 0, *prng) { + frame_sim(circuit_stats, FrameSimulatorMode::STORE_DETECTIONS_TO_MEMORY, 0, std::move(rng)) { } pybind11::object CompiledDetectorSampler::sample_to_numpy( @@ -84,7 +83,7 @@ void CompiledDetectorSampler::sample_write( append_observables, out.f, f, - *prng, + frame_sim.rng, obs_out.f, parsed_obs_out_format); } diff --git a/src/stim/py/compiled_detector_sampler.pybind.h b/src/stim/py/compiled_detector_sampler.pybind.h index 24ace6ca9..c5853022e 100644 --- a/src/stim/py/compiled_detector_sampler.pybind.h +++ b/src/stim/py/compiled_detector_sampler.pybind.h @@ -28,13 +28,12 @@ namespace stim_pybind { struct CompiledDetectorSampler { stim::CircuitStats circuit_stats; stim::Circuit circuit; - std::shared_ptr prng; stim::FrameSimulator frame_sim; CompiledDetectorSampler() = delete; CompiledDetectorSampler(const CompiledDetectorSampler &) = delete; CompiledDetectorSampler(CompiledDetectorSampler &&) = default; - CompiledDetectorSampler(stim::Circuit circuit, std::shared_ptr prng); + CompiledDetectorSampler(stim::Circuit circuit, std::mt19937_64 &&rng); pybind11::object sample_to_numpy( size_t num_shots, bool prepend_observables, diff --git a/src/stim/py/compiled_measurement_sampler.pybind.cc b/src/stim/py/compiled_measurement_sampler.pybind.cc index fae638d68..2588062c0 100644 --- a/src/stim/py/compiled_measurement_sampler.pybind.cc +++ b/src/stim/py/compiled_measurement_sampler.pybind.cc @@ -17,7 +17,6 @@ #include "stim/circuit/circuit.pybind.h" #include "stim/py/base.pybind.h" #include "stim/py/numpy.pybind.h" -#include "stim/simulators/frame_simulator.h" #include "stim/simulators/frame_simulator_util.h" #include "stim/simulators/tableau_simulator.h" @@ -25,15 +24,12 @@ using namespace stim; using namespace stim_pybind; CompiledMeasurementSampler::CompiledMeasurementSampler( - simd_bits ref_sample, - Circuit circuit, - bool skip_reference_sample, - std::shared_ptr prng) - : ref_sample(ref_sample), circuit(circuit), skip_reference_sample(skip_reference_sample), prng(prng) { + simd_bits ref_sample, Circuit circuit, bool skip_reference_sample, std::mt19937_64 &&rng) + : ref_sample(ref_sample), circuit(circuit), skip_reference_sample(skip_reference_sample), rng(std::move(rng)) { } pybind11::object CompiledMeasurementSampler::sample_to_numpy(size_t num_shots, bool bit_packed) { - simd_bit_table sample = sample_batch_measurements(circuit, ref_sample, num_shots, *prng, true); + simd_bit_table sample = sample_batch_measurements(circuit, ref_sample, num_shots, rng, true); size_t bits_per_sample = circuit.count_measurements(); return simd_bit_table_to_numpy(sample, num_shots, bits_per_sample, bit_packed); } @@ -45,7 +41,7 @@ void CompiledMeasurementSampler::sample_write( if (out == nullptr) { throw std::invalid_argument("Failed to open '" + filepath + "' to write."); } - sample_batch_measurements_writing_results_to_disk(circuit, ref_sample, num_samples, out, f, *prng); + sample_batch_measurements_writing_results_to_disk(circuit, ref_sample, num_samples, out, f, rng); fclose(out); } diff --git a/src/stim/py/compiled_measurement_sampler.pybind.h b/src/stim/py/compiled_measurement_sampler.pybind.h index 079d24e3d..ca3f45c92 100644 --- a/src/stim/py/compiled_measurement_sampler.pybind.h +++ b/src/stim/py/compiled_measurement_sampler.pybind.h @@ -28,7 +28,7 @@ struct CompiledMeasurementSampler { const stim::simd_bits ref_sample; const stim::Circuit circuit; const bool skip_reference_sample; - std::shared_ptr prng; + std::mt19937_64 rng; CompiledMeasurementSampler() = delete; CompiledMeasurementSampler(const CompiledMeasurementSampler &) = delete; CompiledMeasurementSampler(CompiledMeasurementSampler &&) = default; @@ -36,7 +36,7 @@ struct CompiledMeasurementSampler { stim::simd_bits ref_sample, stim::Circuit circuit, bool skip_reference_sample, - std::shared_ptr prng); + std::mt19937_64 &&rng); pybind11::object sample_to_numpy(size_t num_shots, bool bit_packed); void sample_write(size_t num_samples, const std::string &filepath, const std::string &format); std::string repr() const; diff --git a/src/stim/simulators/count_determined_measurements.inl b/src/stim/simulators/count_determined_measurements.inl index e38ba6253..d9c9bcd69 100644 --- a/src/stim/simulators/count_determined_measurements.inl +++ b/src/stim/simulators/count_determined_measurements.inl @@ -6,9 +6,8 @@ namespace stim { template uint64_t count_determined_measurements(const Circuit &circuit) { uint64_t result = 0; - std::mt19937_64 irrelevant_rng{0}; auto n = circuit.count_qubits(); - TableauSimulator sim(irrelevant_rng, n); + TableauSimulator sim(std::mt19937_64{0}, n); PauliString obs_buffer(n); circuit.for_each_operation([&](const CircuitInstruction &inst) { diff --git a/src/stim/simulators/dem_sampler.test.cc b/src/stim/simulators/dem_sampler.test.cc index 1a7163608..c1c2b649a 100644 --- a/src/stim/simulators/dem_sampler.test.cc +++ b/src/stim/simulators/dem_sampler.test.cc @@ -57,7 +57,7 @@ TEST_EACH_WORD_SIZE_W(DemSampler, resample_basic_probabilities, { error(0.75) D3 error(1) D4 ^ D5 )DEM"), - SHARED_TEST_RNG(), + INDEPENDENT_TEST_RNG(), 1000); for (size_t k = 0; k < 2; k++) { sampler.resample(false); @@ -82,7 +82,7 @@ TEST_EACH_WORD_SIZE_W(DemSampler, resample_combinations, { error(0.2) D1 D2 error(0.3) D2 D0 )DEM"), - SHARED_TEST_RNG(), + INDEPENDENT_TEST_RNG(), 1000); for (size_t k = 0; k < 2; k++) { sampler.resample(false); diff --git a/src/stim/simulators/error_analyzer.test.cc b/src/stim/simulators/error_analyzer.test.cc index a7a614af5..927fedae5 100644 --- a/src/stim/simulators/error_analyzer.test.cc +++ b/src/stim/simulators/error_analyzer.test.cc @@ -294,7 +294,7 @@ TEST_EACH_WORD_SIZE_W(ErrorAnalyzer, unitary_gates_match_frame_simulator, { CircuitStats stats; stats.num_qubits = 16; stats.num_measurements = 100; - FrameSimulator f(stats, FrameSimulatorMode::STORE_DETECTIONS_TO_MEMORY, 16, SHARED_TEST_RNG()); + FrameSimulator f(stats, FrameSimulatorMode::STORE_DETECTIONS_TO_MEMORY, 16, INDEPENDENT_TEST_RNG()); ErrorAnalyzer e(100, 1, 16, 100, false, false, false, 0.0, false, true); for (size_t q = 0; q < 16; q++) { if (q & 1) { diff --git a/src/stim/simulators/frame_simulator.h b/src/stim/simulators/frame_simulator.h index 0927240fc..64b7d1304 100644 --- a/src/stim/simulators/frame_simulator.h +++ b/src/stim/simulators/frame_simulator.h @@ -54,7 +54,7 @@ struct FrameSimulator { simd_bits tmp_storage; // Workspace used when sampling compound error processes. simd_bits last_correlated_error_occurred; // correlated error flag for each instance. simd_bit_table sweep_table; // Shot-to-shot configuration data. - std::mt19937_64 &rng; // Random number generator used for generating entropy. + std::mt19937_64 rng; // Random number generator used for generating entropy. // Determines whether e.g. 50% Z errors are multiplied into the frame when measuring in the Z basis. // This is necessary for correct sampling. @@ -71,7 +71,7 @@ struct FrameSimulator { /// of buffers. /// batch_size: How many shots to simulate simultaneously. /// rng: The random number generator to pull noise from. - FrameSimulator(CircuitStats circuit_stats, FrameSimulatorMode mode, size_t batch_size, std::mt19937_64 &rng); + FrameSimulator(CircuitStats circuit_stats, FrameSimulatorMode mode, size_t batch_size, std::mt19937_64 &&rng); FrameSimulator() = delete; PauliString get_frame(size_t sample_index) const; diff --git a/src/stim/simulators/frame_simulator.inl b/src/stim/simulators/frame_simulator.inl index 7f3c42bf1..67ac9f998 100644 --- a/src/stim/simulators/frame_simulator.inl +++ b/src/stim/simulators/frame_simulator.inl @@ -39,7 +39,7 @@ inline void for_each_target_pair(FrameSimulator &sim, const CircuitInstructio template FrameSimulator::FrameSimulator( - CircuitStats circuit_stats, FrameSimulatorMode mode, size_t batch_size, std::mt19937_64 &rng) + CircuitStats circuit_stats, FrameSimulatorMode mode, size_t batch_size, std::mt19937_64 &&rng) : num_qubits(0), keeping_detection_data(false), batch_size(0), @@ -52,7 +52,7 @@ FrameSimulator::FrameSimulator( tmp_storage(0), last_correlated_error_occurred(0), sweep_table(0, 0), - rng(rng) { + rng(std::move(rng)) { configure_for(circuit_stats, mode, batch_size); } diff --git a/src/stim/simulators/frame_simulator.perf.cc b/src/stim/simulators/frame_simulator.perf.cc index 7fbe84a00..fde548c81 100644 --- a/src/stim/simulators/frame_simulator.perf.cc +++ b/src/stim/simulators/frame_simulator.perf.cc @@ -25,8 +25,8 @@ BENCHMARK(FrameSimulator_depolarize1_100Kqubits_1Ksamples_per1000) { stats.num_qubits = 100 * 1000; size_t num_samples = 1000; double probability = 0.001; - std::mt19937_64 rng(0); // NOLINT(cert-msc51-cpp) - FrameSimulator sim(stats, FrameSimulatorMode::STORE_DETECTIONS_TO_MEMORY, num_samples, rng); + FrameSimulator sim( + stats, FrameSimulatorMode::STORE_DETECTIONS_TO_MEMORY, num_samples, std::mt19937_64(0)); std::vector targets; for (uint32_t k = 0; k < stats.num_qubits; k++) { @@ -45,8 +45,8 @@ BENCHMARK(FrameSimulator_depolarize2_100Kqubits_1Ksamples_per1000) { stats.num_qubits = 100 * 1000; size_t num_samples = 1000; double probability = 0.001; - std::mt19937_64 rng(0); // NOLINT(cert-msc51-cpp) - FrameSimulator sim(stats, FrameSimulatorMode::STORE_DETECTIONS_TO_MEMORY, num_samples, rng); + FrameSimulator sim( + stats, FrameSimulatorMode::STORE_DETECTIONS_TO_MEMORY, num_samples, std::mt19937_64(0)); std::vector targets; for (uint32_t k = 0; k < stats.num_qubits; k++) { @@ -65,8 +65,8 @@ BENCHMARK(FrameSimulator_hadamard_100Kqubits_1Ksamples) { CircuitStats stats; stats.num_qubits = 100 * 1000; size_t num_samples = 1000; - std::mt19937_64 rng(0); // NOLINT(cert-msc51-cpp) - FrameSimulator sim(stats, FrameSimulatorMode::STORE_DETECTIONS_TO_MEMORY, num_samples, rng); + FrameSimulator sim( + stats, FrameSimulatorMode::STORE_DETECTIONS_TO_MEMORY, num_samples, std::mt19937_64(0)); std::vector targets; for (uint32_t k = 0; k < stats.num_qubits; k++) { @@ -85,8 +85,8 @@ BENCHMARK(FrameSimulator_CX_100Kqubits_1Ksamples) { CircuitStats stats; stats.num_qubits = 100 * 1000; size_t num_samples = 1000; - std::mt19937_64 rng(0); // NOLINT(cert-msc51-cpp) - FrameSimulator sim(stats, FrameSimulatorMode::STORE_DETECTIONS_TO_MEMORY, num_samples, rng); + FrameSimulator sim( + stats, FrameSimulatorMode::STORE_DETECTIONS_TO_MEMORY, num_samples, std::mt19937_64(0)); std::vector targets; for (uint32_t k = 0; k < stats.num_qubits; k++) { @@ -108,9 +108,8 @@ BENCHMARK(FrameSimulator_surface_code_rotated_memory_z_d11_r100_batch1024) { params.after_clifford_depolarization = 0.001; auto circuit = generate_surface_code_circuit(params).circuit; - std::mt19937_64 rng(0); // NOLINT(cert-msc51-cpp) FrameSimulator sim( - circuit.compute_stats(), FrameSimulatorMode::STORE_MEASUREMENTS_TO_MEMORY, 1024, rng); + circuit.compute_stats(), FrameSimulatorMode::STORE_MEASUREMENTS_TO_MEMORY, 1024, std::mt19937_64(0)); benchmark_go([&]() { sim.reset_all_and_run(circuit); diff --git a/src/stim/simulators/frame_simulator.test.cc b/src/stim/simulators/frame_simulator.test.cc index 214251a7b..9b2e04fb1 100644 --- a/src/stim/simulators/frame_simulator.test.cc +++ b/src/stim/simulators/frame_simulator.test.cc @@ -28,7 +28,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, get_set_frame, { CircuitStats circuit_stats; circuit_stats.num_qubits = 6; circuit_stats.max_lookback = 999; - FrameSimulator sim(circuit_stats, FrameSimulatorMode::STORE_DETECTIONS_TO_MEMORY, 4, SHARED_TEST_RNG()); + FrameSimulator sim(circuit_stats, FrameSimulatorMode::STORE_DETECTIONS_TO_MEMORY, 4, INDEPENDENT_TEST_RNG()); ASSERT_EQ(sim.get_frame(0), PauliString::from_str("______")); ASSERT_EQ(sim.get_frame(1), PauliString::from_str("______")); ASSERT_EQ(sim.get_frame(2), PauliString::from_str("______")); @@ -46,7 +46,8 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, get_set_frame, { circuit_stats.num_qubits = 501; circuit_stats.max_lookback = 999; - FrameSimulator big_sim(circuit_stats, FrameSimulatorMode::STORE_DETECTIONS_TO_MEMORY, 1001, SHARED_TEST_RNG()); + FrameSimulator big_sim( + circuit_stats, FrameSimulatorMode::STORE_DETECTIONS_TO_MEMORY, 1001, INDEPENDENT_TEST_RNG()); big_sim.set_frame(258, PauliString::from_func(false, 501, [](size_t k) { return "_X"[k == 303]; })); @@ -62,15 +63,16 @@ bool is_bulk_frame_operation_consistent_with_tableau(const Gate &gate) { circuit_stats.num_qubits = 500; circuit_stats.max_lookback = 10; size_t num_samples = 1000; - FrameSimulator sim(circuit_stats, FrameSimulatorMode::STORE_DETECTIONS_TO_MEMORY, 1000, SHARED_TEST_RNG()); + FrameSimulator sim(circuit_stats, FrameSimulatorMode::STORE_DETECTIONS_TO_MEMORY, 1000, INDEPENDENT_TEST_RNG()); size_t num_targets = tableau.num_qubits; assert(num_targets == 1 || num_targets == 2); std::vector targets{{101}, {403}, {202}, {100}}; while (targets.size() > num_targets) { targets.pop_back(); } + auto rng = INDEPENDENT_TEST_RNG(); for (size_t k = 7; k < num_samples; k += 101) { - auto test_value = PauliString::random(circuit_stats.num_qubits, SHARED_TEST_RNG()); + auto test_value = PauliString::random(circuit_stats.num_qubits, rng); PauliStringRef test_value_ref(test_value); sim.set_frame(k, test_value); sim.do_gate({gate.id, {}, targets}); @@ -103,7 +105,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, bulk_operations_consistent_with_tableau_da template bool is_output_possible_promising_no_bare_resets(const Circuit &circuit, const simd_bits_range_ref output) { - auto tableau_sim = TableauSimulator(SHARED_TEST_RNG(), circuit.count_qubits()); + auto tableau_sim = TableauSimulator(INDEPENDENT_TEST_RNG(), circuit.count_qubits()); size_t out_p = 0; bool pass = true; circuit.for_each_operation([&](const CircuitInstruction &op) { @@ -143,9 +145,10 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, test_util_is_output_possible, { template bool is_sim_frame_consistent_with_sim_tableau(const char *program_text) { + auto rng = INDEPENDENT_TEST_RNG(); auto circuit = Circuit(program_text); auto reference_sample = TableauSimulator::reference_sample_circuit(circuit); - auto samples = sample_batch_measurements(circuit, reference_sample, 10, SHARED_TEST_RNG(), true); + auto samples = sample_batch_measurements(circuit, reference_sample, 10, rng, true); for (size_t k = 0; k < 10; k++) { simd_bits_range_ref sample = samples[k]; @@ -284,6 +287,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, consistency, { }) TEST_EACH_WORD_SIZE_W(FrameSimulator, sample_batch_measurements_writing_results_to_disk, { + auto rng = INDEPENDENT_TEST_RNG(); auto circuit = Circuit( "X 0\n" "M 1\n" @@ -291,17 +295,17 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, sample_batch_measurements_writing_results_ "M 2\n" "M 3\n"); auto ref = TableauSimulator::reference_sample_circuit(circuit); - auto r = sample_batch_measurements(circuit, ref, 10, SHARED_TEST_RNG(), true); + auto r = sample_batch_measurements(circuit, ref, 10, rng, true); for (size_t k = 0; k < 10; k++) { ASSERT_EQ(r[k].u64[0], 2); } FILE *tmp = tmpfile(); - sample_batch_measurements_writing_results_to_disk(circuit, ref, 5, tmp, SAMPLE_FORMAT_01, SHARED_TEST_RNG()); + sample_batch_measurements_writing_results_to_disk(circuit, ref, 5, tmp, SAMPLE_FORMAT_01, rng); ASSERT_EQ(rewind_read_close(tmp), "0100\n0100\n0100\n0100\n0100\n"); tmp = tmpfile(); - sample_batch_measurements_writing_results_to_disk(circuit, ref, 5, tmp, SAMPLE_FORMAT_B8, SHARED_TEST_RNG()); + sample_batch_measurements_writing_results_to_disk(circuit, ref, 5, tmp, SAMPLE_FORMAT_B8, rng); rewind(tmp); for (size_t k = 0; k < 5; k++) { ASSERT_EQ(getc(tmp), 2); @@ -309,7 +313,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, sample_batch_measurements_writing_results_ ASSERT_EQ(getc(tmp), EOF); tmp = tmpfile(); - sample_batch_measurements_writing_results_to_disk(circuit, ref, 64, tmp, SAMPLE_FORMAT_PTB64, SHARED_TEST_RNG()); + sample_batch_measurements_writing_results_to_disk(circuit, ref, 64, tmp, SAMPLE_FORMAT_PTB64, rng); rewind(tmp); for (size_t k = 0; k < 8; k++) { ASSERT_EQ(getc(tmp), 0); @@ -325,6 +329,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, sample_batch_measurements_writing_results_ }) TEST_EACH_WORD_SIZE_W(FrameSimulator, big_circuit_measurements, { + auto rng = INDEPENDENT_TEST_RNG(); Circuit circuit; for (uint32_t k = 0; k < 1250; k += 3) { circuit.safe_append_u("X", {k}); @@ -333,7 +338,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, big_circuit_measurements, { circuit.safe_append_u("M", {k}); } auto ref = TableauSimulator::reference_sample_circuit(circuit); - auto r = sample_batch_measurements(circuit, ref, 750, SHARED_TEST_RNG(), true); + auto r = sample_batch_measurements(circuit, ref, 750, rng, true); for (size_t i = 0; i < 750; i++) { for (size_t k = 0; k < 1250; k++) { ASSERT_EQ(r[i][k], k % 3 == 0) << k; @@ -341,7 +346,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, big_circuit_measurements, { } FILE *tmp = tmpfile(); - sample_batch_measurements_writing_results_to_disk(circuit, ref, 750, tmp, SAMPLE_FORMAT_01, SHARED_TEST_RNG()); + sample_batch_measurements_writing_results_to_disk(circuit, ref, 750, tmp, SAMPLE_FORMAT_01, rng); rewind(tmp); for (size_t s = 0; s < 750; s++) { for (size_t k = 0; k < 1250; k++) { @@ -352,7 +357,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, big_circuit_measurements, { ASSERT_EQ(getc(tmp), EOF); tmp = tmpfile(); - sample_batch_measurements_writing_results_to_disk(circuit, ref, 750, tmp, SAMPLE_FORMAT_B8, SHARED_TEST_RNG()); + sample_batch_measurements_writing_results_to_disk(circuit, ref, 750, tmp, SAMPLE_FORMAT_B8, rng); rewind(tmp); for (size_t s = 0; s < 750; s++) { for (size_t k = 0; k < 1250; k += 8) { @@ -366,6 +371,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, big_circuit_measurements, { }) TEST_EACH_WORD_SIZE_W(FrameSimulator, run_length_measurement_formats, { + auto rng = INDEPENDENT_TEST_RNG(); Circuit circuit; circuit.safe_append_u("X", {100, 500, 501, 551, 1200}); for (uint32_t k = 0; k < 1250; k++) { @@ -374,17 +380,17 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, run_length_measurement_formats, { auto ref = TableauSimulator::reference_sample_circuit(circuit); FILE *tmp = tmpfile(); - sample_batch_measurements_writing_results_to_disk(circuit, ref, 3, tmp, SAMPLE_FORMAT_HITS, SHARED_TEST_RNG()); + sample_batch_measurements_writing_results_to_disk(circuit, ref, 3, tmp, SAMPLE_FORMAT_HITS, rng); ASSERT_EQ(rewind_read_close(tmp), "100,500,501,551,1200\n100,500,501,551,1200\n100,500,501,551,1200\n"); tmp = tmpfile(); - sample_batch_measurements_writing_results_to_disk(circuit, ref, 3, tmp, SAMPLE_FORMAT_DETS, SHARED_TEST_RNG()); + sample_batch_measurements_writing_results_to_disk(circuit, ref, 3, tmp, SAMPLE_FORMAT_DETS, rng); ASSERT_EQ( rewind_read_close(tmp), "shot M100 M500 M501 M551 M1200\nshot M100 M500 M501 M551 M1200\nshot M100 M500 M501 M551 M1200\n"); tmp = tmpfile(); - sample_batch_measurements_writing_results_to_disk(circuit, ref, 3, tmp, SAMPLE_FORMAT_R8, SHARED_TEST_RNG()); + sample_batch_measurements_writing_results_to_disk(circuit, ref, 3, tmp, SAMPLE_FORMAT_R8, rng); rewind(tmp); for (size_t k = 0; k < 3; k++) { ASSERT_EQ(getc(tmp), 100); @@ -401,6 +407,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, run_length_measurement_formats, { }) TEST_EACH_WORD_SIZE_W(FrameSimulator, big_circuit_random_measurements, { + auto rng = INDEPENDENT_TEST_RNG(); Circuit circuit; for (uint32_t k = 0; k < 270; k++) { circuit.safe_append_u("H_XZ", {k}); @@ -409,13 +416,14 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, big_circuit_random_measurements, { circuit.safe_append_u("M", {k}); } auto ref = TableauSimulator::reference_sample_circuit(circuit); - auto r = sample_batch_measurements(circuit, ref, 1000, SHARED_TEST_RNG(), true); + auto r = sample_batch_measurements(circuit, ref, 1000, rng, true); for (size_t k = 0; k < 1000; k++) { ASSERT_TRUE(r[k].not_zero()) << k; } }) TEST_EACH_WORD_SIZE_W(FrameSimulator, correlated_error, { + auto rng = INDEPENDENT_TEST_RNG(); simd_bits ref(5); simd_bits expected(5); @@ -430,7 +438,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, correlated_error, { )circuit"), ref, 1, - SHARED_TEST_RNG(), + rng, true)[0], expected); @@ -447,7 +455,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, correlated_error, { )circuit"), ref, 1, - SHARED_TEST_RNG(), + rng, true)[0], expected); @@ -464,7 +472,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, correlated_error, { )circuit"), ref, 1, - SHARED_TEST_RNG(), + rng, true)[0], expected); @@ -481,7 +489,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, correlated_error, { )circuit"), ref, 1, - SHARED_TEST_RNG(), + rng, true)[0], expected); @@ -498,7 +506,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, correlated_error, { )circuit"), ref, 1, - SHARED_TEST_RNG(), + rng, true)[0], expected); @@ -515,7 +523,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, correlated_error, { )circuit"), ref, 1, - SHARED_TEST_RNG(), + rng, true)[0], expected); @@ -527,28 +535,27 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, correlated_error, { ASSERT_EQ( sample_batch_measurements( Circuit(R"circuit( - CORRELATED_ERROR(1) X0 X1 - ELSE_CORRELATED_ERROR(1) X1 X2 - ELSE_CORRELATED_ERROR(1) X2 X3 - CORRELATED_ERROR(1) X3 X4 - M 0 1 2 3 4 - )circuit"), + CORRELATED_ERROR(1) X0 X1 + ELSE_CORRELATED_ERROR(1) X1 X2 + ELSE_CORRELATED_ERROR(1) X2 X3 + CORRELATED_ERROR(1) X3 X4 + M 0 1 2 3 4 + )circuit"), ref, 1, - SHARED_TEST_RNG(), + rng, true)[0], expected); int hits[3]{}; - std::mt19937_64 rng(0); size_t n = 10000; auto samples = sample_batch_measurements( Circuit(R"circuit( - CORRELATED_ERROR(0.5) X0 - ELSE_CORRELATED_ERROR(0.25) X1 - ELSE_CORRELATED_ERROR(0.75) X2 - M 0 1 2 - )circuit"), + CORRELATED_ERROR(0.5) X0 + ELSE_CORRELATED_ERROR(0.25) X1 + ELSE_CORRELATED_ERROR(0.75) X2 + M 0 1 2 + )circuit"), ref, n, rng, @@ -564,6 +571,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, correlated_error, { }) TEST_EACH_WORD_SIZE_W(FrameSimulator, quantum_cannot_control_classical, { + auto rng = INDEPENDENT_TEST_RNG(); simd_bits ref(128); // Quantum controlling classical operation is not allowed. @@ -576,7 +584,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, quantum_cannot_control_classical, { )circuit"), ref, 1, - SHARED_TEST_RNG(), + rng, true); }, std::invalid_argument); @@ -589,7 +597,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, quantum_cannot_control_classical, { )circuit"), ref, 1, - SHARED_TEST_RNG(), + rng, true); }, std::invalid_argument); @@ -602,7 +610,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, quantum_cannot_control_classical, { )circuit"), ref, 1, - SHARED_TEST_RNG(), + rng, true); }, std::invalid_argument); @@ -615,7 +623,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, quantum_cannot_control_classical, { )circuit"), ref, 1, - SHARED_TEST_RNG(), + rng, true); }, std::invalid_argument); @@ -628,13 +636,14 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, quantum_cannot_control_classical, { )circuit"), ref, 1, - SHARED_TEST_RNG(), + rng, true); }, std::invalid_argument); }) TEST_EACH_WORD_SIZE_W(FrameSimulator, classical_can_control_quantum, { + auto rng = INDEPENDENT_TEST_RNG(); simd_bits ref(128); simd_bits expected(5); expected.clear(); @@ -650,7 +659,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, classical_can_control_quantum, { )circuit"), ref, 1, - SHARED_TEST_RNG(), + rng, true)[0], expected); ASSERT_EQ( @@ -663,7 +672,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, classical_can_control_quantum, { )circuit"), ref, 1, - SHARED_TEST_RNG(), + rng, true)[0], expected); ASSERT_EQ( @@ -676,7 +685,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, classical_can_control_quantum, { )circuit"), ref, 1, - SHARED_TEST_RNG(), + rng, true)[0], expected); ASSERT_EQ( @@ -689,12 +698,13 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, classical_can_control_quantum, { )circuit"), ref, 1, - SHARED_TEST_RNG(), + rng, true)[0], expected); }) TEST_EACH_WORD_SIZE_W(FrameSimulator, classical_controls, { + auto rng = INDEPENDENT_TEST_RNG(); simd_bits ref(128); simd_bits expected(5); @@ -708,7 +718,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, classical_controls, { )circuit"), ref, 1, - SHARED_TEST_RNG(), + rng, true)[0], expected); @@ -722,7 +732,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, classical_controls, { )circuit"), ref, 1, - SHARED_TEST_RNG(), + rng, true)[0], expected); @@ -739,7 +749,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, classical_controls, { )circuit"), ref, 1, - SHARED_TEST_RNG(), + rng, true)[0], expected); @@ -756,7 +766,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, classical_controls, { )circuit"), ref, 1, - SHARED_TEST_RNG(), + rng, true)[0], expected); auto r = sample_batch_measurements( @@ -768,7 +778,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, classical_controls, { )circuit"), ref, 1000, - SHARED_TEST_RNG(), + rng, true); size_t hits = 0; for (size_t k = 0; k < 1000; k++) { @@ -792,7 +802,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, classical_controls, { )circuit"), ref, 1, - SHARED_TEST_RNG(), + rng, true)[0], expected); @@ -809,14 +819,15 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, classical_controls, { )circuit"), ref, 1, - SHARED_TEST_RNG(), + rng, true)[0], expected); }) TEST_EACH_WORD_SIZE_W(FrameSimulator, record_gets_trimmed, { Circuit c = Circuit("M 0 1 2 3 4 5 6 7 8 9"); - FrameSimulator sim(c.compute_stats(), FrameSimulatorMode::STREAM_MEASUREMENTS_TO_DISK, 768, SHARED_TEST_RNG()); + FrameSimulator sim( + c.compute_stats(), FrameSimulatorMode::STREAM_MEASUREMENTS_TO_DISK, 768, INDEPENDENT_TEST_RNG()); MeasureRecordBatchWriter b(tmpfile(), 768, SAMPLE_FORMAT_B8); for (size_t k = 0; k < 1000; k++) { sim.do_MZ(c.operations[0]); @@ -826,6 +837,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, record_gets_trimmed, { }) TEST_EACH_WORD_SIZE_W(FrameSimulator, stream_huge_case, { + auto rng = INDEPENDENT_TEST_RNG(); FILE *tmp = tmpfile(); sample_batch_measurements_writing_results_to_disk( Circuit(R"CIRCUIT( @@ -838,7 +850,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, stream_huge_case, { 256, tmp, SAMPLE_FORMAT_B8, - SHARED_TEST_RNG()); + rng); rewind(tmp); for (size_t k = 0; k < 256 * 100000 * 4 / 8; k++) { ASSERT_EQ(getc(tmp), 0x44); @@ -847,6 +859,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, stream_huge_case, { }) TEST_EACH_WORD_SIZE_W(FrameSimulator, block_results_single_shot, { + auto rng = INDEPENDENT_TEST_RNG(); auto circuit = Circuit(R"circuit( REPEAT 10000 { X_ERROR(1) 0 @@ -855,8 +868,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, block_results_single_shot, { } )circuit"); FILE *tmp = tmpfile(); - sample_batch_measurements_writing_results_to_disk( - circuit, simd_bits(0), 3, tmp, SAMPLE_FORMAT_01, SHARED_TEST_RNG()); + sample_batch_measurements_writing_results_to_disk(circuit, simd_bits(0), 3, tmp, SAMPLE_FORMAT_01, rng); auto result = rewind_read_close(tmp); for (size_t k = 0; k < 30000; k += 3) { @@ -868,6 +880,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, block_results_single_shot, { }) TEST_EACH_WORD_SIZE_W(FrameSimulator, block_results_triple_shot, { + auto rng = INDEPENDENT_TEST_RNG(); auto circuit = Circuit(R"circuit( REPEAT 10000 { X_ERROR(1) 0 @@ -876,8 +889,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, block_results_triple_shot, { } )circuit"); FILE *tmp = tmpfile(); - sample_batch_measurements_writing_results_to_disk( - circuit, simd_bits(0), 3, tmp, SAMPLE_FORMAT_01, SHARED_TEST_RNG()); + sample_batch_measurements_writing_results_to_disk(circuit, simd_bits(0), 3, tmp, SAMPLE_FORMAT_01, rng); auto result = rewind_read_close(tmp); for (size_t rep = 0; rep < 3; rep++) { @@ -892,6 +904,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, block_results_triple_shot, { }) TEST_EACH_WORD_SIZE_W(FrameSimulator, stream_results, { + auto rng = INDEPENDENT_TEST_RNG(); DebugForceResultStreamingRaii force_streaming; auto circuit = Circuit(R"circuit( REPEAT 10000 { @@ -901,8 +914,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, stream_results, { } )circuit"); FILE *tmp = tmpfile(); - sample_batch_measurements_writing_results_to_disk( - circuit, simd_bits(0), 3, tmp, SAMPLE_FORMAT_01, SHARED_TEST_RNG()); + sample_batch_measurements_writing_results_to_disk(circuit, simd_bits(0), 3, tmp, SAMPLE_FORMAT_01, rng); auto result = rewind_read_close(tmp); for (size_t k = 0; k < 30000; k += 3) { @@ -914,14 +926,14 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, stream_results, { }) TEST_EACH_WORD_SIZE_W(FrameSimulator, stream_many_shots, { + auto rng = INDEPENDENT_TEST_RNG(); DebugForceResultStreamingRaii force_streaming; auto circuit = Circuit(R"circuit( X_ERROR(1) 1 M 0 1 2 )circuit"); FILE *tmp = tmpfile(); - sample_batch_measurements_writing_results_to_disk( - circuit, simd_bits(0), 2049, tmp, SAMPLE_FORMAT_01, SHARED_TEST_RNG()); + sample_batch_measurements_writing_results_to_disk(circuit, simd_bits(0), 2049, tmp, SAMPLE_FORMAT_01, rng); auto result = rewind_read_close(tmp); ASSERT_EQ(result.size(), 2049 * 4); @@ -934,6 +946,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, stream_many_shots, { }) TEST_EACH_WORD_SIZE_W(FrameSimulator, stream_results_triple_shot, { + auto rng = INDEPENDENT_TEST_RNG(); DebugForceResultStreamingRaii force_streaming; auto circuit = Circuit(R"circuit( REPEAT 10000 { @@ -943,8 +956,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, stream_results_triple_shot, { } )circuit"); FILE *tmp = tmpfile(); - sample_batch_measurements_writing_results_to_disk( - circuit, simd_bits(0), 3, tmp, SAMPLE_FORMAT_01, SHARED_TEST_RNG()); + sample_batch_measurements_writing_results_to_disk(circuit, simd_bits(0), 3, tmp, SAMPLE_FORMAT_01, rng); auto result = rewind_read_close(tmp); for (size_t rep = 0; rep < 3; rep++) { @@ -959,6 +971,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, stream_results_triple_shot, { }) TEST_EACH_WORD_SIZE_W(FrameSimulator, measure_y_without_reset_doesnt_reset, { + auto rng = INDEPENDENT_TEST_RNG(); auto r = sample_batch_measurements( Circuit(R"CIRCUIT( RY 0 @@ -973,7 +986,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, measure_y_without_reset_doesnt_reset, { )CIRCUIT"), simd_bits(0), 10000, - SHARED_TEST_RNG(), + rng, false); ASSERT_EQ(r[0].popcnt(), 0); ASSERT_EQ(r[1].popcnt(), 0); @@ -996,7 +1009,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, measure_y_without_reset_doesnt_reset, { )CIRCUIT"), simd_bits(0), 10000, - SHARED_TEST_RNG(), + rng, false); ASSERT_EQ(r[0].popcnt(), 0); ASSERT_EQ(r[1].popcnt(), 0); @@ -1007,12 +1020,13 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, measure_y_without_reset_doesnt_reset, { }) TEST_EACH_WORD_SIZE_W(FrameSimulator, resets_vs_measurements, { + auto rng = INDEPENDENT_TEST_RNG(); auto check = [&](const char *circuit, std::vector results) { simd_bits ref(results.size()); for (size_t k = 0; k < results.size(); k++) { ref[k] = results[k]; } - simd_bit_table t = sample_batch_measurements(Circuit(circuit), ref, 100, SHARED_TEST_RNG(), true); + simd_bit_table t = sample_batch_measurements(Circuit(circuit), ref, 100, rng, true); return !t.data.not_zero(); }; @@ -1156,6 +1170,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, resets_vs_measurements, { }) TEST_EACH_WORD_SIZE_W(FrameSimulator, noisy_measurement_x, { + auto rng = INDEPENDENT_TEST_RNG(); auto r = sample_batch_measurements( Circuit(R"CIRCUIT( RX 0 @@ -1164,7 +1179,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, noisy_measurement_x, { )CIRCUIT"), simd_bits(0), 10000, - SHARED_TEST_RNG(), + rng, false); ASSERT_FALSE(r[1].not_zero()); auto m1 = r[0].popcnt(); @@ -1180,7 +1195,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, noisy_measurement_x, { )CIRCUIT"), simd_bits(0), 5000, - SHARED_TEST_RNG(), + rng, false); auto m2 = r[0].popcnt() + r[1].popcnt(); ASSERT_LT(m2, 10000 - 300); @@ -1190,6 +1205,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, noisy_measurement_x, { }) TEST_EACH_WORD_SIZE_W(FrameSimulator, noisy_measurement_y, { + auto rng = INDEPENDENT_TEST_RNG(); auto r = sample_batch_measurements( Circuit(R"CIRCUIT( RY 0 @@ -1198,7 +1214,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, noisy_measurement_y, { )CIRCUIT"), simd_bits(0), 10000, - SHARED_TEST_RNG(), + rng, false); ASSERT_FALSE(r[1].not_zero()); auto m1 = r[0].popcnt(); @@ -1214,7 +1230,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, noisy_measurement_y, { )CIRCUIT"), simd_bits(0), 5000, - SHARED_TEST_RNG(), + rng, false); auto m2 = r[0].popcnt() + r[1].popcnt(); ASSERT_LT(m2, 10000 - 300); @@ -1224,6 +1240,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, noisy_measurement_y, { }) TEST_EACH_WORD_SIZE_W(FrameSimulator, noisy_measurement_z, { + auto rng = INDEPENDENT_TEST_RNG(); auto r = sample_batch_measurements( Circuit(R"CIRCUIT( RZ 0 @@ -1232,7 +1249,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, noisy_measurement_z, { )CIRCUIT"), simd_bits(0), 10000, - SHARED_TEST_RNG(), + rng, false); ASSERT_FALSE(r[1].not_zero()); auto m1 = r[0].popcnt(); @@ -1248,7 +1265,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, noisy_measurement_z, { )CIRCUIT"), simd_bits(0), 5000, - SHARED_TEST_RNG(), + rng, false); auto m2 = r[0].popcnt() + r[1].popcnt(); ASSERT_LT(m2, 10000 - 300); @@ -1258,6 +1275,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, noisy_measurement_z, { }) TEST_EACH_WORD_SIZE_W(FrameSimulator, noisy_measurement_reset_x, { + auto rng = INDEPENDENT_TEST_RNG(); auto r = sample_batch_measurements( Circuit(R"CIRCUIT( RX 0 @@ -1266,7 +1284,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, noisy_measurement_reset_x, { )CIRCUIT"), simd_bits(0), 10000, - SHARED_TEST_RNG(), + rng, false); ASSERT_FALSE(r[1].not_zero()); auto m1 = r[0].popcnt(); @@ -1282,7 +1300,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, noisy_measurement_reset_x, { )CIRCUIT"), simd_bits(0), 5000, - SHARED_TEST_RNG(), + rng, false); auto m2 = r[0].popcnt() + r[1].popcnt(); ASSERT_LT(m2, 10000 - 300); @@ -1292,6 +1310,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, noisy_measurement_reset_x, { }) TEST_EACH_WORD_SIZE_W(FrameSimulator, noisy_measurement_reset_y, { + auto rng = INDEPENDENT_TEST_RNG(); auto r = sample_batch_measurements( Circuit(R"CIRCUIT( RY 0 @@ -1300,7 +1319,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, noisy_measurement_reset_y, { )CIRCUIT"), simd_bits(0), 10000, - SHARED_TEST_RNG(), + rng, false); ASSERT_FALSE(r[1].not_zero()); auto m1 = r[0].popcnt(); @@ -1316,7 +1335,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, noisy_measurement_reset_y, { )CIRCUIT"), simd_bits(0), 5000, - SHARED_TEST_RNG(), + rng, false); auto m2 = r[0].popcnt() + r[1].popcnt(); ASSERT_LT(m2, 10000 - 300); @@ -1326,6 +1345,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, noisy_measurement_reset_y, { }) TEST_EACH_WORD_SIZE_W(FrameSimulator, noisy_measurement_reset_z, { + auto rng = INDEPENDENT_TEST_RNG(); auto r = sample_batch_measurements( Circuit(R"CIRCUIT( RZ 0 @@ -1334,7 +1354,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, noisy_measurement_reset_z, { )CIRCUIT"), simd_bits(0), 10000, - SHARED_TEST_RNG(), + rng, false); ASSERT_FALSE(r[1].not_zero()); auto m1 = r[0].popcnt(); @@ -1350,7 +1370,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, noisy_measurement_reset_z, { )CIRCUIT"), simd_bits(0), 5000, - SHARED_TEST_RNG(), + rng, false); auto m2 = r[0].popcnt() + r[1].popcnt(); ASSERT_LT(m2, 10000 - 300); @@ -1360,6 +1380,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, noisy_measurement_reset_z, { }) TEST_EACH_WORD_SIZE_W(FrameSimulator, measure_pauli_product_4body, { + auto rng = INDEPENDENT_TEST_RNG(); auto r = sample_batch_measurements( Circuit(R"CIRCUIT( X_ERROR(0.5) 0 1 2 3 @@ -1371,7 +1392,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, measure_pauli_product_4body, { )CIRCUIT"), simd_bits(0), 10, - SHARED_TEST_RNG(), + rng, false); for (size_t k = 0; k < 10; k++) { auto x0123 = r[0][k]; @@ -1391,6 +1412,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, measure_pauli_product_4body, { }) TEST_EACH_WORD_SIZE_W(FrameSimulator, non_deterministic_pauli_product_detectors, { + auto rng = INDEPENDENT_TEST_RNG(); auto n = sample_batch_measurements( Circuit(R"CIRCUIT( MPP Z8*X9 @@ -1398,7 +1420,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, non_deterministic_pauli_product_detectors, )CIRCUIT"), simd_bits(0), 1000, - SHARED_TEST_RNG(), + rng, false)[0] .popcnt(); ASSERT_TRUE(400 < n && n < 600); @@ -1410,7 +1432,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, non_deterministic_pauli_product_detectors, )CIRCUIT"), simd_bits(0), 1000, - SHARED_TEST_RNG(), + rng, false)[0] .popcnt(); ASSERT_TRUE(400 < n && n < 600); @@ -1422,13 +1444,14 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, non_deterministic_pauli_product_detectors, )CIRCUIT"), simd_bits(0), 1000, - SHARED_TEST_RNG(), + rng, false)[0] .popcnt(); ASSERT_TRUE(400 < n && n < 600); }) TEST_EACH_WORD_SIZE_W(FrameSimulator, ignores_sweep_controls_when_given_no_sweep_data, { + auto rng = INDEPENDENT_TEST_RNG(); auto n = sample_batch_measurements( Circuit(R"CIRCUIT( CNOT sweep[0] 0 @@ -1437,7 +1460,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, ignores_sweep_controls_when_given_no_sweep )CIRCUIT"), simd_bits(0), 1000, - SHARED_TEST_RNG(), + rng, false)[0] .popcnt(); ASSERT_EQ(n, 0); @@ -1451,18 +1474,19 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, reconfigure_for, { )CIRCUIT"); FrameSimulator frame_sim( - circuit.compute_stats(), FrameSimulatorMode::STORE_DETECTIONS_TO_MEMORY, 0, SHARED_TEST_RNG()); + circuit.compute_stats(), FrameSimulatorMode::STORE_DETECTIONS_TO_MEMORY, 0, INDEPENDENT_TEST_RNG()); frame_sim.configure_for(circuit.compute_stats(), FrameSimulatorMode::STORE_DETECTIONS_TO_MEMORY, 256); frame_sim.reset_all_and_run(circuit); ASSERT_EQ(frame_sim.det_record.storage[0].popcnt(), 256); }) TEST_EACH_WORD_SIZE_W(FrameSimulator, mpad, { + auto rng = INDEPENDENT_TEST_RNG(); auto circuit = Circuit(R"CIRCUIT( MPAD 0 1 )CIRCUIT"); - auto sample = sample_batch_measurements( - circuit, TableauSimulator::reference_sample_circuit(circuit), 100, SHARED_TEST_RNG(), false); + auto sample = + sample_batch_measurements(circuit, TableauSimulator::reference_sample_circuit(circuit), 100, rng, false); for (size_t k = 0; k < 100; k++) { ASSERT_EQ(sample[0][k], false); ASSERT_EQ(sample[1][k], true); @@ -1470,6 +1494,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, mpad, { }) TEST_EACH_WORD_SIZE_W(FrameSimulator, mxxyyzz_basis, { + auto rng = INDEPENDENT_TEST_RNG(); auto circuit = Circuit(R"CIRCUIT( RX 0 1 MXX 0 1 @@ -1478,8 +1503,8 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, mxxyyzz_basis, { RZ 0 1 MZZ 0 1 )CIRCUIT"); - auto sample = sample_batch_measurements( - circuit, TableauSimulator::reference_sample_circuit(circuit), 100, SHARED_TEST_RNG(), false); + auto sample = + sample_batch_measurements(circuit, TableauSimulator::reference_sample_circuit(circuit), 100, rng, false); for (size_t k = 0; k < 100; k++) { ASSERT_EQ(sample[0][k], false); ASSERT_EQ(sample[1][k], false); @@ -1488,13 +1513,14 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, mxxyyzz_basis, { }) TEST_EACH_WORD_SIZE_W(FrameSimulator, mxxyyzz_inversion, { + auto rng = INDEPENDENT_TEST_RNG(); auto circuit = Circuit(R"CIRCUIT( MXX 0 1 0 !1 !0 1 !0 !1 MYY 0 1 0 !1 !0 1 !0 !1 MZZ 0 1 0 !1 !0 1 !0 !1 )CIRCUIT"); - auto sample = sample_batch_measurements( - circuit, TableauSimulator::reference_sample_circuit(circuit), 100, SHARED_TEST_RNG(), false); + auto sample = + sample_batch_measurements(circuit, TableauSimulator::reference_sample_circuit(circuit), 100, rng, false); for (size_t k = 0; k < 100; k++) { ASSERT_EQ(sample[1][k], !sample[0][k]); ASSERT_EQ(sample[2][k], !sample[0][k]); @@ -1510,9 +1536,10 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, mxxyyzz_inversion, { }) TEST_EACH_WORD_SIZE_W(FrameSimulator, runs_on_general_circuit, { + auto rng = INDEPENDENT_TEST_RNG(); auto circuit = generate_test_circuit_with_all_operations(); - auto sample = sample_batch_measurements( - circuit, TableauSimulator::reference_sample_circuit(circuit), 100, SHARED_TEST_RNG(), false); + auto sample = + sample_batch_measurements(circuit, TableauSimulator::reference_sample_circuit(circuit), 100, rng, false); ASSERT_GT(sample.num_simd_words_minor, 0); ASSERT_GT(sample.num_simd_words_major, 0); }) @@ -1531,7 +1558,7 @@ TEST_EACH_WORD_SIZE_W(FrameSimulator, heralded_erase_detect_statistics, { size_t n; std::array bins{}; FrameSimulator sim( - circuit.compute_stats(), FrameSimulatorMode::STORE_DETECTIONS_TO_MEMORY, 1024, SHARED_TEST_RNG()); + circuit.compute_stats(), FrameSimulatorMode::STORE_DETECTIONS_TO_MEMORY, 1024, INDEPENDENT_TEST_RNG()); for (n = 0; n < 1024 * 256; n += 1024) { sim.reset_all_and_run(circuit); auto sample = sim.det_record.storage.transposed(); diff --git a/src/stim/simulators/frame_simulator_util.inl b/src/stim/simulators/frame_simulator_util.inl index d4366f0c2..3607ceb94 100644 --- a/src/stim/simulators/frame_simulator_util.inl +++ b/src/stim/simulators/frame_simulator_util.inl @@ -22,8 +22,9 @@ namespace stim { template std::pair, simd_bit_table> sample_batch_detection_events( const Circuit &circuit, size_t num_shots, std::mt19937_64 &rng) { - FrameSimulator sim(circuit.compute_stats(), FrameSimulatorMode::STORE_DETECTIONS_TO_MEMORY, num_shots, rng); + FrameSimulator sim(circuit.compute_stats(), FrameSimulatorMode::STORE_DETECTIONS_TO_MEMORY, num_shots, std::move(rng)); sim.reset_all_and_run(circuit); + rng = std::move(sim.rng); // Update input rng as if it was used directly, by moving the updated state out of the simulator. return std::pair, simd_bit_table>{ std::move(sim.det_record.storage), @@ -237,7 +238,7 @@ void sample_batch_detection_events_writing_results_to_disk( stats, streaming ? FrameSimulatorMode::STREAM_DETECTIONS_TO_DISK : FrameSimulatorMode::STORE_DETECTIONS_TO_MEMORY, batch_size, - rng); + std::move(rng)); // Will copy rng state back out later. // Run the frame simulator until as many shots as requested have been written. simd_bit_table out_concat_buf(0, 0); @@ -275,6 +276,9 @@ void sample_batch_detection_events_writing_results_to_disk( } shots_left -= shots_performed; } + + // Update input rng as if it was used directly, by moving the updated state out of the simulator. + rng = std::move(frame_sim.rng); } template @@ -284,9 +288,10 @@ simd_bit_table sample_batch_measurements( size_t num_samples, std::mt19937_64 &rng, bool transposed) { - FrameSimulator sim(circuit.compute_stats(), FrameSimulatorMode::STORE_MEASUREMENTS_TO_MEMORY, num_samples, rng); + FrameSimulator sim(circuit.compute_stats(), FrameSimulatorMode::STORE_MEASUREMENTS_TO_MEMORY, num_samples, std::move(rng)); sim.reset_all_and_run(circuit); simd_bit_table result = std::move(sim.m_record.storage); + rng = std::move(sim.rng); // Update input rng as if it was used directly, by moving the updated state out of the simulator. if (reference_sample.not_zero()) { result = transposed_vs_ref(num_samples, result, reference_sample); @@ -337,7 +342,7 @@ void sample_batch_measurements_writing_results_to_disk( circuit.compute_stats(), streaming ? FrameSimulatorMode::STREAM_MEASUREMENTS_TO_DISK : FrameSimulatorMode::STORE_MEASUREMENTS_TO_MEMORY, batch_size, - rng); + std::move(rng)); // Temporarily move rng into simulator. // Run the frame simulator until as many shots as requested have been written. size_t shots_left = num_shots; @@ -352,6 +357,9 @@ void sample_batch_measurements_writing_results_to_disk( } shots_left -= shots_performed; } + + // Update input rng as if it was used directly, by moving the updated state out of the simulator. + rng = std::move(frame_sim.rng); } } // namespace stim diff --git a/src/stim/simulators/frame_simulator_util.test.cc b/src/stim/simulators/frame_simulator_util.test.cc index e555a9008..651de8a79 100644 --- a/src/stim/simulators/frame_simulator_util.test.cc +++ b/src/stim/simulators/frame_simulator_util.test.cc @@ -24,7 +24,8 @@ using namespace stim; template simd_bit_table sample_test_detection_events(const Circuit &circuit, size_t num_shots) { - return sample_batch_detection_events(circuit, num_shots, SHARED_TEST_RNG()).first; + auto rng = INDEPENDENT_TEST_RNG(); + return sample_batch_detection_events(circuit, num_shots, rng).first; } TEST_EACH_WORD_SIZE_W(DetectionSimulator, sample_test_detection_events, { @@ -47,6 +48,7 @@ TEST_EACH_WORD_SIZE_W(DetectionSimulator, bad_detector, { }) TEST_EACH_WORD_SIZE_W(DetectionSimulator, sample_batch_detection_events_writing_results_to_disk, { + auto rng = INDEPENDENT_TEST_RNG(); auto circuit = Circuit(R"circuit( X_ERROR(1) 0 M 0 1 @@ -57,26 +59,27 @@ TEST_EACH_WORD_SIZE_W(DetectionSimulator, sample_batch_detection_events_writing_ FILE *tmp = tmpfile(); sample_batch_detection_events_writing_results_to_disk( - circuit, 2, false, false, tmp, SAMPLE_FORMAT_DETS, SHARED_TEST_RNG(), nullptr, SAMPLE_FORMAT_01); + circuit, 2, false, false, tmp, SAMPLE_FORMAT_DETS, rng, nullptr, SAMPLE_FORMAT_01); ASSERT_EQ(rewind_read_close(tmp), "shot D1\nshot D1\n"); tmp = tmpfile(); sample_batch_detection_events_writing_results_to_disk( - circuit, 2, true, false, tmp, SAMPLE_FORMAT_DETS, SHARED_TEST_RNG(), nullptr, SAMPLE_FORMAT_01); + circuit, 2, true, false, tmp, SAMPLE_FORMAT_DETS, rng, nullptr, SAMPLE_FORMAT_01); ASSERT_EQ(rewind_read_close(tmp), "shot L4 D1\nshot L4 D1\n"); tmp = tmpfile(); sample_batch_detection_events_writing_results_to_disk( - circuit, 2, false, true, tmp, SAMPLE_FORMAT_DETS, SHARED_TEST_RNG(), nullptr, SAMPLE_FORMAT_01); + circuit, 2, false, true, tmp, SAMPLE_FORMAT_DETS, rng, nullptr, SAMPLE_FORMAT_01); ASSERT_EQ(rewind_read_close(tmp), "shot D1 L4\nshot D1 L4\n"); tmp = tmpfile(); sample_batch_detection_events_writing_results_to_disk( - circuit, 2, false, true, tmp, SAMPLE_FORMAT_HITS, SHARED_TEST_RNG(), nullptr, SAMPLE_FORMAT_01); + circuit, 2, false, true, tmp, SAMPLE_FORMAT_HITS, rng, nullptr, SAMPLE_FORMAT_01); ASSERT_EQ(rewind_read_close(tmp), "1,6\n1,6\n"); }) TEST_EACH_WORD_SIZE_W(DetectionSimulator, stream_many_shots, { + auto rng = INDEPENDENT_TEST_RNG(); DebugForceResultStreamingRaii force_streaming; auto circuit = Circuit(R"circuit( X_ERROR(1) 1 @@ -87,7 +90,7 @@ TEST_EACH_WORD_SIZE_W(DetectionSimulator, stream_many_shots, { )circuit"); FILE *tmp = tmpfile(); sample_batch_detection_events_writing_results_to_disk( - circuit, 2048, false, false, tmp, SAMPLE_FORMAT_01, SHARED_TEST_RNG(), nullptr, SAMPLE_FORMAT_01); + circuit, 2048, false, false, tmp, SAMPLE_FORMAT_01, rng, nullptr, SAMPLE_FORMAT_01); auto result = rewind_read_close(tmp); for (size_t k = 0; k < 2048 * 4; k += 4) { @@ -99,6 +102,7 @@ TEST_EACH_WORD_SIZE_W(DetectionSimulator, stream_many_shots, { }) TEST_EACH_WORD_SIZE_W(DetectionSimulator, block_results_single_shot, { + auto rng = INDEPENDENT_TEST_RNG(); auto circuit = Circuit(R"circuit( REPEAT 10000 { M 0 @@ -113,7 +117,7 @@ TEST_EACH_WORD_SIZE_W(DetectionSimulator, block_results_single_shot, { )circuit"); FILE *tmp = tmpfile(); sample_batch_detection_events_writing_results_to_disk( - circuit, 1, false, true, tmp, SAMPLE_FORMAT_01, SHARED_TEST_RNG(), nullptr, SAMPLE_FORMAT_01); + circuit, 1, false, true, tmp, SAMPLE_FORMAT_01, rng, nullptr, SAMPLE_FORMAT_01); auto result = rewind_read_close(tmp); for (size_t k = 0; k < 30000; k += 3) { @@ -125,6 +129,7 @@ TEST_EACH_WORD_SIZE_W(DetectionSimulator, block_results_single_shot, { }) TEST_EACH_WORD_SIZE_W(DetectionSimulator, block_results_triple_shot, { + auto rng = INDEPENDENT_TEST_RNG(); auto circuit = Circuit(R"circuit( REPEAT 10000 { M 0 @@ -139,7 +144,7 @@ TEST_EACH_WORD_SIZE_W(DetectionSimulator, block_results_triple_shot, { )circuit"); FILE *tmp = tmpfile(); sample_batch_detection_events_writing_results_to_disk( - circuit, 3, false, true, tmp, SAMPLE_FORMAT_01, SHARED_TEST_RNG(), nullptr, SAMPLE_FORMAT_01); + circuit, 3, false, true, tmp, SAMPLE_FORMAT_01, rng, nullptr, SAMPLE_FORMAT_01); auto result = rewind_read_close(tmp); for (size_t rep = 0; rep < 3; rep++) { @@ -154,6 +159,7 @@ TEST_EACH_WORD_SIZE_W(DetectionSimulator, block_results_triple_shot, { }) TEST_EACH_WORD_SIZE_W(DetectionSimulator, stream_results, { + auto rng = INDEPENDENT_TEST_RNG(); DebugForceResultStreamingRaii force_streaming; auto circuit = Circuit(R"circuit( REPEAT 10000 { @@ -171,7 +177,7 @@ TEST_EACH_WORD_SIZE_W(DetectionSimulator, stream_results, { RaiiTempNamedFile tmp; FILE *f = fopen(tmp.path.c_str(), "w"); sample_batch_detection_events_writing_results_to_disk( - circuit, 1, false, true, f, SAMPLE_FORMAT_01, SHARED_TEST_RNG(), nullptr, SAMPLE_FORMAT_01); + circuit, 1, false, true, f, SAMPLE_FORMAT_01, rng, nullptr, SAMPLE_FORMAT_01); fclose(f); auto result = tmp.read_contents(); @@ -184,6 +190,7 @@ TEST_EACH_WORD_SIZE_W(DetectionSimulator, stream_results, { }) TEST_EACH_WORD_SIZE_W(DetectionSimulator, stream_results_triple_shot, { + auto rng = INDEPENDENT_TEST_RNG(); DebugForceResultStreamingRaii force_streaming; auto circuit = Circuit(R"circuit( REPEAT 10000 { @@ -199,7 +206,7 @@ TEST_EACH_WORD_SIZE_W(DetectionSimulator, stream_results_triple_shot, { )circuit"); FILE *tmp = tmpfile(); sample_batch_detection_events_writing_results_to_disk( - circuit, 3, false, true, tmp, SAMPLE_FORMAT_01, SHARED_TEST_RNG(), nullptr, SAMPLE_FORMAT_01); + circuit, 3, false, true, tmp, SAMPLE_FORMAT_01, rng, nullptr, SAMPLE_FORMAT_01); auto result = rewind_read_close(tmp); for (size_t rep = 0; rep < 3; rep++) { @@ -418,6 +425,7 @@ TEST_EACH_WORD_SIZE_W(DetectionSimulator, noisy_measure_reset_z, { }) TEST_EACH_WORD_SIZE_W(DetectionSimulator, obs_data, { + auto rng = INDEPENDENT_TEST_RNG(); auto circuit = Circuit(R"circuit( REPEAT 399 { X_ERROR(1) 0 @@ -439,7 +447,7 @@ TEST_EACH_WORD_SIZE_W(DetectionSimulator, obs_data, { FILE *det_tmp = tmpfile(); FILE *obs_tmp = tmpfile(); sample_batch_detection_events_writing_results_to_disk( - circuit, 1001, false, false, det_tmp, SAMPLE_FORMAT_B8, SHARED_TEST_RNG(), obs_tmp, SAMPLE_FORMAT_B8); + circuit, 1001, false, false, det_tmp, SAMPLE_FORMAT_B8, rng, obs_tmp, SAMPLE_FORMAT_B8); auto det_saved = rewind_read_close(det_tmp); auto obs_saved = rewind_read_close(obs_tmp); diff --git a/src/stim/simulators/measurements_to_detection_events.inl b/src/stim/simulators/measurements_to_detection_events.inl index a6d271407..535198f73 100644 --- a/src/stim/simulators/measurements_to_detection_events.inl +++ b/src/stim/simulators/measurements_to_detection_events.inl @@ -58,9 +58,7 @@ void measurements_to_detection_events_helper( // The frame simulator is used to account for flips in the measurement results that originate from the sweep data. // Eg. a `CNOT sweep[5] 0` can bit flip qubit 0, which can invert later measurement results, which will invert the // expected parity of detectors involving that measurement. This can vary from shot to shot. - std::mt19937_64 rng1(0); - std::mt19937_64 rng2(0); // Used to sanity check that rng1 isn't called. - FrameSimulator frame_sim(circuit_stats, FrameSimulatorMode::STREAM_DETECTIONS_TO_DISK, batch_size, rng1); + FrameSimulator frame_sim(circuit_stats, FrameSimulatorMode::STREAM_DETECTIONS_TO_DISK, batch_size, std::mt19937_64(0)); frame_sim.sweep_table = sweep_bits__minor_shot_index; frame_sim.guarantee_anticommutation_via_frame_randomization = false; @@ -121,7 +119,8 @@ void measurements_to_detection_events_helper( } // Safety check verifying no randomness was used by the frame simulator. - if (rng1() != rng2()) { + std::mt19937_64 fresh_rng(0); + if (frame_sim.rng() != fresh_rng() || frame_sim.rng() != fresh_rng() || frame_sim.rng() != fresh_rng()) { throw std::invalid_argument("Something is wrong. Converting measurements consumed entropy, but it shouldn't."); } } diff --git a/src/stim/simulators/sparse_rev_frame_tracker.test.cc b/src/stim/simulators/sparse_rev_frame_tracker.test.cc index 0ff2c3f83..c638a7d9a 100644 --- a/src/stim/simulators/sparse_rev_frame_tracker.test.cc +++ b/src/stim/simulators/sparse_rev_frame_tracker.test.cc @@ -142,7 +142,7 @@ static std::vector qubit_targets(const std::vector &target } TEST_EACH_WORD_SIZE_W(SparseUnsignedRevFrameTracker, fuzz_all_unitary_gates_vs_tableau, { - auto &rng = SHARED_TEST_RNG(); + auto rng = INDEPENDENT_TEST_RNG(); for (const auto &gate : GATE_DATA.items) { if (gate.flags & GATE_IS_UNITARY) { size_t n = (gate.flags & GATE_TARGETS_PAIRS) ? 2 : 1; diff --git a/src/stim/simulators/tableau_simulator.h b/src/stim/simulators/tableau_simulator.h index 49fdc6380..b9e7ca123 100644 --- a/src/stim/simulators/tableau_simulator.h +++ b/src/stim/simulators/tableau_simulator.h @@ -51,11 +51,11 @@ struct TableauSimulator { /// sign_bias: 0 means collapse randomly, -1 means collapse towards True, +1 means collapse towards False. /// record: Measurement record configuration. explicit TableauSimulator( - std::mt19937_64 rng, size_t num_qubits = 0, int8_t sign_bias = 0, MeasureRecord record = MeasureRecord()); + std::mt19937_64 &&rng, size_t num_qubits = 0, int8_t sign_bias = 0, MeasureRecord record = MeasureRecord()); /// Args: /// other: TableauSimulator to copy state from. /// rng: The random number generator to use for random operations. - TableauSimulator(const TableauSimulator &other, std::mt19937_64 rng); + TableauSimulator(const TableauSimulator &other, std::mt19937_64 &&rng); /// Samples the given circuit in a deterministic fashion. /// diff --git a/src/stim/simulators/tableau_simulator.inl b/src/stim/simulators/tableau_simulator.inl index 3717a05ce..27e42117a 100644 --- a/src/stim/simulators/tableau_simulator.inl +++ b/src/stim/simulators/tableau_simulator.inl @@ -24,7 +24,7 @@ namespace stim { template -TableauSimulator::TableauSimulator(std::mt19937_64 rng, size_t num_qubits, int8_t sign_bias, MeasureRecord record) +TableauSimulator::TableauSimulator(std::mt19937_64 &&rng, size_t num_qubits, int8_t sign_bias, MeasureRecord record) : inv_state(Tableau::identity(num_qubits)), rng(std::move(rng)), sign_bias(sign_bias), @@ -33,7 +33,7 @@ TableauSimulator::TableauSimulator(std::mt19937_64 rng, size_t num_qubits, in } template -TableauSimulator::TableauSimulator(const TableauSimulator &other, std::mt19937_64 rng) +TableauSimulator::TableauSimulator(const TableauSimulator &other, std::mt19937_64 &&rng) : inv_state(other.inv_state), rng(std::move(rng)), sign_bias(other.sign_bias), diff --git a/src/stim/simulators/tableau_simulator.perf.cc b/src/stim/simulators/tableau_simulator.perf.cc index d672b6cc0..790f73411 100644 --- a/src/stim/simulators/tableau_simulator.perf.cc +++ b/src/stim/simulators/tableau_simulator.perf.cc @@ -20,8 +20,7 @@ using namespace stim; BENCHMARK(TableauSimulator_CX_10Kqubits) { size_t num_qubits = 10 * 1000; - std::mt19937_64 rng(0); // NOLINT(cert-msc51-cpp) - TableauSimulator sim(rng, num_qubits); + TableauSimulator sim(std::mt19937_64(0), num_qubits); std::vector targets; for (uint32_t k = 0; k < (uint32_t)num_qubits; k++) { diff --git a/src/stim/simulators/tableau_simulator.pybind.cc b/src/stim/simulators/tableau_simulator.pybind.cc index 0d4610030..ed1199962 100644 --- a/src/stim/simulators/tableau_simulator.pybind.cc +++ b/src/stim/simulators/tableau_simulator.pybind.cc @@ -50,7 +50,7 @@ void do_obj(TableauSimulator &self, const pybind11::object &obj) { template TableauSimulator create_tableau_simulator(const pybind11::object &seed) { - return TableauSimulator(*make_py_seeded_rng(seed)); + return TableauSimulator(make_py_seeded_rng(seed)); } template @@ -562,7 +562,7 @@ void stim_pybind::pybind_tableau_simulator_methods( c.def( "h", - [](TableauSimulator &self, pybind11::args args) { + [](TableauSimulator &self, const pybind11::args &args) { self.do_H_XZ(build_single_qubit_gate_instruction_ensure_size(self, GateType::H, args)); }, clean_doc_string(R"DOC( @@ -682,7 +682,7 @@ void stim_pybind::pybind_tableau_simulator_methods( c.def( "h_xz", - [](TableauSimulator &self, pybind11::args args) { + [](TableauSimulator &self, const pybind11::args &args) { self.do_H_XZ(build_single_qubit_gate_instruction_ensure_size(self, GateType::H, args)); }, clean_doc_string(R"DOC( @@ -695,7 +695,7 @@ void stim_pybind::pybind_tableau_simulator_methods( c.def( "c_xyz", - [](TableauSimulator &self, pybind11::args args) { + [](TableauSimulator &self, const pybind11::args &args) { self.do_C_XYZ( build_single_qubit_gate_instruction_ensure_size(self, GateType::C_XYZ, args)); }, @@ -709,7 +709,7 @@ void stim_pybind::pybind_tableau_simulator_methods( c.def( "c_zyx", - [](TableauSimulator &self, pybind11::args args) { + [](TableauSimulator &self, const pybind11::args &args) { self.do_C_ZYX( build_single_qubit_gate_instruction_ensure_size(self, GateType::C_ZYX, args)); }, @@ -723,7 +723,7 @@ void stim_pybind::pybind_tableau_simulator_methods( c.def( "h_xy", - [](TableauSimulator &self, pybind11::args args) { + [](TableauSimulator &self, const pybind11::args &args) { self.do_H_XY( build_single_qubit_gate_instruction_ensure_size(self, GateType::H_XY, args)); }, @@ -737,7 +737,7 @@ void stim_pybind::pybind_tableau_simulator_methods( c.def( "h_yz", - [](TableauSimulator &self, pybind11::args args) { + [](TableauSimulator &self, const pybind11::args &args) { self.do_H_YZ( build_single_qubit_gate_instruction_ensure_size(self, GateType::H_YZ, args)); }, @@ -751,7 +751,7 @@ void stim_pybind::pybind_tableau_simulator_methods( c.def( "x", - [](TableauSimulator &self, pybind11::args args) { + [](TableauSimulator &self, const pybind11::args &args) { self.do_X(build_single_qubit_gate_instruction_ensure_size(self, GateType::X, args)); }, clean_doc_string(R"DOC( @@ -764,7 +764,7 @@ void stim_pybind::pybind_tableau_simulator_methods( c.def( "y", - [](TableauSimulator &self, pybind11::args args) { + [](TableauSimulator &self, const pybind11::args &args) { self.do_Y(build_single_qubit_gate_instruction_ensure_size(self, GateType::Y, args)); }, clean_doc_string(R"DOC( @@ -790,7 +790,7 @@ void stim_pybind::pybind_tableau_simulator_methods( c.def( "s", - [](TableauSimulator &self, pybind11::args args) { + [](TableauSimulator &self, const pybind11::args &args) { self.do_SQRT_Z(build_single_qubit_gate_instruction_ensure_size(self, GateType::S, args)); }, clean_doc_string(R"DOC( @@ -803,7 +803,7 @@ void stim_pybind::pybind_tableau_simulator_methods( c.def( "s_dag", - [](TableauSimulator &self, pybind11::args args) { + [](TableauSimulator &self, const pybind11::args &args) { self.do_SQRT_Z_DAG( build_single_qubit_gate_instruction_ensure_size(self, GateType::S_DAG, args)); }, @@ -817,7 +817,7 @@ void stim_pybind::pybind_tableau_simulator_methods( c.def( "sqrt_x", - [](TableauSimulator &self, pybind11::args args) { + [](TableauSimulator &self, const pybind11::args &args) { self.do_SQRT_X( build_single_qubit_gate_instruction_ensure_size(self, GateType::SQRT_X, args)); }, @@ -831,7 +831,7 @@ void stim_pybind::pybind_tableau_simulator_methods( c.def( "sqrt_x_dag", - [](TableauSimulator &self, pybind11::args args) { + [](TableauSimulator &self, const pybind11::args &args) { self.do_SQRT_X_DAG( build_single_qubit_gate_instruction_ensure_size(self, GateType::SQRT_X_DAG, args)); }, @@ -845,7 +845,7 @@ void stim_pybind::pybind_tableau_simulator_methods( c.def( "sqrt_y", - [](TableauSimulator &self, pybind11::args args) { + [](TableauSimulator &self, const pybind11::args &args) { self.do_SQRT_Y( build_single_qubit_gate_instruction_ensure_size(self, GateType::SQRT_Y, args)); }, @@ -859,7 +859,7 @@ void stim_pybind::pybind_tableau_simulator_methods( c.def( "sqrt_y_dag", - [](TableauSimulator &self, pybind11::args args) { + [](TableauSimulator &self, const pybind11::args &args) { self.do_SQRT_Y_DAG( build_single_qubit_gate_instruction_ensure_size(self, GateType::SQRT_Y_DAG, args)); }, @@ -873,7 +873,7 @@ void stim_pybind::pybind_tableau_simulator_methods( c.def( "swap", - [](TableauSimulator &self, pybind11::args args) { + [](TableauSimulator &self, const pybind11::args &args) { self.do_SWAP(build_two_qubit_gate_instruction_ensure_size(self, GateType::SWAP, args)); }, clean_doc_string(R"DOC( @@ -888,7 +888,7 @@ void stim_pybind::pybind_tableau_simulator_methods( c.def( "iswap", - [](TableauSimulator &self, pybind11::args args) { + [](TableauSimulator &self, const pybind11::args &args) { self.do_ISWAP(build_two_qubit_gate_instruction_ensure_size(self, GateType::ISWAP, args)); }, clean_doc_string(R"DOC( @@ -903,7 +903,7 @@ void stim_pybind::pybind_tableau_simulator_methods( c.def( "iswap_dag", - [](TableauSimulator &self, pybind11::args args) { + [](TableauSimulator &self, const pybind11::args &args) { self.do_ISWAP_DAG( build_two_qubit_gate_instruction_ensure_size(self, GateType::ISWAP_DAG, args)); }, @@ -919,7 +919,7 @@ void stim_pybind::pybind_tableau_simulator_methods( c.def( "cnot", - [](TableauSimulator &self, pybind11::args args) { + [](TableauSimulator &self, const pybind11::args &args) { self.do_ZCX(build_two_qubit_gate_instruction_ensure_size(self, GateType::CX, args)); }, clean_doc_string(R"DOC( @@ -934,7 +934,7 @@ void stim_pybind::pybind_tableau_simulator_methods( c.def( "zcx", - [](TableauSimulator &self, pybind11::args args) { + [](TableauSimulator &self, const pybind11::args &args) { self.do_ZCX(build_two_qubit_gate_instruction_ensure_size(self, GateType::CX, args)); }, clean_doc_string(R"DOC( @@ -949,7 +949,7 @@ void stim_pybind::pybind_tableau_simulator_methods( c.def( "cx", - [](TableauSimulator &self, pybind11::args args) { + [](TableauSimulator &self, const pybind11::args &args) { self.do_ZCX(build_two_qubit_gate_instruction_ensure_size(self, GateType::CX, args)); }, clean_doc_string(R"DOC( @@ -964,7 +964,7 @@ void stim_pybind::pybind_tableau_simulator_methods( c.def( "cz", - [](TableauSimulator &self, pybind11::args args) { + [](TableauSimulator &self, const pybind11::args &args) { self.do_ZCZ(build_two_qubit_gate_instruction_ensure_size(self, GateType::CZ, args)); }, clean_doc_string(R"DOC( @@ -979,7 +979,7 @@ void stim_pybind::pybind_tableau_simulator_methods( c.def( "zcz", - [](TableauSimulator &self, pybind11::args args) { + [](TableauSimulator &self, const pybind11::args &args) { self.do_ZCZ(build_two_qubit_gate_instruction_ensure_size(self, GateType::CZ, args)); }, clean_doc_string(R"DOC( @@ -994,7 +994,7 @@ void stim_pybind::pybind_tableau_simulator_methods( c.def( "cy", - [](TableauSimulator &self, pybind11::args args) { + [](TableauSimulator &self, const pybind11::args &args) { self.do_ZCY(build_two_qubit_gate_instruction_ensure_size(self, GateType::CY, args)); }, clean_doc_string(R"DOC( @@ -1009,7 +1009,7 @@ void stim_pybind::pybind_tableau_simulator_methods( c.def( "zcy", - [](TableauSimulator &self, pybind11::args args) { + [](TableauSimulator &self, const pybind11::args &args) { self.do_ZCY(build_two_qubit_gate_instruction_ensure_size(self, GateType::CY, args)); }, clean_doc_string(R"DOC( @@ -1024,7 +1024,7 @@ void stim_pybind::pybind_tableau_simulator_methods( c.def( "xcx", - [](TableauSimulator &self, pybind11::args args) { + [](TableauSimulator &self, const pybind11::args &args) { self.do_XCX(build_two_qubit_gate_instruction_ensure_size(self, GateType::XCX, args)); }, clean_doc_string(R"DOC( @@ -1039,7 +1039,7 @@ void stim_pybind::pybind_tableau_simulator_methods( c.def( "xcy", - [](TableauSimulator &self, pybind11::args args) { + [](TableauSimulator &self, const pybind11::args &args) { self.do_XCY(build_two_qubit_gate_instruction_ensure_size(self, GateType::XCY, args)); }, clean_doc_string(R"DOC( @@ -1054,7 +1054,7 @@ void stim_pybind::pybind_tableau_simulator_methods( c.def( "xcz", - [](TableauSimulator &self, pybind11::args args) { + [](TableauSimulator &self, const pybind11::args &args) { self.do_XCZ(build_two_qubit_gate_instruction_ensure_size(self, GateType::XCZ, args)); }, clean_doc_string(R"DOC( @@ -1069,7 +1069,7 @@ void stim_pybind::pybind_tableau_simulator_methods( c.def( "ycx", - [](TableauSimulator &self, pybind11::args args) { + [](TableauSimulator &self, const pybind11::args &args) { self.do_YCX(build_two_qubit_gate_instruction_ensure_size(self, GateType::YCX, args)); }, clean_doc_string(R"DOC( @@ -1084,7 +1084,7 @@ void stim_pybind::pybind_tableau_simulator_methods( c.def( "ycy", - [](TableauSimulator &self, pybind11::args args) { + [](TableauSimulator &self, const pybind11::args &args) { self.do_YCY(build_two_qubit_gate_instruction_ensure_size(self, GateType::YCY, args)); }, clean_doc_string(R"DOC( @@ -1099,7 +1099,7 @@ void stim_pybind::pybind_tableau_simulator_methods( c.def( "ycz", - [](TableauSimulator &self, pybind11::args args) { + [](TableauSimulator &self, const pybind11::args &args) { self.do_YCZ(build_two_qubit_gate_instruction_ensure_size(self, GateType::YCZ, args)); }, clean_doc_string(R"DOC( @@ -1114,7 +1114,7 @@ void stim_pybind::pybind_tableau_simulator_methods( c.def( "reset", - [](TableauSimulator &self, pybind11::args args) { + [](TableauSimulator &self, const pybind11::args &args) { self.do_RZ(build_single_qubit_gate_instruction_ensure_size(self, GateType::R, args)); }, clean_doc_string(R"DOC( @@ -1135,7 +1135,7 @@ void stim_pybind::pybind_tableau_simulator_methods( c.def( "reset_x", - [](TableauSimulator &self, pybind11::args args) { + [](TableauSimulator &self, const pybind11::args &args) { self.do_RX(build_single_qubit_gate_instruction_ensure_size(self, GateType::RX, args)); }, clean_doc_string(R"DOC( @@ -1155,7 +1155,7 @@ void stim_pybind::pybind_tableau_simulator_methods( c.def( "reset_y", - [](TableauSimulator &self, pybind11::args args) { + [](TableauSimulator &self, const pybind11::args &args) { self.do_RY(build_single_qubit_gate_instruction_ensure_size(self, GateType::RY, args)); }, clean_doc_string(R"DOC( @@ -1175,7 +1175,7 @@ void stim_pybind::pybind_tableau_simulator_methods( c.def( "reset_z", - [](TableauSimulator &self, pybind11::args args) { + [](TableauSimulator &self, const pybind11::args &args) { self.do_RZ(build_single_qubit_gate_instruction_ensure_size(self, GateType::R, args)); }, clean_doc_string(R"DOC( @@ -1536,7 +1536,7 @@ void stim_pybind::pybind_tableau_simulator_methods( c.def( "measure_many", - [](TableauSimulator &self, pybind11::args args) { + [](TableauSimulator &self, const pybind11::args &args) { auto converted_args = build_single_qubit_gate_instruction_ensure_size(self, GateType::M, args); self.do_MZ(converted_args); @@ -1798,7 +1798,7 @@ void stim_pybind::pybind_tableau_simulator_methods( } if (!copy_rng || !seed.is_none()) { - TableauSimulator copy_with_new_rng(self, *make_py_seeded_rng(seed)); + TableauSimulator copy_with_new_rng(self, make_py_seeded_rng(seed)); return copy_with_new_rng; } diff --git a/src/stim/simulators/tableau_simulator.test.cc b/src/stim/simulators/tableau_simulator.test.cc index c3bc4211d..5e737150e 100644 --- a/src/stim/simulators/tableau_simulator.test.cc +++ b/src/stim/simulators/tableau_simulator.test.cc @@ -42,7 +42,7 @@ struct OpDat { }; TEST_EACH_WORD_SIZE_W(TableauSimulator, identity, { - auto s = TableauSimulator(SHARED_TEST_RNG(), 1); + auto s = TableauSimulator(INDEPENDENT_TEST_RNG(), 1); ASSERT_EQ(s.measurement_record.storage, (std::vector{})); s.do_MZ({GateType::Z, {}, qubit_targets({0})}); ASSERT_EQ(s.measurement_record.storage, (std::vector{false})); @@ -51,7 +51,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, identity, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, bit_flip, { - auto s = TableauSimulator(SHARED_TEST_RNG(), 1); + auto s = TableauSimulator(INDEPENDENT_TEST_RNG(), 1); s.do_H_XZ(OpDat(0)); s.do_SQRT_Z(OpDat(0)); s.do_SQRT_Z(OpDat(0)); @@ -63,7 +63,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, bit_flip, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, identity2, { - auto s = TableauSimulator(SHARED_TEST_RNG(), 2); + auto s = TableauSimulator(INDEPENDENT_TEST_RNG(), 2); s.do_MZ(OpDat(0)); ASSERT_EQ(s.measurement_record.storage, (std::vector{false})); s.do_MZ(OpDat(1)); @@ -71,7 +71,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, identity2, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, bit_flip_2, { - auto s = TableauSimulator(SHARED_TEST_RNG(), 2); + auto s = TableauSimulator(INDEPENDENT_TEST_RNG(), 2); s.do_H_XZ(OpDat(0)); s.do_SQRT_Z(OpDat(0)); s.do_SQRT_Z(OpDat(0)); @@ -83,7 +83,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, bit_flip_2, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, epr, { - auto s = TableauSimulator(SHARED_TEST_RNG(), 2); + auto s = TableauSimulator(INDEPENDENT_TEST_RNG(), 2); s.do_H_XZ(OpDat(0)); s.do_ZCX(OpDat({0, 1})); ASSERT_EQ(s.is_deterministic_z(0), false); @@ -96,7 +96,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, epr, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, big_determinism, { - auto s = TableauSimulator(SHARED_TEST_RNG(), 1000); + auto s = TableauSimulator(INDEPENDENT_TEST_RNG(), 1000); s.do_H_XZ(OpDat(0)); s.do_H_YZ(OpDat(1)); ASSERT_FALSE(s.is_deterministic_z(0)); @@ -114,7 +114,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, big_determinism, { TEST_EACH_WORD_SIZE_W(TableauSimulator, phase_kickback_consume_s_state, { for (size_t k = 0; k < 8; k++) { - auto s = TableauSimulator(SHARED_TEST_RNG(), 2); + auto s = TableauSimulator(INDEPENDENT_TEST_RNG(), 2); s.do_H_XZ(OpDat(1)); s.do_SQRT_Z(OpDat(1)); s.do_H_XZ(OpDat(0)); @@ -135,7 +135,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, phase_kickback_consume_s_state, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, phase_kickback_preserve_s_state, { - auto s = TableauSimulator(SHARED_TEST_RNG(), 2); + auto s = TableauSimulator(INDEPENDENT_TEST_RNG(), 2); // Prepare S state. s.do_H_XZ(OpDat(1)); @@ -164,7 +164,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, phase_kickback_preserve_s_state, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, kickback_vs_stabilizer, { - auto sim = TableauSimulator(SHARED_TEST_RNG(), 3); + auto sim = TableauSimulator(INDEPENDENT_TEST_RNG(), 3); sim.do_H_XZ(OpDat(2)); sim.do_ZCX(OpDat({2, 0})); sim.do_ZCX(OpDat({2, 1})); @@ -184,7 +184,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, kickback_vs_stabilizer, { TEST_EACH_WORD_SIZE_W(TableauSimulator, s_state_distillation_low_depth, { for (size_t reps = 0; reps < 10; reps++) { - auto sim = TableauSimulator(SHARED_TEST_RNG(), 9); + auto sim = TableauSimulator(INDEPENDENT_TEST_RNG(), 9); std::vector> stabilizers = { {0, 1, 2, 3}, @@ -255,7 +255,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, s_state_distillation_low_depth, { TEST_EACH_WORD_SIZE_W(TableauSimulator, s_state_distillation_low_space, { for (size_t rep = 0; rep < 10; rep++) { - auto sim = TableauSimulator(SHARED_TEST_RNG(), 5); + auto sim = TableauSimulator(INDEPENDENT_TEST_RNG(), 5); std::vector> phasors = { { @@ -307,8 +307,9 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, s_state_distillation_low_space, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, unitary_gates_consistent_with_tableau_data, { - auto t = Tableau::random(10, SHARED_TEST_RNG()); - TableauSimulator sim(SHARED_TEST_RNG(), 10); + auto rng = INDEPENDENT_TEST_RNG(); + auto t = Tableau::random(10, rng); + TableauSimulator sim(INDEPENDENT_TEST_RNG(), 10); for (const auto &gate : GATE_DATA.items) { if (!(gate.flags & GATE_IS_UNITARY)) { continue; @@ -328,8 +329,8 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, unitary_gates_consistent_with_tableau_da }) TEST_EACH_WORD_SIZE_W(TableauSimulator, certain_errors_consistent_with_gates, { - TableauSimulator sim1(SHARED_TEST_RNG(), 2); - TableauSimulator sim2(SHARED_TEST_RNG(), 2); + TableauSimulator sim1(INDEPENDENT_TEST_RNG(), 2); + TableauSimulator sim2(INDEPENDENT_TEST_RNG(), 2); GateTarget targets[]{GateTarget{0}}; double p0 = 0.0; double p1 = 1.0; @@ -356,18 +357,20 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, certain_errors_consistent_with_gates, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, simulate, { + auto rng = INDEPENDENT_TEST_RNG(); auto results = TableauSimulator::sample_circuit( Circuit("H 0\n" "CNOT 0 1\n" "M 0\n" "M 1\n" "M 2\n"), - SHARED_TEST_RNG()); + rng); ASSERT_EQ(results[0], results[1]); ASSERT_EQ(results[2], false); }) TEST_EACH_WORD_SIZE_W(TableauSimulator, simulate_reset, { + auto rng = INDEPENDENT_TEST_RNG(); auto results = TableauSimulator::sample_circuit( Circuit("X 0\n" "M 0\n" @@ -375,14 +378,15 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, simulate_reset, { "M 0\n" "R 0\n" "M 0\n"), - SHARED_TEST_RNG()); + rng); ASSERT_EQ(results[0], true); ASSERT_EQ(results[1], false); ASSERT_EQ(results[2], false); }) TEST_EACH_WORD_SIZE_W(TableauSimulator, to_vector_sim, { - TableauSimulator sim_tab(SHARED_TEST_RNG(), 2); + auto rng = INDEPENDENT_TEST_RNG(); + TableauSimulator sim_tab(INDEPENDENT_TEST_RNG(), 2); VectorSimulator sim_vec(2); ASSERT_TRUE(sim_tab.to_vector_sim().approximate_equals(sim_vec, true)); @@ -402,7 +406,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, to_vector_sim, { sim_vec.apply("ZCX", 0, 1); ASSERT_TRUE(sim_tab.to_vector_sim().approximate_equals(sim_vec, true)); - sim_tab.inv_state = Tableau::random(10, SHARED_TEST_RNG()); + sim_tab.inv_state = Tableau::random(10, rng); sim_vec = sim_tab.to_vector_sim(); ASSERT_TRUE(sim_tab.to_vector_sim().approximate_equals(sim_vec, true)); @@ -412,13 +416,13 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, to_vector_sim, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, to_state_vector, { - auto v = TableauSimulator(SHARED_TEST_RNG(), 0).to_state_vector(true); + auto v = TableauSimulator(INDEPENDENT_TEST_RNG(), 0).to_state_vector(true); ASSERT_EQ(v.size(), 1); auto r = v[0].real(); auto i = v[0].imag(); ASSERT_LT(r * r + i * i - 1, 1e-4); - TableauSimulator sim_tab(SHARED_TEST_RNG(), 3); + TableauSimulator sim_tab(INDEPENDENT_TEST_RNG(), 3); auto sim_vec = sim_tab.to_vector_sim(); VectorSimulator sim_vec2(3); sim_vec2.state = sim_tab.to_state_vector(true); @@ -431,7 +435,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, to_state_vector_endian, { sim_vec0.apply("H", 0); sim_vec2.apply("H", 2); - TableauSimulator sim_tab(SHARED_TEST_RNG(), 3); + TableauSimulator sim_tab(INDEPENDENT_TEST_RNG(), 3); sim_tab.do_H_XZ(OpDat(2)); VectorSimulator cmp(3); @@ -442,7 +446,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, to_state_vector_endian, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, to_state_vector_canonical, { - TableauSimulator sim_tab(SHARED_TEST_RNG(), 3); + TableauSimulator sim_tab(INDEPENDENT_TEST_RNG(), 3); sim_tab.do_H_XZ(OpDat(2)); std::vector expected; @@ -464,7 +468,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, to_state_vector_canonical, { template bool vec_sim_corroborates_measurement_process( const Tableau &state, const std::vector &measurement_targets) { - TableauSimulator sim_tab(SHARED_TEST_RNG(), 2); + TableauSimulator sim_tab(INDEPENDENT_TEST_RNG(), 2); sim_tab.inv_state = state; auto vec_sim = sim_tab.to_vector_sim(); sim_tab.do_MZ(OpDat(measurement_targets)); @@ -483,20 +487,21 @@ bool vec_sim_corroborates_measurement_process( } TEST_EACH_WORD_SIZE_W(TableauSimulator, measurement_vs_vector_sim, { + auto rng = INDEPENDENT_TEST_RNG(); for (size_t k = 0; k < 10; k++) { - auto state = Tableau::random(2, SHARED_TEST_RNG()); + auto state = Tableau::random(2, rng); ASSERT_TRUE(vec_sim_corroborates_measurement_process(state, {0})); ASSERT_TRUE(vec_sim_corroborates_measurement_process(state, {1})); ASSERT_TRUE(vec_sim_corroborates_measurement_process(state, {0, 1})); } for (size_t k = 0; k < 10; k++) { - auto state = Tableau::random(4, SHARED_TEST_RNG()); + auto state = Tableau::random(4, rng); ASSERT_TRUE(vec_sim_corroborates_measurement_process(state, {0, 1})); ASSERT_TRUE(vec_sim_corroborates_measurement_process(state, {2, 1})); ASSERT_TRUE(vec_sim_corroborates_measurement_process(state, {0, 1, 2, 3})); } { - auto state = Tableau::random(12, SHARED_TEST_RNG()); + auto state = Tableau::random(12, rng); ASSERT_TRUE(vec_sim_corroborates_measurement_process(state, {0, 1, 2, 3})); ASSERT_TRUE(vec_sim_corroborates_measurement_process(state, {0, 10, 11})); ASSERT_TRUE(vec_sim_corroborates_measurement_process(state, {11, 5, 7})); @@ -505,6 +510,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, measurement_vs_vector_sim, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, correlated_error, { + auto rng = INDEPENDENT_TEST_RNG(); simd_bits expected(5); expected.clear(); @@ -516,7 +522,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, correlated_error, { ELSE_CORRELATED_ERROR(0) X2 X3 M 0 1 2 3 )circuit"), - SHARED_TEST_RNG()), + rng), expected); expected.clear(); @@ -530,7 +536,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, correlated_error, { ELSE_CORRELATED_ERROR(0) X2 X3 M 0 1 2 3 )circuit"), - SHARED_TEST_RNG()), + rng), expected); expected.clear(); @@ -544,7 +550,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, correlated_error, { ELSE_CORRELATED_ERROR(0) X2 X3 M 0 1 2 3 )circuit"), - SHARED_TEST_RNG()), + rng), expected); expected.clear(); @@ -558,7 +564,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, correlated_error, { ELSE_CORRELATED_ERROR(1) X2 X3 M 0 1 2 3 )circuit"), - SHARED_TEST_RNG()), + rng), expected); expected.clear(); @@ -572,7 +578,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, correlated_error, { ELSE_CORRELATED_ERROR(0) X2 X3 M 0 1 2 3 )circuit"), - SHARED_TEST_RNG()), + rng), expected); expected.clear(); @@ -586,7 +592,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, correlated_error, { ELSE_CORRELATED_ERROR(1) X2 X3 M 0 1 2 3 )circuit"), - SHARED_TEST_RNG()), + rng), expected); expected.clear(); @@ -603,12 +609,11 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, correlated_error, { CORRELATED_ERROR(1) X3 X4 M 0 1 2 3 4 )circuit"), - SHARED_TEST_RNG()), + rng), expected); int hits[3]{}; size_t n = 10000; - std::mt19937_64 rng(0); for (size_t k = 0; k < n; k++) { auto sample = TableauSimulator::sample_circuit( Circuit(R"circuit( @@ -628,6 +633,8 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, correlated_error, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, quantum_cannot_control_classical, { + auto rng = INDEPENDENT_TEST_RNG(); + // Quantum controlling classical operation is not allowed. ASSERT_THROW( { @@ -636,7 +643,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, quantum_cannot_control_classical, { M 0 CNOT 1 rec[-1] )circuit"), - SHARED_TEST_RNG()); + rng); }, std::invalid_argument); ASSERT_THROW( @@ -646,7 +653,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, quantum_cannot_control_classical, { M 0 CY 1 rec[-1] )circuit"), - SHARED_TEST_RNG()); + rng); }, std::invalid_argument); ASSERT_THROW( @@ -656,7 +663,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, quantum_cannot_control_classical, { M 0 YCZ rec[-1] 1 )circuit"), - SHARED_TEST_RNG()); + rng); }, std::invalid_argument); ASSERT_THROW( @@ -666,7 +673,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, quantum_cannot_control_classical, { M 0 XCZ rec[-1] 1 )circuit"), - SHARED_TEST_RNG()); + rng); }, std::invalid_argument); ASSERT_THROW( @@ -676,12 +683,13 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, quantum_cannot_control_classical, { M 0 SWAP 1 rec[-1] )circuit"), - SHARED_TEST_RNG()); + rng); }, std::invalid_argument); }) TEST_EACH_WORD_SIZE_W(TableauSimulator, classical_can_control_quantum, { + auto rng = INDEPENDENT_TEST_RNG(); simd_bits expected(5); expected.clear(); expected[0] = true; @@ -693,7 +701,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, classical_can_control_quantum, { CX rec[-1] 1 M 1 )circuit"), - SHARED_TEST_RNG()), + rng), expected); ASSERT_EQ( TableauSimulator::sample_circuit( @@ -702,7 +710,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, classical_can_control_quantum, { CY rec[-1] 1 M 1 )circuit"), - SHARED_TEST_RNG()), + rng), expected); ASSERT_EQ( TableauSimulator::sample_circuit( @@ -711,7 +719,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, classical_can_control_quantum, { XCZ 1 rec[-1] M 1 )circuit"), - SHARED_TEST_RNG()), + rng), expected); ASSERT_EQ( TableauSimulator::sample_circuit( @@ -720,11 +728,12 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, classical_can_control_quantum, { YCZ 1 rec[-1] M 1 )circuit"), - SHARED_TEST_RNG()), + rng), expected); }) TEST_EACH_WORD_SIZE_W(TableauSimulator, classical_control_cases, { + auto rng = INDEPENDENT_TEST_RNG(); simd_bits expected(5); expected.clear(); expected[0] = true; @@ -738,7 +747,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, classical_control_cases, { H 1 M 1 )circuit"), - SHARED_TEST_RNG()), + rng), expected); expected.clear(); @@ -751,7 +760,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, classical_control_cases, { CY rec[-1] 1 M 1 )circuit"), - SHARED_TEST_RNG()), + rng), expected); expected.clear(); @@ -764,7 +773,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, classical_control_cases, { CX rec[-1] 1 M 1 )circuit"), - SHARED_TEST_RNG()), + rng), expected); expected.clear(); @@ -784,19 +793,20 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, classical_control_cases, { CX rec[-1] 2 M 1 2 3 )circuit"), - SHARED_TEST_RNG()), + rng), expected); }) TEST_EACH_WORD_SIZE_W(TableauSimulator, mr_repeated_target, { + auto rng = INDEPENDENT_TEST_RNG(); simd_bits expected(2); expected[0] = true; - auto r = TableauSimulator::sample_circuit(Circuit("X 0\nMR 0 0"), SHARED_TEST_RNG()); + auto r = TableauSimulator::sample_circuit(Circuit("X 0\nMR 0 0"), rng); ASSERT_EQ(r, expected); }) TEST_EACH_WORD_SIZE_W(TableauSimulator, peek_bloch, { - TableauSimulator sim(SHARED_TEST_RNG(), 3); + TableauSimulator sim(INDEPENDENT_TEST_RNG(), 3); ASSERT_EQ(sim.peek_bloch(0), PauliString::from_str("+Z")); ASSERT_EQ(sim.peek_bloch(1), PauliString::from_str("+Z")); ASSERT_EQ(sim.peek_bloch(2), PauliString::from_str("+Z")); @@ -854,9 +864,10 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, peek_bloch, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, paulis, { - TableauSimulator sim1(SHARED_TEST_RNG(), 500); - TableauSimulator sim2(SHARED_TEST_RNG(), 500); - sim1.inv_state = Tableau::random(500, SHARED_TEST_RNG()); + auto rng = INDEPENDENT_TEST_RNG(); + TableauSimulator sim1(INDEPENDENT_TEST_RNG(), 500); + TableauSimulator sim2(INDEPENDENT_TEST_RNG(), 500); + sim1.inv_state = Tableau::random(500, rng); sim2.inv_state = sim1.inv_state; sim1.paulis(PauliString(500)); @@ -874,9 +885,10 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, paulis, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, set_num_qubits, { - TableauSimulator sim1(SHARED_TEST_RNG(), 10); - TableauSimulator sim2(SHARED_TEST_RNG(), 10); - sim1.inv_state = Tableau::random(10, SHARED_TEST_RNG()); + auto rng = INDEPENDENT_TEST_RNG(); + TableauSimulator sim1(INDEPENDENT_TEST_RNG(), 10); + TableauSimulator sim2(INDEPENDENT_TEST_RNG(), 10); + sim1.inv_state = Tableau::random(10, rng); sim2.inv_state = sim1.inv_state; sim1.set_num_qubits(20); @@ -897,8 +909,9 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, set_num_qubits, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, set_num_qubits_reduce_random, { - TableauSimulator sim(SHARED_TEST_RNG(), 10); - sim.inv_state = Tableau::random(10, SHARED_TEST_RNG()); + auto rng = INDEPENDENT_TEST_RNG(); + TableauSimulator sim(INDEPENDENT_TEST_RNG(), 10); + sim.inv_state = Tableau::random(10, rng); sim.set_num_qubits(5); ASSERT_EQ(sim.inv_state.num_qubits, 5); ASSERT_TRUE(sim.inv_state.satisfies_invariants()); @@ -906,7 +919,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, set_num_qubits_reduce_random, { template void scramble_stabilizers(TableauSimulator &s) { - auto &rng = SHARED_TEST_RNG(); + auto rng = INDEPENDENT_TEST_RNG(); TableauTransposedRaii tmp(s.inv_state); for (size_t i = 0; i < s.inv_state.num_qubits; i++) { for (size_t j = i + 1; j < s.inv_state.num_qubits; j++) { @@ -927,7 +940,7 @@ void scramble_stabilizers(TableauSimulator &s) { } TEST_EACH_WORD_SIZE_W(TableauSimulator, canonical_stabilizers, { - TableauSimulator sim(SHARED_TEST_RNG(), 2); + TableauSimulator sim(INDEPENDENT_TEST_RNG(), 2); sim.do_H_XZ(OpDat(0)); sim.do_ZCX(OpDat({0, 1})); ASSERT_EQ( @@ -969,8 +982,9 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, canonical_stabilizers, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, canonical_stabilizers_random, { - TableauSimulator sim(SHARED_TEST_RNG(), 4); - sim.inv_state = Tableau::random(4, SHARED_TEST_RNG()); + auto rng = INDEPENDENT_TEST_RNG(); + TableauSimulator sim(INDEPENDENT_TEST_RNG(), 4); + sim.inv_state = Tableau::random(4, rng); auto s1 = sim.canonical_stabilizers(); scramble_stabilizers(sim); auto s2 = sim.canonical_stabilizers(); @@ -978,9 +992,9 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, canonical_stabilizers_random, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, set_num_qubits_reduce_preserves_scrambled_stabilizers, { - auto &rng = SHARED_TEST_RNG(); - TableauSimulator sim(rng, 4); - sim.inv_state = Tableau::random(4, SHARED_TEST_RNG()); + auto rng = INDEPENDENT_TEST_RNG(); + TableauSimulator sim(INDEPENDENT_TEST_RNG(), 4); + sim.inv_state = Tableau::random(4, rng); auto s1 = sim.canonical_stabilizers(); sim.inv_state.expand(8, 1.0); scramble_stabilizers(sim); @@ -990,7 +1004,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, set_num_qubits_reduce_preserves_scramble }) TEST_EACH_WORD_SIZE_W(TableauSimulator, measure_kickback_z, { - TableauSimulator sim(SHARED_TEST_RNG(), 4); + TableauSimulator sim(INDEPENDENT_TEST_RNG(), 4); sim.do_H_XZ(OpDat({0, 2})); sim.do_ZCX(OpDat({0, 1, 2, 3})); auto k1 = sim.measure_kickback_z(GateTarget::qubit(1)); @@ -1009,7 +1023,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, measure_kickback_z, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, measure_kickback_x, { - TableauSimulator sim(SHARED_TEST_RNG(), 4); + TableauSimulator sim(INDEPENDENT_TEST_RNG(), 4); sim.do_H_XZ(OpDat({0, 2})); sim.do_ZCX(OpDat({0, 1, 2, 3})); auto k1 = sim.measure_kickback_x(GateTarget::qubit(1)); @@ -1028,7 +1042,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, measure_kickback_x, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, measure_kickback_y, { - TableauSimulator sim(SHARED_TEST_RNG(), 4); + TableauSimulator sim(INDEPENDENT_TEST_RNG(), 4); sim.do_H_XZ(OpDat({0, 2})); sim.do_ZCX(OpDat({0, 1, 2, 3})); auto k1 = sim.measure_kickback_y(GateTarget::qubit(1)); @@ -1047,8 +1061,9 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, measure_kickback_y, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, measure_kickback_isolates, { - TableauSimulator sim(SHARED_TEST_RNG(), 4); - sim.inv_state = Tableau::random(4, SHARED_TEST_RNG()); + auto rng = INDEPENDENT_TEST_RNG(); + TableauSimulator sim(INDEPENDENT_TEST_RNG(), 4); + sim.inv_state = Tableau::random(4, rng); for (size_t k = 0; k < 4; k++) { auto result = sim.measure_kickback_z(GateTarget::qubit(k)); for (size_t j = 0; j < result.second.num_qubits && j < k; j++) { @@ -1059,9 +1074,10 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, measure_kickback_isolates, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, collapse_isolate_completely, { + auto rng = INDEPENDENT_TEST_RNG(); for (size_t k = 0; k < 10; k++) { - TableauSimulator sim(SHARED_TEST_RNG(), 6); - sim.inv_state = Tableau::random(6, SHARED_TEST_RNG()); + TableauSimulator sim(INDEPENDENT_TEST_RNG(), 6); + sim.inv_state = Tableau::random(6, rng); { TableauTransposedRaii tmp(sim.inv_state); sim.collapse_isolate_qubit_z(2, tmp); @@ -1076,7 +1092,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, collapse_isolate_completely, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, reset_pure, { - TableauSimulator t(SHARED_TEST_RNG(), 1); + TableauSimulator t(INDEPENDENT_TEST_RNG(), 1); ASSERT_EQ(t.peek_bloch(0), PauliString::from_str("+Z")); t.do_RY(OpDat(0)); ASSERT_EQ(t.peek_bloch(0), PauliString::from_str("+Y")); @@ -1089,35 +1105,36 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, reset_pure, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, reset_random, { - TableauSimulator t(SHARED_TEST_RNG(), 5); + auto rng = INDEPENDENT_TEST_RNG(); + TableauSimulator t(INDEPENDENT_TEST_RNG(), 5); - t.inv_state = Tableau::random(5, SHARED_TEST_RNG()); + t.inv_state = Tableau::random(5, rng); t.do_RX(OpDat(0)); ASSERT_EQ(t.peek_bloch(0), PauliString::from_str("+X")); - t.inv_state = Tableau::random(5, SHARED_TEST_RNG()); + t.inv_state = Tableau::random(5, rng); t.do_RY(OpDat(0)); ASSERT_EQ(t.peek_bloch(0), PauliString::from_str("+Y")); - t.inv_state = Tableau::random(5, SHARED_TEST_RNG()); + t.inv_state = Tableau::random(5, rng); t.do_RZ(OpDat(0)); ASSERT_EQ(t.peek_bloch(0), PauliString::from_str("+Z")); - t.inv_state = Tableau::random(5, SHARED_TEST_RNG()); + t.inv_state = Tableau::random(5, rng); t.do_MRX(OpDat(0)); ASSERT_EQ(t.peek_bloch(0), PauliString::from_str("+X")); - t.inv_state = Tableau::random(5, SHARED_TEST_RNG()); + t.inv_state = Tableau::random(5, rng); t.do_MRY(OpDat(0)); ASSERT_EQ(t.peek_bloch(0), PauliString::from_str("+Y")); - t.inv_state = Tableau::random(5, SHARED_TEST_RNG()); + t.inv_state = Tableau::random(5, rng); t.do_MRZ(OpDat(0)); ASSERT_EQ(t.peek_bloch(0), PauliString::from_str("+Z")); }) TEST_EACH_WORD_SIZE_W(TableauSimulator, reset_x_entangled, { - TableauSimulator t(SHARED_TEST_RNG(), 2); + TableauSimulator t(INDEPENDENT_TEST_RNG(), 2); t.do_H_XZ(OpDat(0)); t.do_ZCX(OpDat({0, 1})); t.do_RX(OpDat(0)); @@ -1129,7 +1146,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, reset_x_entangled, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, reset_y_entangled, { - TableauSimulator t(SHARED_TEST_RNG(), 2); + TableauSimulator t(INDEPENDENT_TEST_RNG(), 2); t.do_H_XZ(OpDat(0)); t.do_ZCX(OpDat({0, 1})); t.do_RY(OpDat(0)); @@ -1141,7 +1158,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, reset_y_entangled, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, reset_z_entangled, { - TableauSimulator t(SHARED_TEST_RNG(), 2); + TableauSimulator t(INDEPENDENT_TEST_RNG(), 2); t.do_H_XZ(OpDat(0)); t.do_ZCX(OpDat({0, 1})); t.do_RZ(OpDat(0)); @@ -1153,7 +1170,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, reset_z_entangled, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, measure_x_entangled, { - TableauSimulator t(SHARED_TEST_RNG(), 2); + TableauSimulator t(INDEPENDENT_TEST_RNG(), 2); t.do_H_XZ(OpDat(0)); t.do_ZCX(OpDat({0, 1})); t.do_MX(OpDat(0)); @@ -1167,7 +1184,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, measure_x_entangled, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, measure_y_entangled, { - TableauSimulator t(SHARED_TEST_RNG(), 2); + TableauSimulator t(INDEPENDENT_TEST_RNG(), 2); t.do_H_XZ(OpDat(0)); t.do_ZCX(OpDat({0, 1})); t.do_MY(OpDat(0)); @@ -1181,7 +1198,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, measure_y_entangled, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, measure_z_entangled, { - TableauSimulator t(SHARED_TEST_RNG(), 2); + TableauSimulator t(INDEPENDENT_TEST_RNG(), 2); t.do_H_XZ(OpDat(0)); t.do_ZCX(OpDat({0, 1})); t.do_MZ(OpDat(0)); @@ -1195,7 +1212,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, measure_z_entangled, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, measure_reset_x_entangled, { - TableauSimulator t(SHARED_TEST_RNG(), 2); + TableauSimulator t(INDEPENDENT_TEST_RNG(), 2); t.do_H_XZ(OpDat(0)); t.do_ZCX(OpDat({0, 1})); t.do_MRX(OpDat(0)); @@ -1208,7 +1225,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, measure_reset_x_entangled, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, measure_reset_y_entangled, { - TableauSimulator t(SHARED_TEST_RNG(), 2); + TableauSimulator t(INDEPENDENT_TEST_RNG(), 2); t.do_H_XZ(OpDat(0)); t.do_ZCX(OpDat({0, 1})); t.do_MRY(OpDat(0)); @@ -1221,7 +1238,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, measure_reset_y_entangled, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, measure_reset_z_entangled, { - TableauSimulator t(SHARED_TEST_RNG(), 2); + TableauSimulator t(INDEPENDENT_TEST_RNG(), 2); t.do_H_XZ(OpDat(0)); t.do_ZCX(OpDat({0, 1})); t.do_MRZ(OpDat(0)); @@ -1234,13 +1251,14 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, measure_reset_z_entangled, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, reset_vs_measurements, { + auto rng = INDEPENDENT_TEST_RNG(); auto check = [&](const char *circuit, std::vector results) { simd_bits ref(results.size()); for (size_t k = 0; k < results.size(); k++) { ref[k] = results[k]; } for (size_t reps = 0; reps < 5; reps++) { - simd_bits t = TableauSimulator::sample_circuit(Circuit(circuit), SHARED_TEST_RNG()); + simd_bits t = TableauSimulator::sample_circuit(Circuit(circuit), rng); if (t != ref) { return false; } @@ -1406,7 +1424,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, sample_stream_mutates_rng_state, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, noisy_measurement_x, { - TableauSimulator t(SHARED_TEST_RNG()); + TableauSimulator t(INDEPENDENT_TEST_RNG()); t.expand_do_circuit(R"CIRCUIT( RX 0 REPEAT 10000 { @@ -1435,7 +1453,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, noisy_measurement_x, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, noisy_measurement_y, { - TableauSimulator t(SHARED_TEST_RNG()); + TableauSimulator t(INDEPENDENT_TEST_RNG()); t.expand_do_circuit(R"CIRCUIT( RY 0 REPEAT 10000 { @@ -1464,7 +1482,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, noisy_measurement_y, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, noisy_measurement_z, { - TableauSimulator t(SHARED_TEST_RNG()); + TableauSimulator t(INDEPENDENT_TEST_RNG()); t.expand_do_circuit(R"CIRCUIT( RZ 0 REPEAT 10000 { @@ -1493,7 +1511,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, noisy_measurement_z, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, noisy_measure_reset_x, { - TableauSimulator t(SHARED_TEST_RNG()); + TableauSimulator t(INDEPENDENT_TEST_RNG()); t.expand_do_circuit(R"CIRCUIT( RX 0 REPEAT 10000 { @@ -1522,7 +1540,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, noisy_measure_reset_x, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, noisy_measure_reset_y, { - TableauSimulator t(SHARED_TEST_RNG()); + TableauSimulator t(INDEPENDENT_TEST_RNG()); t.expand_do_circuit(R"CIRCUIT( RY 0 1 REPEAT 5000 { @@ -1551,7 +1569,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, noisy_measure_reset_y, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, noisy_measure_reset_z, { - TableauSimulator t(SHARED_TEST_RNG()); + TableauSimulator t(INDEPENDENT_TEST_RNG()); t.expand_do_circuit(R"CIRCUIT( RZ 0 1 REPEAT 5000 { @@ -1580,13 +1598,13 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, noisy_measure_reset_z, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, measure_pauli_product_bad, { - TableauSimulator t(SHARED_TEST_RNG()); + TableauSimulator t(INDEPENDENT_TEST_RNG()); ASSERT_THROW({ t.expand_do_circuit("MPP X0*X0"); }, std::invalid_argument); ASSERT_THROW({ t.expand_do_circuit("MPP X0*Z0"); }, std::invalid_argument); }) TEST_EACH_WORD_SIZE_W(TableauSimulator, measure_pauli_product_1, { - TableauSimulator t(SHARED_TEST_RNG()); + TableauSimulator t(INDEPENDENT_TEST_RNG()); t.expand_do_circuit(R"CIRCUIT( REPEAT 100 { RX 0 @@ -1601,7 +1619,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, measure_pauli_product_1, { TEST_EACH_WORD_SIZE_W(TableauSimulator, measure_pauli_product_4body, { for (size_t k = 0; k < 10; k++) { - TableauSimulator t(SHARED_TEST_RNG()); + TableauSimulator t(INDEPENDENT_TEST_RNG()); t.expand_do_circuit(R"CIRCUIT( MPP X0*X1*X2*X3 MX 0 1 2 3 4 5 @@ -1626,7 +1644,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, measure_pauli_product_4body, { TEST_EACH_WORD_SIZE_W(TableauSimulator, measure_pauli_product_epr, { for (size_t k = 0; k < 10; k++) { - TableauSimulator t(SHARED_TEST_RNG()); + TableauSimulator t(INDEPENDENT_TEST_RNG()); t.expand_do_circuit(R"CIRCUIT( MPP X0*X1 Z0*Z1 Y0*Y1 CNOT 0 1 @@ -1646,7 +1664,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, measure_pauli_product_epr, { TEST_EACH_WORD_SIZE_W(TableauSimulator, measure_pauli_product_inversions, { for (size_t k = 0; k < 10; k++) { - TableauSimulator t(SHARED_TEST_RNG()); + TableauSimulator t(INDEPENDENT_TEST_RNG()); t.expand_do_circuit(R"CIRCUIT( MPP !X0*!X1 !X0*X1 X0*!X1 X0*X1 X0 X1 !X0 !X1 )CIRCUIT"); @@ -1668,7 +1686,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, measure_pauli_product_inversions, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, measure_pauli_product_noisy, { - TableauSimulator t(SHARED_TEST_RNG()); + TableauSimulator t(INDEPENDENT_TEST_RNG()); t.expand_do_circuit(R"CIRCUIT( H 0 CNOT 0 1 @@ -1684,7 +1702,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, measure_pauli_product_noisy, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, ignores_sweep_controls, { - TableauSimulator t(SHARED_TEST_RNG()); + TableauSimulator t(INDEPENDENT_TEST_RNG()); t.expand_do_circuit(R"CIRCUIT( X 0 CNOT sweep[0] 0 @@ -1694,7 +1712,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, ignores_sweep_controls, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, peek_observable_expectation, { - TableauSimulator t(SHARED_TEST_RNG()); + TableauSimulator t(INDEPENDENT_TEST_RNG()); t.expand_do_circuit(R"CIRCUIT( H 0 CNOT 0 1 @@ -1718,7 +1736,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, peek_observable_expectation, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, postselect_x, { - TableauSimulator sim(SHARED_TEST_RNG(), 2); + TableauSimulator sim(INDEPENDENT_TEST_RNG(), 2); // Postselect from +X. sim.do_RX(OpDat(0)); @@ -1798,7 +1816,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, postselect_x, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, postselect_y, { - TableauSimulator sim(SHARED_TEST_RNG(), 2); + TableauSimulator sim(INDEPENDENT_TEST_RNG(), 2); // Postselect from +X. sim.do_RX(OpDat(0)); @@ -1878,7 +1896,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, postselect_y, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, postselect_z, { - TableauSimulator sim(SHARED_TEST_RNG(), 2); + TableauSimulator sim(INDEPENDENT_TEST_RNG(), 2); // Postselect from +X. sim.do_RX(OpDat(0)); @@ -1958,7 +1976,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, postselect_z, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, peek_x, { - TableauSimulator sim(SHARED_TEST_RNG(), 3); + TableauSimulator sim(INDEPENDENT_TEST_RNG(), 3); ASSERT_EQ(sim.peek_x(0), 0); ASSERT_EQ(sim.peek_y(0), 0); ASSERT_EQ(sim.peek_z(0), +1); @@ -2081,7 +2099,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, apply_tableau, { auto h = GATE_DATA.at("H").tableau(); auto cxyz = GATE_DATA.at("C_XYZ").tableau(); - TableauSimulator sim(SHARED_TEST_RNG(), 4); + TableauSimulator sim(INDEPENDENT_TEST_RNG(), 4); sim.apply_tableau(h, {1}); ASSERT_EQ(sim.peek_bloch(1), PauliString::from_str("+X")); sim.apply_tableau(s, {1}); @@ -2102,7 +2120,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, apply_tableau, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, measure_pauli_string, { - TableauSimulator sim(SHARED_TEST_RNG(), 4); + TableauSimulator sim(INDEPENDENT_TEST_RNG(), 4); sim.do_H_XZ(OpDat(0)); sim.do_ZCX(OpDat({0, 1})); sim.do_X(OpDat(0)); @@ -2151,13 +2169,13 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, measure_pauli_string, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, amortized_resizing, { - TableauSimulator sim(SHARED_TEST_RNG(), 5120); + TableauSimulator sim(INDEPENDENT_TEST_RNG(), 5120); sim.ensure_large_enough_for_qubits(5121); ASSERT_GT(sim.inv_state.xs.xt.num_minor_bits_padded(), 5600); }) TEST_EACH_WORD_SIZE_W(TableauSimulator, mpad, { - TableauSimulator sim(SHARED_TEST_RNG(), 5); + TableauSimulator sim(INDEPENDENT_TEST_RNG(), 5); ASSERT_EQ(sim.inv_state, Tableau(5)); ASSERT_EQ(sim.measurement_record.storage, (std::vector{})); @@ -2177,8 +2195,8 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, mpad, { template void expect_same_final_state(const Tableau &start, const Circuit &c1, const Circuit &c2, bool unsigned_stabilizers) { size_t n = start.num_qubits; - TableauSimulator sim1(SHARED_TEST_RNG(), n); - TableauSimulator sim2(SHARED_TEST_RNG(), n); + TableauSimulator sim1(INDEPENDENT_TEST_RNG(), n); + TableauSimulator sim2(INDEPENDENT_TEST_RNG(), n); sim1.inv_state = start; sim2.inv_state = start; sim1.expand_do_circuit(c1); @@ -2197,22 +2215,24 @@ void expect_same_final_state(const Tableau &start, const Circuit &c1, const C } TEST_EACH_WORD_SIZE_W(TableauSimulator, mxx_myy_mzz_vs_mpp_unsigned, { + auto rng = INDEPENDENT_TEST_RNG(); expect_same_final_state( - Tableau::random(5, SHARED_TEST_RNG()), Circuit("MXX 1 3 1 2 3 4"), Circuit("MPP X1*X3 X1*X2 X3*X4"), true); + Tableau::random(5, rng), Circuit("MXX 1 3 1 2 3 4"), Circuit("MPP X1*X3 X1*X2 X3*X4"), true); expect_same_final_state( - Tableau::random(5, SHARED_TEST_RNG()), Circuit("MYY 1 3 1 2 3 4"), Circuit("MPP Y1*Y3 Y1*Y2 Y3*Y4"), true); + Tableau::random(5, rng), Circuit("MYY 1 3 1 2 3 4"), Circuit("MPP Y1*Y3 Y1*Y2 Y3*Y4"), true); expect_same_final_state( - Tableau::random(5, SHARED_TEST_RNG()), Circuit("MZZ 1 3 1 2 3 4"), Circuit("MPP Z1*Z3 Z1*Z2 Z3*Z4"), true); + Tableau::random(5, rng), Circuit("MZZ 1 3 1 2 3 4"), Circuit("MPP Z1*Z3 Z1*Z2 Z3*Z4"), true); }) TEST_EACH_WORD_SIZE_W(TableauSimulator, mxx, { - TableauSimulator sim(SHARED_TEST_RNG(), 5); + auto rng = INDEPENDENT_TEST_RNG(); + TableauSimulator sim(INDEPENDENT_TEST_RNG(), 5); sim.expand_do_circuit(Circuit("RX 0 1")); sim.expand_do_circuit(Circuit("MXX 0 1")); ASSERT_EQ(sim.measurement_record.storage, (std::vector{false})); sim.measurement_record.storage.clear(); - sim.inv_state = Tableau::random(5, SHARED_TEST_RNG()); + sim.inv_state = Tableau::random(5, rng); sim.expand_do_circuit(Circuit("MXX 1 3")); bool x13 = sim.measurement_record.storage.back(); sim.measurement_record.storage.clear(); @@ -2242,13 +2262,14 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, mxx, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, myy, { - TableauSimulator sim(SHARED_TEST_RNG(), 5); + auto rng = INDEPENDENT_TEST_RNG(); + TableauSimulator sim(INDEPENDENT_TEST_RNG(), 5); sim.expand_do_circuit(Circuit("RY 0 1")); sim.expand_do_circuit(Circuit("MYY 0 1")); ASSERT_EQ(sim.measurement_record.storage, (std::vector{false})); sim.measurement_record.storage.clear(); - sim.inv_state = Tableau::random(5, SHARED_TEST_RNG()); + sim.inv_state = Tableau::random(5, rng); sim.expand_do_circuit(Circuit("MYY 1 3")); bool x13 = sim.measurement_record.storage.back(); sim.measurement_record.storage.clear(); @@ -2278,13 +2299,14 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, myy, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, mzz, { - TableauSimulator sim(SHARED_TEST_RNG(), 5); + auto rng = INDEPENDENT_TEST_RNG(); + TableauSimulator sim(INDEPENDENT_TEST_RNG(), 5); sim.expand_do_circuit(Circuit("RZ 0 1")); sim.expand_do_circuit(Circuit("MZZ 0 1")); ASSERT_EQ(sim.measurement_record.storage, (std::vector{false})); sim.measurement_record.storage.clear(); - sim.inv_state = Tableau::random(5, SHARED_TEST_RNG()); + sim.inv_state = Tableau::random(5, rng); sim.expand_do_circuit(Circuit("MZZ 1 3")); bool x13 = sim.measurement_record.storage.back(); sim.measurement_record.storage.clear(); @@ -2315,13 +2337,13 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, mzz, { TEST_EACH_WORD_SIZE_W(TableauSimulator, runs_on_general_circuit, { auto circuit = generate_test_circuit_with_all_operations(); - TableauSimulator sim(SHARED_TEST_RNG(), 1); + TableauSimulator sim(INDEPENDENT_TEST_RNG(), 1); sim.expand_do_circuit(circuit); ASSERT_GT(sim.inv_state.xs.num_qubits, 1); }) TEST_EACH_WORD_SIZE_W(TableauSimulator, heralded_erase, { - TableauSimulator sim(SHARED_TEST_RNG(), 1); + TableauSimulator sim(INDEPENDENT_TEST_RNG(), 1); sim.expand_do_circuit(Circuit(R"CIRCUIT( HERALDED_ERASE(0) 0 1 2 3 10 11 12 13 )CIRCUIT")); @@ -2337,7 +2359,7 @@ TEST_EACH_WORD_SIZE_W(TableauSimulator, heralded_erase, { }) TEST_EACH_WORD_SIZE_W(TableauSimulator, postselect_observable, { - TableauSimulator sim(SHARED_TEST_RNG(), 0); + TableauSimulator sim(INDEPENDENT_TEST_RNG(), 0); sim.postselect_observable(PauliString("ZZ"), false); sim.postselect_observable(PauliString("XX"), false); diff --git a/src/stim/stabilizers/conversions.inl b/src/stim/stabilizers/conversions.inl index e116c7f69..8f589b5fa 100644 --- a/src/stim/stabilizers/conversions.inl +++ b/src/stim/stabilizers/conversions.inl @@ -147,8 +147,7 @@ template Tableau circuit_to_tableau( const Circuit &circuit, bool ignore_noise, bool ignore_measurement, bool ignore_reset) { Tableau result(circuit.count_qubits()); - std::mt19937_64 unused_rng(0); - TableauSimulator sim(unused_rng, circuit.count_qubits()); + TableauSimulator sim(std::mt19937_64(0), circuit.count_qubits()); circuit.for_each_operation([&](const CircuitInstruction &op) { const auto &flags = GATE_DATA.items[op.gate_type].flags; @@ -188,8 +187,7 @@ Tableau circuit_to_tableau( template std::vector> circuit_to_output_state_vector(const Circuit &circuit, bool little_endian) { Tableau result(circuit.count_qubits()); - std::mt19937_64 unused_rng(0); - TableauSimulator sim(unused_rng, circuit.count_qubits()); + TableauSimulator sim(std::mt19937_64(0), circuit.count_qubits()); circuit.for_each_operation([&](const CircuitInstruction &op) { const auto &flags = GATE_DATA.items[op.gate_type].flags; diff --git a/src/stim/stabilizers/conversions.test.cc b/src/stim/stabilizers/conversions.test.cc index 7c6fb4ef7..2c103398b 100644 --- a/src/stim/stabilizers/conversions.test.cc +++ b/src/stim/stabilizers/conversions.test.cc @@ -215,11 +215,12 @@ TEST_EACH_WORD_SIZE_W(conversions, stabilizer_state_vector_to_circuit_basic, { }) TEST_EACH_WORD_SIZE_W(conversions, stabilizer_state_vector_to_circuit_fuzz_round_trip, { + auto rng = INDEPENDENT_TEST_RNG(); for (const auto &little_endian : std::vector{false, true}) { for (size_t n = 0; n < 10; n++) { // Pick a random stabilizer state. - TableauSimulator sim(SHARED_TEST_RNG(), n); - sim.inv_state = Tableau::random(n, SHARED_TEST_RNG()); + TableauSimulator sim(INDEPENDENT_TEST_RNG(), n); + sim.inv_state = Tableau::random(n, rng); auto desired_vec = sim.to_state_vector(little_endian); // Round trip through a circuit. @@ -430,8 +431,9 @@ TEST_EACH_WORD_SIZE_W(conversions, circuit_to_output_state_vector, { }) TEST_EACH_WORD_SIZE_W(conversions, tableau_to_circuit_fuzz_vs_circuit_to_tableau, { + auto rng = INDEPENDENT_TEST_RNG(); for (size_t n = 0; n < 10; n++) { - auto desired = Tableau::random(n, SHARED_TEST_RNG()); + auto desired = Tableau::random(n, rng); Circuit circuit = tableau_to_circuit(desired, "elimination"); auto actual = circuit_to_tableau(circuit, false, false, false); ASSERT_EQ(actual, desired); @@ -517,9 +519,10 @@ TEST_EACH_WORD_SIZE_W(conversions, unitary_vs_tableau_basic, { }) TEST_EACH_WORD_SIZE_W(conversions, unitary_to_tableau_fuzz_vs_tableau_to_unitary, { + auto rng = INDEPENDENT_TEST_RNG(); for (bool little_endian : std::vector{false, true}) { for (size_t n = 0; n < 6; n++) { - auto desired = Tableau::random(n, SHARED_TEST_RNG()); + auto desired = Tableau::random(n, rng); auto unitary = tableau_to_unitary(desired, little_endian); auto actual = unitary_to_tableau(unitary, little_endian); ASSERT_EQ(actual, desired) << "little_endian=" << little_endian << ", n=" << n; @@ -564,8 +567,9 @@ TEST_EACH_WORD_SIZE_W(conversions, unitary_to_tableau_fail, { }) TEST_EACH_WORD_SIZE_W(conversions, stabilizers_to_tableau_fuzz, { + auto rng = INDEPENDENT_TEST_RNG(); for (size_t n = 0; n < 10; n++) { - auto t = Tableau::random(n, SHARED_TEST_RNG()); + auto t = Tableau::random(n, rng); std::vector> expected_stabilizers; for (size_t k = 0; k < n; k++) { expected_stabilizers.push_back(t.zs[k]); @@ -580,9 +584,10 @@ TEST_EACH_WORD_SIZE_W(conversions, stabilizers_to_tableau_fuzz, { }) TEST_EACH_WORD_SIZE_W(conversions, stabilizers_to_tableau_partial_fuzz, { + auto rng = INDEPENDENT_TEST_RNG(); for (size_t n = 0; n < 10; n++) { for (size_t skipped = 1; skipped < n && skipped < 4; skipped++) { - auto t = Tableau::random(n, SHARED_TEST_RNG()); + auto t = Tableau::random(n, rng); std::vector> expected_stabilizers; for (size_t k = 0; k < n - skipped; k++) { expected_stabilizers.push_back(t.zs[k]); @@ -603,8 +608,9 @@ TEST_EACH_WORD_SIZE_W(conversions, stabilizers_to_tableau_partial_fuzz, { }) TEST_EACH_WORD_SIZE_W(conversions, stabilizers_to_tableau_overconstrained, { + auto rng = INDEPENDENT_TEST_RNG(); for (size_t n = 4; n < 10; n++) { - auto t = Tableau::random(n, SHARED_TEST_RNG()); + auto t = Tableau::random(n, rng); std::vector> expected_stabilizers; expected_stabilizers.push_back(PauliString(n)); expected_stabilizers.push_back(PauliString(n)); diff --git a/src/stim/stabilizers/pauli_string.pybind.cc b/src/stim/stabilizers/pauli_string.pybind.cc index 2d8316f2c..bcf6148ea 100644 --- a/src/stim/stabilizers/pauli_string.pybind.cc +++ b/src/stim/stabilizers/pauli_string.pybind.cc @@ -603,7 +603,7 @@ void stim_pybind::pybind_pauli_string_methods(pybind11::module &m, pybind11::cla [](size_t num_qubits, bool allow_imaginary) { auto rng = make_py_seeded_rng(pybind11::none()); return PyPauliString( - PauliString::random(num_qubits, *rng), allow_imaginary ? ((*rng)() & 1) : false); + PauliString::random(num_qubits, rng), allow_imaginary ? (rng() & 1) : false); }, pybind11::arg("num_qubits"), pybind11::kw_only(), diff --git a/src/stim/stabilizers/pauli_string.test.cc b/src/stim/stabilizers/pauli_string.test.cc index 57655fda4..b713aa7e4 100644 --- a/src/stim/stabilizers/pauli_string.test.cc +++ b/src/stim/stabilizers/pauli_string.test.cc @@ -215,8 +215,9 @@ TEST_EACH_WORD_SIZE_W(pauli_string, move_copy_assignment, { }) TEST_EACH_WORD_SIZE_W(pauli_string, foreign_memory, { + auto rng = INDEPENDENT_TEST_RNG(); size_t bits = 2048; - auto buffer = simd_bits::random(bits, SHARED_TEST_RNG()); + auto buffer = simd_bits::random(bits, rng); bool signs = false; size_t num_qubits = W * 2 - 12; diff --git a/src/stim/stabilizers/tableau.pybind.cc b/src/stim/stabilizers/tableau.pybind.cc index 64cc5d338..ce5eb5d8f 100644 --- a/src/stim/stabilizers/tableau.pybind.cc +++ b/src/stim/stabilizers/tableau.pybind.cc @@ -179,7 +179,8 @@ void stim_pybind::pybind_tableau_methods(pybind11::module &m, pybind11::class_::random(num_qubits, *make_py_seeded_rng(pybind11::none())); + auto rng = make_py_seeded_rng(pybind11::none()); + return Tableau::random(num_qubits, rng); }, pybind11::arg("num_qubits"), clean_doc_string(R"DOC( @@ -2121,8 +2122,7 @@ void stim_pybind::pybind_tableau_methods(pybind11::module &m, pybind11::class_ sim(unused_rng, self.num_qubits); + TableauSimulator sim(std::mt19937_64{0}, self.num_qubits); sim.inv_state = self.inverse(false); auto complex_vec = sim.to_state_vector(little_endian); diff --git a/src/stim/stabilizers/tableau.test.cc b/src/stim/stabilizers/tableau.test.cc index ce5a81766..b3c804ddf 100644 --- a/src/stim/stabilizers/tableau.test.cc +++ b/src/stim/stabilizers/tableau.test.cc @@ -349,6 +349,7 @@ bool are_tableau_mutations_equivalent( size_t n, const std::function &t, const std::vector &)> &mutation1, const std::function &t, const std::vector &)> &mutation2) { + auto rng = INDEPENDENT_TEST_RNG(); auto test_tableau_dual = Tableau::identity(2 * n); std::vector targets1; std::vector targets2; @@ -363,8 +364,8 @@ bool are_tableau_mutations_equivalent( std::vector> tableaus{ test_tableau_dual, - Tableau::random(n + 10, SHARED_TEST_RNG()), - Tableau::random(n + 30, SHARED_TEST_RNG()), + Tableau::random(n + 10, rng), + Tableau::random(n + 30, rng), }; std::vector> cases{targets1, targets2, targets3}; for (const auto &t : tableaus) { @@ -451,20 +452,21 @@ TEST_EACH_WORD_SIZE_W(tableau, from_pauli_string, { }) TEST_EACH_WORD_SIZE_W(tableau, random, { + auto rng = INDEPENDENT_TEST_RNG(); for (size_t k = 0; k < 20; k++) { - auto t = Tableau::random(1, SHARED_TEST_RNG()); + auto t = Tableau::random(1, rng); ASSERT_TRUE(t.satisfies_invariants()) << t; } for (size_t k = 0; k < 20; k++) { - auto t = Tableau::random(2, SHARED_TEST_RNG()); + auto t = Tableau::random(2, rng); ASSERT_TRUE(t.satisfies_invariants()) << t; } for (size_t k = 0; k < 20; k++) { - auto t = Tableau::random(3, SHARED_TEST_RNG()); + auto t = Tableau::random(3, rng); ASSERT_TRUE(t.satisfies_invariants()) << t; } for (size_t k = 0; k < 20; k++) { - auto t = Tableau::random(30, SHARED_TEST_RNG()); + auto t = Tableau::random(30, rng); ASSERT_TRUE(t.satisfies_invariants()); } }) @@ -627,7 +629,8 @@ TEST_EACH_WORD_SIZE_W(tableau, specialized_operation, { }) TEST_EACH_WORD_SIZE_W(tableau, expand, { - auto t = Tableau::random(4, SHARED_TEST_RNG()); + auto rng = INDEPENDENT_TEST_RNG(); + auto t = Tableau::random(4, rng); auto t2 = t; for (size_t n = 8; n < 500; n += 255) { t2.expand(n, 1.0); @@ -663,7 +666,8 @@ TEST_EACH_WORD_SIZE_W(tableau, expand, { }) TEST_EACH_WORD_SIZE_W(tableau, expand_pad, { - auto t = Tableau::random(4, SHARED_TEST_RNG()); + auto rng = INDEPENDENT_TEST_RNG(); + auto t = Tableau::random(4, rng); auto t2 = t; size_t n = 8; while (n < 10000) { @@ -708,7 +712,8 @@ TEST_EACH_WORD_SIZE_W(tableau, expand_pad, { }) TEST_EACH_WORD_SIZE_W(tableau, expand_pad_equals, { - auto t = Tableau::random(15, SHARED_TEST_RNG()); + auto rng = INDEPENDENT_TEST_RNG(); + auto t = Tableau::random(15, rng); auto t2 = t; t.expand(500, 1.0); t2.expand(500, 2.0); @@ -716,13 +721,14 @@ TEST_EACH_WORD_SIZE_W(tableau, expand_pad_equals, { }) TEST_EACH_WORD_SIZE_W(tableau, transposed_access, { + auto rng = INDEPENDENT_TEST_RNG(); size_t n = 1000; Tableau t(n); auto m = t.xs.xt.data.num_bits_padded(); - t.xs.xt.data.randomize(m, SHARED_TEST_RNG()); - t.xs.zt.data.randomize(m, SHARED_TEST_RNG()); - t.zs.xt.data.randomize(m, SHARED_TEST_RNG()); - t.zs.zt.data.randomize(m, SHARED_TEST_RNG()); + t.xs.xt.data.randomize(m, rng); + t.xs.zt.data.randomize(m, rng); + t.zs.xt.data.randomize(m, rng); + t.zs.zt.data.randomize(m, rng); for (size_t inp_qubit = 0; inp_qubit < 1000; inp_qubit += 99) { for (size_t out_qubit = 0; out_qubit < 1000; out_qubit += 99) { bool bxx = t.xs.xt[inp_qubit][out_qubit]; @@ -747,6 +753,7 @@ TEST_EACH_WORD_SIZE_W(tableau, transposed_access, { }) TEST_EACH_WORD_SIZE_W(tableau, inverse, { + auto rng = INDEPENDENT_TEST_RNG(); Tableau t1(1); ASSERT_EQ(t1, t1.inverse()); t1.prepend_X(0); @@ -756,10 +763,10 @@ TEST_EACH_WORD_SIZE_W(tableau, inverse, { ASSERT_EQ(t2, GATE_DATA.at("X").tableau()); for (size_t k = 5; k < 20; k += 7) { - t1 = Tableau::random(k, SHARED_TEST_RNG()); + t1 = Tableau::random(k, rng); t2 = t1.inverse(); ASSERT_TRUE(t2.satisfies_invariants()); - auto p = PauliString::random(k, SHARED_TEST_RNG()); + auto p = PauliString::random(k, rng); auto p2 = t1(t2(p)); auto x1 = p.xs.str(); auto x2 = p2.xs.str(); @@ -771,7 +778,8 @@ TEST_EACH_WORD_SIZE_W(tableau, inverse, { }) TEST_EACH_WORD_SIZE_W(tableau, prepend_pauli_product, { - auto t = Tableau::random(6, SHARED_TEST_RNG()); + auto rng = INDEPENDENT_TEST_RNG(); + auto t = Tableau::random(6, rng); auto ref = t; t.prepend_pauli_product(PauliString::from_str("_XYZ__")); ref.prepend_X(1); @@ -858,7 +866,8 @@ TEST_EACH_WORD_SIZE_W(tableau, raised_to, { }) TEST_EACH_WORD_SIZE_W(tableau, transposed_xz_input, { - auto t = Tableau::random(4, SHARED_TEST_RNG()); + auto rng = INDEPENDENT_TEST_RNG(); + auto t = Tableau::random(4, rng); PauliString x0(0); PauliString x1(0); { @@ -875,8 +884,9 @@ TEST_EACH_WORD_SIZE_W(tableau, transposed_xz_input, { }) TEST_EACH_WORD_SIZE_W(tableau, direct_sum, { - auto t1 = Tableau::random(260, SHARED_TEST_RNG()); - auto t2 = Tableau::random(270, SHARED_TEST_RNG()); + auto rng = INDEPENDENT_TEST_RNG(); + auto t1 = Tableau::random(260, rng); + auto t2 = Tableau::random(270, rng); auto t3 = t1; t3 += t2; ASSERT_EQ(t3, t1 + t2); @@ -899,7 +909,8 @@ TEST_EACH_WORD_SIZE_W(tableau, direct_sum, { }) TEST_EACH_WORD_SIZE_W(tableau, pauli_access_methods, { - auto t = Tableau::random(3, SHARED_TEST_RNG()); + auto rng = INDEPENDENT_TEST_RNG(); + auto t = Tableau::random(3, rng); auto t_inv = t.inverse(); for (size_t i = 0; i < 3; i++) { auto x = t.xs[i]; @@ -966,7 +977,8 @@ TEST_EACH_WORD_SIZE_W(tableau, pauli_access_methods, { }) TEST_EACH_WORD_SIZE_W(tableau, inverse_pauli_string_acces_methods, { - auto t = Tableau::random(5, SHARED_TEST_RNG()); + auto rng = INDEPENDENT_TEST_RNG(); + auto t = Tableau::random(5, rng); auto t_inv = t.inverse(); auto y0 = t_inv.eval_y_obs(0); auto y1 = t_inv.eval_y_obs(1); diff --git a/src/stim/test_util.test.cc b/src/stim/test_util.test.cc index a60914d18..68e23963d 100644 --- a/src/stim/test_util.test.cc +++ b/src/stim/test_util.test.cc @@ -72,12 +72,13 @@ void expect_string_is_identical_to_saved_file(const std::string &actual, const s } } -std::mt19937_64 &SHARED_TEST_RNG() { +std::mt19937_64 INDEPENDENT_TEST_RNG() { if (!shared_test_rng_initialized) { shared_test_rng = externally_seeded_rng(); shared_test_rng_initialized = true; } - return shared_test_rng; + std::seed_seq seq{shared_test_rng(), shared_test_rng(), shared_test_rng(), shared_test_rng()}; + return std::mt19937_64(seq); } std::string rewind_read_close(FILE *f) { diff --git a/src/stim/test_util.test.h b/src/stim/test_util.test.h index 8bfb3bf63..3c71cd4e7 100644 --- a/src/stim/test_util.test.h +++ b/src/stim/test_util.test.h @@ -21,7 +21,7 @@ #include "gtest/gtest.h" -std::mt19937_64 &SHARED_TEST_RNG(); +std::mt19937_64 INDEPENDENT_TEST_RNG(); std::string rewind_read_close(FILE *f);