diff --git a/file_lists/test_files b/file_lists/test_files index 9de5d724..b57d0093 100644 --- a/file_lists/test_files +++ b/file_lists/test_files @@ -82,6 +82,7 @@ src/stim/util_bot/twiddle.test.cc src/stim/util_top/circuit_flow_generators.test.cc src/stim/util_top/circuit_inverse_qec.test.cc src/stim/util_top/circuit_inverse_unitary.test.cc +src/stim/util_top/circuit_to_dem.test.cc src/stim/util_top/circuit_to_detecting_regions.test.cc src/stim/util_top/circuit_vs_amplitudes.test.cc src/stim/util_top/circuit_vs_tableau.test.cc diff --git a/src/stim.h b/src/stim.h index adc845a5..e04fcdba 100644 --- a/src/stim.h +++ b/src/stim.h @@ -108,6 +108,7 @@ #include "stim/util_top/circuit_flow_generators.h" #include "stim/util_top/circuit_inverse_qec.h" #include "stim/util_top/circuit_inverse_unitary.h" +#include "stim/util_top/circuit_to_dem.h" #include "stim/util_top/circuit_to_detecting_regions.h" #include "stim/util_top/circuit_vs_amplitudes.h" #include "stim/util_top/circuit_vs_tableau.h" diff --git a/src/stim/cmd/command_diagram.pybind.cc b/src/stim/cmd/command_diagram.pybind.cc index 3ea12cd4..8f35dda0 100644 --- a/src/stim/cmd/command_diagram.pybind.cc +++ b/src/stim/cmd/command_diagram.pybind.cc @@ -268,7 +268,13 @@ DiagramHelper stim_pybind::circuit_diagram( type == "timeslice" || type == "time-slice") { std::stringstream out; DiagramTimelineSvgDrawer::make_diagram_write_to( - circuit, out, tick_min, num_ticks, DiagramTimelineSvgDrawerMode::SVG_MODE_TIME_SLICE, filter_coords, num_rows); + circuit, + out, + tick_min, + num_ticks, + DiagramTimelineSvgDrawerMode::SVG_MODE_TIME_SLICE, + filter_coords, + num_rows); DiagramType d_type = type.find("html") != std::string::npos ? DiagramType::DIAGRAM_TYPE_SVG_HTML : DiagramType::DIAGRAM_TYPE_SVG; return DiagramHelper{d_type, out.str()}; @@ -276,7 +282,8 @@ DiagramHelper stim_pybind::circuit_diagram( type == "detslice-svg" || type == "detslice" || type == "detslice-html" || type == "detslice-svg-html" || type == "detector-slice-svg" || type == "detector-slice") { std::stringstream out; - DetectorSliceSet::from_circuit_ticks(circuit, tick_min, num_ticks, filter_coords).write_svg_diagram_to(out, num_rows); + DetectorSliceSet::from_circuit_ticks(circuit, tick_min, num_ticks, filter_coords) + .write_svg_diagram_to(out, num_rows); DiagramType d_type = type.find("html") != std::string::npos ? DiagramType::DIAGRAM_TYPE_SVG_HTML : DiagramType::DIAGRAM_TYPE_SVG; return DiagramHelper{d_type, out.str()}; diff --git a/src/stim/dem/detector_error_model_target.pybind.cc b/src/stim/dem/detector_error_model_target.pybind.cc index 43b442e6..ce5ca16f 100644 --- a/src/stim/dem/detector_error_model_target.pybind.cc +++ b/src/stim/dem/detector_error_model_target.pybind.cc @@ -28,7 +28,6 @@ pybind11::class_ stim_pybind::pybind_detector_error_model_targ void stim_pybind::pybind_detector_error_model_target_methods( pybind11::module &m, pybind11::class_ &c) { - c.def( pybind11::init([](const pybind11::object &arg) -> ExposedDemTarget { if (pybind11::isinstance(arg)) { diff --git a/src/stim/gates/gates.cc b/src/stim/gates/gates.cc index 09f46adf..2ee52a2b 100644 --- a/src/stim/gates/gates.cc +++ b/src/stim/gates/gates.cc @@ -47,110 +47,110 @@ GateDataMap::GateDataMap() { GateType Gate::hadamard_conjugated(bool ignoring_sign) const { switch (id) { - case GateType::DETECTOR: - case GateType::OBSERVABLE_INCLUDE: - case GateType::TICK: - case GateType::QUBIT_COORDS: - case GateType::SHIFT_COORDS: - case GateType::MPAD: - case GateType::H: - case GateType::DEPOLARIZE1: - case GateType::DEPOLARIZE2: - case GateType::Y_ERROR: - case GateType::I: - case GateType::Y: - case GateType::SQRT_YY: - case GateType::SQRT_YY_DAG: - case GateType::MYY: - case GateType::SWAP: - return id; + case GateType::DETECTOR: + case GateType::OBSERVABLE_INCLUDE: + case GateType::TICK: + case GateType::QUBIT_COORDS: + case GateType::SHIFT_COORDS: + case GateType::MPAD: + case GateType::H: + case GateType::DEPOLARIZE1: + case GateType::DEPOLARIZE2: + case GateType::Y_ERROR: + case GateType::I: + case GateType::Y: + case GateType::SQRT_YY: + case GateType::SQRT_YY_DAG: + case GateType::MYY: + case GateType::SWAP: + return id; - case GateType::MY: - case GateType::MRY: - case GateType::RY: - case GateType::YCY: - return ignoring_sign ? id : GateType::NOT_A_GATE; + case GateType::MY: + case GateType::MRY: + case GateType::RY: + case GateType::YCY: + return ignoring_sign ? id : GateType::NOT_A_GATE; - case GateType::ISWAP: - case GateType::CZSWAP: - case GateType::ISWAP_DAG: - return GateType::NOT_A_GATE; + case GateType::ISWAP: + case GateType::CZSWAP: + case GateType::ISWAP_DAG: + return GateType::NOT_A_GATE; - case GateType::XCY: - return ignoring_sign ? GateType::CY : GateType::NOT_A_GATE; - case GateType::CY: - return ignoring_sign ? GateType::XCY : GateType::NOT_A_GATE; - case GateType::YCX: - return ignoring_sign ? GateType::YCZ : GateType::NOT_A_GATE; - case GateType::YCZ: - return ignoring_sign ? GateType::YCX : GateType::NOT_A_GATE; - case GateType::C_XYZ: - return ignoring_sign ? GateType::C_ZYX : GateType::NOT_A_GATE; - case GateType::C_ZYX: - return ignoring_sign ? GateType::C_XYZ : GateType::NOT_A_GATE; - case GateType::H_XY: - return ignoring_sign ? GateType::H_YZ : GateType::NOT_A_GATE; - case GateType::H_YZ: - return ignoring_sign ? GateType::H_XY : GateType::NOT_A_GATE; + case GateType::XCY: + return ignoring_sign ? GateType::CY : GateType::NOT_A_GATE; + case GateType::CY: + return ignoring_sign ? GateType::XCY : GateType::NOT_A_GATE; + case GateType::YCX: + return ignoring_sign ? GateType::YCZ : GateType::NOT_A_GATE; + case GateType::YCZ: + return ignoring_sign ? GateType::YCX : GateType::NOT_A_GATE; + case GateType::C_XYZ: + return ignoring_sign ? GateType::C_ZYX : GateType::NOT_A_GATE; + case GateType::C_ZYX: + return ignoring_sign ? GateType::C_XYZ : GateType::NOT_A_GATE; + case GateType::H_XY: + return ignoring_sign ? GateType::H_YZ : GateType::NOT_A_GATE; + case GateType::H_YZ: + return ignoring_sign ? GateType::H_XY : GateType::NOT_A_GATE; - case GateType::X: - return GateType::Z; - case GateType::Z: - return GateType::X; - case GateType::SQRT_Y: - return GateType::SQRT_Y_DAG; - case GateType::SQRT_Y_DAG: - return GateType::SQRT_Y; - case GateType::MX: - return GateType::M; - case GateType::M: - return GateType::MX; - case GateType::MRX: - return GateType::MR; - case GateType::MR: - return GateType::MRX; - case GateType::RX: - return GateType::R; - case GateType::R: - return GateType::RX; - case GateType::XCX: - return GateType::CZ; - case GateType::XCZ: - return GateType::CX; - case GateType::CX: - return GateType::XCZ; - case GateType::CZ: - return GateType::XCX; - case GateType::X_ERROR: - return GateType::Z_ERROR; - case GateType::Z_ERROR: - return GateType::X_ERROR; - case GateType::SQRT_X: - return GateType::S; - case GateType::SQRT_X_DAG: - return GateType::S_DAG; - case GateType::S: - return GateType::SQRT_X; - case GateType::S_DAG: - return GateType::SQRT_X_DAG; - case GateType::SQRT_XX: - return GateType::SQRT_ZZ; - case GateType::SQRT_XX_DAG: - return GateType::SQRT_ZZ_DAG; - case GateType::SQRT_ZZ: - return GateType::SQRT_XX; - case GateType::SQRT_ZZ_DAG: - return GateType::SQRT_XX_DAG; - case GateType::CXSWAP: - return GateType::SWAPCX; - case GateType::SWAPCX: - return GateType::CXSWAP; - case GateType::MXX: - return GateType::MZZ; - case GateType::MZZ: - return GateType::MXX; - default: - return GateType::NOT_A_GATE; + case GateType::X: + return GateType::Z; + case GateType::Z: + return GateType::X; + case GateType::SQRT_Y: + return GateType::SQRT_Y_DAG; + case GateType::SQRT_Y_DAG: + return GateType::SQRT_Y; + case GateType::MX: + return GateType::M; + case GateType::M: + return GateType::MX; + case GateType::MRX: + return GateType::MR; + case GateType::MR: + return GateType::MRX; + case GateType::RX: + return GateType::R; + case GateType::R: + return GateType::RX; + case GateType::XCX: + return GateType::CZ; + case GateType::XCZ: + return GateType::CX; + case GateType::CX: + return GateType::XCZ; + case GateType::CZ: + return GateType::XCX; + case GateType::X_ERROR: + return GateType::Z_ERROR; + case GateType::Z_ERROR: + return GateType::X_ERROR; + case GateType::SQRT_X: + return GateType::S; + case GateType::SQRT_X_DAG: + return GateType::S_DAG; + case GateType::S: + return GateType::SQRT_X; + case GateType::S_DAG: + return GateType::SQRT_X_DAG; + case GateType::SQRT_XX: + return GateType::SQRT_ZZ; + case GateType::SQRT_XX_DAG: + return GateType::SQRT_ZZ_DAG; + case GateType::SQRT_ZZ: + return GateType::SQRT_XX; + case GateType::SQRT_ZZ_DAG: + return GateType::SQRT_XX_DAG; + case GateType::CXSWAP: + return GateType::SWAPCX; + case GateType::SWAPCX: + return GateType::CXSWAP; + case GateType::MXX: + return GateType::MZZ; + case GateType::MZZ: + return GateType::MXX; + default: + return GateType::NOT_A_GATE; } } diff --git a/src/stim/gates/gates.test.cc b/src/stim/gates/gates.test.cc index edafb88f..1fe5c6b3 100644 --- a/src/stim/gates/gates.test.cc +++ b/src/stim/gates/gates.test.cc @@ -22,8 +22,8 @@ #include "stim/simulators/tableau_simulator.h" #include "stim/util_bot/str_util.h" #include "stim/util_bot/test_util.test.h" -#include "stim/util_top/has_flow.h" #include "stim/util_top/circuit_flow_generators.h" +#include "stim/util_top/has_flow.h" using namespace stim; @@ -375,8 +375,10 @@ TEST(gate_data, hadamard_conjugated_vs_flow_generators_of_two_qubit_gates) { GateType actual_s = g.hadamard_conjugated(false); GateType actual_u = g.hadamard_conjugated(true); bool found = std::find(other_us.begin(), other_us.end(), actual_u) != other_us.end(); - EXPECT_EQ(actual_s, expected_s) << "signed " << g.name << " -> " << GATE_DATA[actual_s].name << " != " << GATE_DATA[expected_s].name; - EXPECT_TRUE(found) << "unsigned " << g.name << " -> " << GATE_DATA[actual_u].name << " not in " << GATE_DATA[other_us[0]].name; + EXPECT_EQ(actual_s, expected_s) + << "signed " << g.name << " -> " << GATE_DATA[actual_s].name << " != " << GATE_DATA[expected_s].name; + EXPECT_TRUE(found) << "unsigned " << g.name << " -> " << GATE_DATA[actual_u].name << " not in " + << GATE_DATA[other_us[0]].name; } } } diff --git a/src/stim/simulators/error_analyzer.cc b/src/stim/simulators/error_analyzer.cc index 823caeb0..47f393be 100644 --- a/src/stim/simulators/error_analyzer.cc +++ b/src/stim/simulators/error_analyzer.cc @@ -307,7 +307,7 @@ void ErrorAnalyzer::undo_MZ_with_context(const CircuitInstruction &dat, const ch } void ErrorAnalyzer::undo_HERALDED_ERASE(const CircuitInstruction &dat) { - check_can_approximate_disjoint("HERALDED_ERASE", dat.args); + check_can_approximate_disjoint("HERALDED_ERASE", dat.args, false); double p = dat.args[0] * 0.25; double i = std::max(0.0, 1.0 - 4 * p); @@ -327,7 +327,7 @@ void ErrorAnalyzer::undo_HERALDED_ERASE(const CircuitInstruction &dat) { } void ErrorAnalyzer::undo_HERALDED_PAULI_CHANNEL_1(const CircuitInstruction &dat) { - check_can_approximate_disjoint("HERALDED_PAULI_CHANNEL_1", dat.args); + check_can_approximate_disjoint("HERALDED_PAULI_CHANNEL_1", dat.args, true); double hi = dat.args[0]; double hx = dat.args[1]; double hy = dat.args[2]; @@ -341,7 +341,7 @@ void ErrorAnalyzer::undo_HERALDED_PAULI_CHANNEL_1(const CircuitInstruction &dat) SparseXorVec &herald_symptoms = tracker.rec_bits[tracker.num_measurements_in_past]; if (accumulate_errors) { add_error_combinations<3>( - {i, 0, 0, 0, hi, hx, hy, hz}, + {i, 0, 0, 0, hi, hz, hx, hy}, {tracker.xs[q].range(), tracker.zs[q].range(), herald_symptoms.range()}, true); } @@ -750,7 +750,7 @@ void ErrorAnalyzer::correlated_error_block(const std::vector add_composite_error(dats[0].args[0], dats[0].targets); return; } - check_can_approximate_disjoint("ELSE_CORRELATED_ERROR", {}); + check_can_approximate_disjoint("ELSE_CORRELATED_ERROR", {}, false); double remaining_p = 1; for (size_t k = dats.size(); k--;) { @@ -820,7 +820,18 @@ void ErrorAnalyzer::undo_ELSE_CORRELATED_ERROR(const CircuitInstruction &dat) { } } -void ErrorAnalyzer::check_can_approximate_disjoint(const char *op_name, SpanRef probabilities) const { +void ErrorAnalyzer::check_can_approximate_disjoint( + const char *op_name, SpanRef probabilities, bool allow_single_component) const { + if (allow_single_component) { + size_t num_specified = 0; + for (double p : probabilities) { + num_specified += p > 0; + } + if (num_specified <= 1) { + return; + } + } + if (approximate_disjoint_errors_threshold == 0) { std::stringstream msg; msg << "Encountered the operation " << op_name @@ -854,7 +865,7 @@ void ErrorAnalyzer::undo_PAULI_CHANNEL_1(const CircuitInstruction &dat) { double iz; bool is_independent = try_disjoint_to_independent_xyz_errors_approx(dx, dy, dz, &ix, &iy, &iz); if (!is_independent) { - check_can_approximate_disjoint("PAULI_CHANNEL_1", dat.args); + check_can_approximate_disjoint("PAULI_CHANNEL_1", dat.args, true); ix = dx; iy = dy; iz = dz; @@ -875,7 +886,7 @@ void ErrorAnalyzer::undo_PAULI_CHANNEL_1(const CircuitInstruction &dat) { } void ErrorAnalyzer::undo_PAULI_CHANNEL_2(const CircuitInstruction &dat) { - check_can_approximate_disjoint("PAULI_CHANNEL_2", dat.args); + check_can_approximate_disjoint("PAULI_CHANNEL_2", dat.args, true); std::array probabilities; for (size_t k = 0; k < 15; k++) { diff --git a/src/stim/simulators/error_analyzer.h b/src/stim/simulators/error_analyzer.h index f55178f1..38c14420 100644 --- a/src/stim/simulators/error_analyzer.h +++ b/src/stim/simulators/error_analyzer.h @@ -329,7 +329,8 @@ struct ErrorAnalyzer { void undo_MXX_disjoint_controls_segment(const CircuitInstruction &inst); void undo_MYY_disjoint_controls_segment(const CircuitInstruction &inst); void undo_MZZ_disjoint_controls_segment(const CircuitInstruction &inst); - void check_can_approximate_disjoint(const char *op_name, SpanRef probabilities) const; + void check_can_approximate_disjoint( + const char *op_name, SpanRef probabilities, bool allow_single_component) const; void add_composite_error(double probability, SpanRef targets); void correlated_error_block(const std::vector &dats); }; diff --git a/src/stim/simulators/error_analyzer.test.cc b/src/stim/simulators/error_analyzer.test.cc index 1666d96c..3e6b26c9 100644 --- a/src/stim/simulators/error_analyzer.test.cc +++ b/src/stim/simulators/error_analyzer.test.cc @@ -23,6 +23,7 @@ #include "stim/mem/simd_word.test.h" #include "stim/simulators/frame_simulator.h" #include "stim/util_bot/test_util.test.h" +#include "stim/util_top/circuit_to_dem.h" using namespace stim; @@ -3491,17 +3492,13 @@ TEST(ErrorAnalyzer, heralded_erase_conditional_division) { } TEST(ErrorAnalyzer, heralded_erase) { - ErrorAnalyzer::circuit_to_detector_error_model( - Circuit("HERALDED_ERASE(0.25) 0"), false, false, false, 0.3, false, false); + circuit_to_dem(Circuit("HERALDED_ERASE(0.25) 0"), {.approximate_disjoint_errors_threshold = 0.3}); ASSERT_THROW( - { - ErrorAnalyzer::circuit_to_detector_error_model( - Circuit("HERALDED_ERASE(0.25) 0"), false, false, false, 0.2, false, false); - }, + { circuit_to_dem(Circuit("HERALDED_ERASE(0.25) 0"), {.approximate_disjoint_errors_threshold = 0.2}); }, std::invalid_argument); ASSERT_EQ( - ErrorAnalyzer::circuit_to_detector_error_model( + circuit_to_dem( Circuit(R"CIRCUIT( MZZ 0 1 MXX 0 1 @@ -3512,12 +3509,7 @@ TEST(ErrorAnalyzer, heralded_erase) { DETECTOR rec[-2] rec[-5] DETECTOR rec[-3] )CIRCUIT"), - false, - false, - false, - 1.0, - false, - false), + {.approximate_disjoint_errors_threshold = 1}), DetectorErrorModel(R"DEM( error(0.0625) D0 D1 D2 error(0.0625) D0 D2 @@ -3526,7 +3518,7 @@ TEST(ErrorAnalyzer, heralded_erase) { )DEM")); ASSERT_EQ( - ErrorAnalyzer::circuit_to_detector_error_model( + circuit_to_dem( Circuit(R"CIRCUIT( MPP X10*X11*X20*X21 MPP Z11*Z12*Z21*Z22 @@ -3543,12 +3535,7 @@ TEST(ErrorAnalyzer, heralded_erase) { DETECTOR rec[-4] rec[-9] DETECTOR rec[-5] )CIRCUIT"), - true, - false, - false, - 1.0, - false, - false), + {.decompose_errors = true, .approximate_disjoint_errors_threshold = 1}), DetectorErrorModel(R"DEM( error(0.0625) D0 D3 ^ D1 D2 ^ D4 error(0.0625) D0 D3 ^ D4 @@ -3557,7 +3544,7 @@ TEST(ErrorAnalyzer, heralded_erase) { )DEM")); ASSERT_EQ( - ErrorAnalyzer::circuit_to_detector_error_model( + circuit_to_dem( Circuit(R"CIRCUIT( M 0 HERALDED_ERASE(0.25) 9 0 9 9 9 @@ -3565,19 +3552,14 @@ TEST(ErrorAnalyzer, heralded_erase) { DETECTOR rec[-1] rec[-7] DETECTOR rec[-5] )CIRCUIT"), - false, - false, - false, - 1.0, - false, - false), + {.approximate_disjoint_errors_threshold = 1}), DetectorErrorModel(R"DEM( error(0.125) D0 D1 error(0.125) D1 )DEM")); ASSERT_EQ( - ErrorAnalyzer::circuit_to_detector_error_model( + circuit_to_dem( Circuit(R"CIRCUIT( MPAD 0 MPAD 0 @@ -3594,12 +3576,7 @@ TEST(ErrorAnalyzer, heralded_erase) { DETECTOR rec[-4] rec[-9] DETECTOR rec[-5] )CIRCUIT"), - true, - false, - false, - 1.0, - false, - false), + {.decompose_errors = true, .approximate_disjoint_errors_threshold = 1}), DetectorErrorModel(R"DEM( error(0.0625) D0 ^ D1 ^ D4 error(0.0625) D0 ^ D4 @@ -3626,54 +3603,44 @@ TEST(ErrorAnalyzer, heralded_pauli_channel_1) { }, std::invalid_argument); - ASSERT_TRUE(ErrorAnalyzer::circuit_to_detector_error_model( + ASSERT_TRUE(circuit_to_dem( Circuit(R"CIRCUIT( - MZZ 0 1 - MXX 0 1 - HERALDED_PAULI_CHANNEL_1(0.01, 0.02, 0.03, 0.04) 0 - MZZ 0 1 - MXX 0 1 - DETECTOR rec[-1] rec[-4] - DETECTOR rec[-2] rec[-5] - DETECTOR rec[-3] - )CIRCUIT"), - false, - false, - false, - 1.0, - false, - false) + MZZ 0 1 + MXX 0 1 + HERALDED_PAULI_CHANNEL_1(0.01, 0.02, 0.03, 0.04) 0 + MZZ 0 1 + MXX 0 1 + DETECTOR rec[-1] rec[-4] + DETECTOR rec[-2] rec[-5] + DETECTOR rec[-3] + )CIRCUIT"), + {.approximate_disjoint_errors_threshold = 1}) .approx_equals( DetectorErrorModel(R"DEM( - error(0.04) D0 D1 D2 - error(0.02) D0 D2 - error(0.03) D1 D2 - error(0.01) D2 - )DEM"), + error(0.03) D0 D1 D2 + error(0.04) D0 D2 + error(0.02) D1 D2 + error(0.01) D2 + )DEM"), 1e-6)); - ASSERT_TRUE(ErrorAnalyzer::circuit_to_detector_error_model( + ASSERT_TRUE(circuit_to_dem( Circuit(R"CIRCUIT( - MZZ 0 1 - MXX 0 1 - HERALDED_PAULI_CHANNEL_1(0.01, 0.02, 0.03, 0.04) 0 - MZZ 0 1 - MXX 0 1 - DETECTOR - DETECTOR rec[-2] rec[-5] - DETECTOR rec[-3] - )CIRCUIT"), - false, - false, - false, - 1.0, - false, - false) + MZZ 0 1 + MXX 0 1 + HERALDED_PAULI_CHANNEL_1(0.01, 0.02, 0.03, 0.1) 0 + MZZ 0 1 + MXX 0 1 + DETECTOR + DETECTOR rec[-2] rec[-5] + DETECTOR rec[-3] + )CIRCUIT"), + {.approximate_disjoint_errors_threshold = 1}) .approx_equals( DetectorErrorModel(R"DEM( - error(0.07) D1 D2 - error(0.03) D2 - detector D0 - )DEM"), + error(0.05) D1 D2 + error(0.11) D2 + detector D0 + )DEM"), 1e-6)); } diff --git a/src/stim/simulators/matched_error.pybind.cc b/src/stim/simulators/matched_error.pybind.cc index 984c74c4..a85efef3 100644 --- a/src/stim/simulators/matched_error.pybind.cc +++ b/src/stim/simulators/matched_error.pybind.cc @@ -383,7 +383,8 @@ void stim_pybind::pybind_flipped_measurement_methods( }); c.def( pybind11::init( - [](const pybind11::object &measurement_record_index, const pybind11::object &measured_observable) -> FlippedMeasurement { + [](const pybind11::object &measurement_record_index, + const pybind11::object &measured_observable) -> FlippedMeasurement { uint64_t u; if (measurement_record_index.is_none()) { u = UINT64_MAX; diff --git a/src/stim/util_top/circuit_to_dem.h b/src/stim/util_top/circuit_to_dem.h new file mode 100644 index 00000000..1ffcf4a1 --- /dev/null +++ b/src/stim/util_top/circuit_to_dem.h @@ -0,0 +1,30 @@ +#ifndef _STIM_UTIL_TOP_CIRCUIT_TO_DEM_H +#define _STIM_UTIL_TOP_CIRCUIT_TO_DEM_H + +#include "stim/simulators/error_analyzer.h" + +namespace stim { + +struct DemOptions { + bool decompose_errors = false; + bool flatten_loops = true; + bool allow_gauge_detectors = false; + double approximate_disjoint_errors_threshold = 0; + bool ignore_decomposition_failures = false; + bool block_decomposition_from_introducing_remnant_edges = false; +}; + +inline DetectorErrorModel circuit_to_dem(const Circuit &circuit, DemOptions options = {}) { + return ErrorAnalyzer::circuit_to_detector_error_model( + circuit, + options.decompose_errors, + !options.flatten_loops, + options.allow_gauge_detectors, + options.approximate_disjoint_errors_threshold, + options.ignore_decomposition_failures, + options.block_decomposition_from_introducing_remnant_edges); +} + +} // namespace stim + +#endif diff --git a/src/stim/util_top/circuit_to_dem.test.cc b/src/stim/util_top/circuit_to_dem.test.cc new file mode 100644 index 00000000..371717a6 --- /dev/null +++ b/src/stim/util_top/circuit_to_dem.test.cc @@ -0,0 +1,115 @@ +#include "stim/util_top/circuit_to_dem.h" + +#include "gtest/gtest.h" + +using namespace stim; + +TEST(circuit_to_dem, heralded_noise_basis) { + ASSERT_EQ( + circuit_to_dem(Circuit(R"CIRCUIT( + MXX 0 1 + MZZ 0 1 + HERALDED_PAULI_CHANNEL_1(0.25, 0, 0, 0) 0 + MXX 0 1 + MZZ 0 1 + DETECTOR(2) rec[-3] + DETECTOR(3) rec[-2] rec[-5] + DETECTOR(5) rec[-1] rec[-4] + )CIRCUIT")), + DetectorErrorModel(R"DEM( + error(0.25) D0 + detector(2) D0 + detector(3) D1 + detector(5) D2 + )DEM")); + + ASSERT_EQ( + circuit_to_dem(Circuit(R"CIRCUIT( + MXX 0 1 + MZZ 0 1 + HERALDED_PAULI_CHANNEL_1(0, 0.25, 0, 0) 0 + MXX 0 1 + MZZ 0 1 + DETECTOR(2) rec[-3] + DETECTOR(3) rec[-2] rec[-5] + DETECTOR(5) rec[-1] rec[-4] + )CIRCUIT")), + DetectorErrorModel(R"DEM( + error(0.25) D0 D2 + detector(2) D0 + detector(3) D1 + detector(5) D2 + )DEM")); + + ASSERT_EQ( + circuit_to_dem(Circuit(R"CIRCUIT( + MXX 0 1 + MZZ 0 1 + HERALDED_PAULI_CHANNEL_1(0, 0, 0.25, 0) 0 + MXX 0 1 + MZZ 0 1 + DETECTOR(2) rec[-3] + DETECTOR(3) rec[-2] rec[-5] + DETECTOR(5) rec[-1] rec[-4] + )CIRCUIT")), + DetectorErrorModel(R"DEM( + error(0.25) D0 D1 D2 + detector(2) D0 + detector(3) D1 + detector(5) D2 + )DEM")); + + ASSERT_EQ( + circuit_to_dem(Circuit(R"CIRCUIT( + MXX 0 1 + MZZ 0 1 + HERALDED_PAULI_CHANNEL_1(0, 0, 0, 0.25) 0 + MXX 0 1 + MZZ 0 1 + DETECTOR(2) rec[-3] + DETECTOR(3) rec[-2] rec[-5] + DETECTOR(5) rec[-1] rec[-4] + )CIRCUIT")), + DetectorErrorModel(R"DEM( + error(0.25) D0 D1 + detector(2) D0 + detector(3) D1 + detector(5) D2 + )DEM")); + + ASSERT_EQ( + circuit_to_dem( + Circuit(R"CIRCUIT( + MXX 0 1 + MZZ 0 1 + HERALDED_PAULI_CHANNEL_1(0.125, 0, 0.25, 0) 0 + MXX 0 1 + MZZ 0 1 + DETECTOR(2) rec[-3] + DETECTOR(3) rec[-2] rec[-5] + DETECTOR(5) rec[-1] rec[-4] + )CIRCUIT"), + {.approximate_disjoint_errors_threshold = 1}), + DetectorErrorModel(R"DEM( + error(0.125) D0 + error(0.25) D0 D1 D2 + detector(2) D0 + detector(3) D1 + detector(5) D2 + )DEM")); + + ASSERT_THROW( + { + circuit_to_dem(Circuit(R"CIRCUIT( + MXX 0 1 + MZZ 0 1 + HERALDED_PAULI_CHANNEL_1(0.125, 0, 0.25, 0) 0 + MXX 0 1 + MZZ 0 1 + DETECTOR(2) rec[-3] + DETECTOR(3) rec[-2] rec[-5] + DETECTOR(5) rec[-1] rec[-4] + )CIRCUIT")); + }, + std::invalid_argument); +} diff --git a/src/stim/util_top/circuit_vs_amplitudes.cc b/src/stim/util_top/circuit_vs_amplitudes.cc index 6a56219b..75bfeba9 100644 --- a/src/stim/util_top/circuit_vs_amplitudes.cc +++ b/src/stim/util_top/circuit_vs_amplitudes.cc @@ -1,9 +1,9 @@ #include "stim/util_top/circuit_vs_amplitudes.h" -#include "stim/util_top/circuit_inverse_unitary.h" #include "stim/simulators/tableau_simulator.h" #include "stim/simulators/vector_simulator.h" #include "stim/util_bot/twiddle.h" +#include "stim/util_top/circuit_inverse_unitary.h" using namespace stim;