diff --git a/src/stim/cmd/command_diagram.pybind.cc b/src/stim/cmd/command_diagram.pybind.cc index 8f35dda0..9ef8b45a 100644 --- a/src/stim/cmd/command_diagram.pybind.cc +++ b/src/stim/cmd/command_diagram.pybind.cc @@ -125,6 +125,31 @@ void stim_pybind::pybind_diagram_methods(pybind11::module &m, pybind11::class_ void { pybind11::getattr(p, "text")(self.content); }); + c.def("__repr__", [](const DiagramHelper &self) -> std::string { + std::stringstream ss; + ss << ""; + return ss.str(); + }); c.def("__str__", [](const DiagramHelper &self) -> pybind11::object { if (self.type == DiagramType::DIAGRAM_TYPE_SVG_HTML) { return diagram_as_html(self); diff --git a/src/stim/simulators/error_analyzer.cc b/src/stim/simulators/error_analyzer.cc index 47f393be..1fe3a9be 100644 --- a/src/stim/simulators/error_analyzer.cc +++ b/src/stim/simulators/error_analyzer.cc @@ -414,12 +414,32 @@ void ErrorAnalyzer::check_for_gauge( has_detectors &= !allow_gauge_detectors; if (has_observables) { error_msg << "The circuit contains non-deterministic observables.\n"; - error_msg << "(Error analysis requires deterministic observables.)\n"; } if (has_detectors) { error_msg << "The circuit contains non-deterministic detectors.\n"; - error_msg << "(To allow non-deterministic detectors, use the `allow_gauge_detectors` option.)\n"; } + size_t range_start = num_ticks_in_past - std::min(num_ticks_in_past, size_t{5}); + size_t range_end = num_ticks_in_past + 5; + error_msg << "\nTo make an SVG picture of the problem, you can use the python API like this:\n "; + error_msg << "your_circuit.diagram('detslice-with-ops-svg'"; + error_msg << ", tick=range(" << range_start << ", " << range_end << ")"; + error_msg << ", filter_coords=["; + for (auto d : potential_gauge) { + error_msg << "'" << d << "', "; + } + error_msg << "])"; + error_msg << "\nor the command line API like this:\n "; + error_msg << "stim diagram --in your_circuit_file.stim"; + error_msg << " --type detslice-with-ops-svg"; + error_msg << " --tick " << range_start << ":" << range_end; + error_msg << " --filter_coords "; + for (size_t k = 0; k < potential_gauge.size(); k++) { + if (k) { + error_msg << ':'; + } + error_msg << potential_gauge.sorted_items[k]; + } + error_msg << " > output_image.svg\n"; std::map> qubit_coords_map; if (current_circuit_being_analyzed != nullptr) { diff --git a/src/stim/simulators/error_analyzer.test.cc b/src/stim/simulators/error_analyzer.test.cc index 3e6b26c9..a4feaeb2 100644 --- a/src/stim/simulators/error_analyzer.test.cc +++ b/src/stim/simulators/error_analyzer.test.cc @@ -2348,6 +2348,17 @@ TEST(ErrorAnalyzer, noisy_measurement_mrz) { )MODEL")); } +template +std::string expect_catch_message(std::function func) { + try { + func(); + EXPECT_FALSE(false) << "Function didn't throw an exception."; + return ""; + } catch (const TEx &ex) { + return ex.what(); + } +} + template std::string check_catch(std::string expected_substring, std::function func) { try { @@ -2364,13 +2375,7 @@ std::string check_catch(std::string expected_substring, std::function( - "Can't analyze over-mixing DEPOLARIZE1 errors (probability > 3/4).\n" - "\n" - "Circuit stack trace:\n" - " at instruction #2 [which is DEPOLARIZE1(1) 0]", - [&] { + expect_catch_message([&](){ ErrorAnalyzer::circuit_to_detector_error_model( Circuit(R"CIRCUIT( X 0 @@ -2382,7 +2387,11 @@ TEST(ErrorAnalyzer, context_clues_for_errors) { 0.0, false, true); - })); + }), + "Can't analyze over-mixing DEPOLARIZE1 errors (probability > 3/4).\n" + "\n" + "Circuit stack trace:\n" + " at instruction #2 [which is DEPOLARIZE1(1) 0]"); ASSERT_EQ( "", @@ -2846,10 +2855,31 @@ TEST(ErrorAnalyzer, mpp_ordering) { TEST(ErrorAnalyzer, anticommuting_observable_error_message_help) { for (size_t folding = 0; folding < 2; folding++) { ASSERT_EQ( - "", - check_catch( - R"ERROR(The circuit contains non-deterministic observables. -(Error analysis requires deterministic observables.) + expect_catch_message([&](){ + circuit_to_dem( + Circuit(R"CIRCUIT( + QUBIT_COORDS(1, 2, 3) 0 + RX 2 + REPEAT 10 { + REPEAT 20 { + C_XYZ 0 + R 1 + M 1 + DETECTOR rec[-1] + TICK + } + } + M 0 2 + OBSERVABLE_INCLUDE(0) rec[-1] rec[-2] + )CIRCUIT"), + {.flatten_loops = folding != 1}); + }), + R"ERROR(The circuit contains non-deterministic observables. + +To make an SVG picture of the problem, you can use the python API like this: + your_circuit.diagram('detslice-with-ops-svg', tick=range(0, 5), filter_coords=['L0', ]) +or the command line API like this: + stim diagram --in your_circuit_file.stim --type detslice-with-ops-svg --tick 0:5 --filter_coords L0 > output_image.svg This was discovered while analyzing an X-basis reset (RX) on: qubit 2 @@ -2863,39 +2893,42 @@ The backward-propagating error sensitivity for L0 was: Circuit stack trace: during TICK layer #1 of 201 - at instruction #2 [which is RX 2])ERROR", - [&] { - ErrorAnalyzer::circuit_to_detector_error_model( - Circuit(R"CIRCUIT( - QUBIT_COORDS(1, 2, 3) 0 - RX 2 - REPEAT 10 { - REPEAT 20 { - C_XYZ 0 - R 1 - M 1 - DETECTOR rec[-1] - TICK - } - } - M 0 2 - OBSERVABLE_INCLUDE(0) rec[-1] rec[-2] - )CIRCUIT"), - false, - folding == 1, - false, - 0.0, - false, - true); - })); + at instruction #2 [which is RX 2])ERROR"); ASSERT_EQ( - "", - check_catch( - R"ERROR(The circuit contains non-deterministic observables. -(Error analysis requires deterministic observables.) + expect_catch_message([&](){ + circuit_to_dem(Circuit(R"CIRCUIT( + TICK + SHIFT_COORDS(1000, 2000) + M 0 1 + REPEAT 100 { + RX 0 + DETECTOR rec[-1] + TICK + } + REPEAT 200 { + TICK + } + REPEAT 100 { + M 0 1 + SHIFT_COORDS(0, 100) + DETECTOR(1, 2, 3) rec[-1] rec[-3] + DETECTOR(4, 5, 6) rec[-2] rec[-4] + OBSERVABLE_INCLUDE(0) rec[-1] rec[-2] rec[-3] rec[-4] + TICK + } + REPEAT 1000 { + TICK + } + )CIRCUIT"), {.flatten_loops = folding != 1}); + }), + R"ERROR(The circuit contains non-deterministic observables. The circuit contains non-deterministic detectors. -(To allow non-deterministic detectors, use the `allow_gauge_detectors` option.) + +To make an SVG picture of the problem, you can use the python API like this: + your_circuit.diagram('detslice-with-ops-svg', tick=range(95, 105), filter_coords=['D101', 'L0', ]) +or the command line API like this: + stim diagram --in your_circuit_file.stim --type detslice-with-ops-svg --tick 95:105 --filter_coords D101:L0 > output_image.svg This was discovered while analyzing an X-basis reset (RX) on: qubit 0 @@ -2914,40 +2947,7 @@ The backward-propagating error sensitivity for L0 was: Circuit stack trace: during TICK layer #101 of 1402 at instruction #4 [which is a REPEAT 100 block] - at block's instruction #1 [which is RX 0])ERROR", - [&] { - ErrorAnalyzer::circuit_to_detector_error_model( - Circuit(R"CIRCUIT( - TICK - SHIFT_COORDS(1000, 2000) - M 0 1 - REPEAT 100 { - RX 0 - DETECTOR rec[-1] - TICK - } - REPEAT 200 { - TICK - } - REPEAT 100 { - M 0 1 - SHIFT_COORDS(0, 100) - DETECTOR(1, 2, 3) rec[-1] rec[-3] - DETECTOR(4, 5, 6) rec[-2] rec[-4] - OBSERVABLE_INCLUDE(0) rec[-1] rec[-2] rec[-3] rec[-4] - TICK - } - REPEAT 1000 { - TICK - } - )CIRCUIT"), - false, - folding == 1, - false, - 0.0, - false, - true); - })); + at block's instruction #1 [which is RX 0])ERROR"); } } diff --git a/src/stim/util_top/export_crumble_url.cc b/src/stim/util_top/export_crumble_url.cc index fcb9765c..dab4bd92 100644 --- a/src/stim/util_top/export_crumble_url.cc +++ b/src/stim/util_top/export_crumble_url.cc @@ -7,6 +7,8 @@ std::string stim::export_crumble_url(const Circuit &circuit) { std::string_view s_view = s; std::vector> replace_rules{ {"QUBIT_COORDS", "Q"}, + {"DETECTOR", "DT"}, + {"OBSERVABLE_INCLUDE", "OI"}, {", ", ","}, {") ", ")"}, {" ", ""},