@@ -735,10 +735,41 @@ void bindDecoder(nb::module_ &mod) {
735735 });
736736 });
737737
738+ // Shared implementation for constructing a decoder from a Stim DEM string,
739+ // used by both get_decoder overload paths and the (deprecated)
740+ // get_decoder_from_stim_dem entry point.
741+ auto get_decoder_from_dem_text = [](const std::string &name,
742+ const std::string &dem_text,
743+ nb::kwargs options)
744+ -> std::variant<nb::object, std::unique_ptr<decoder>> {
745+ if (PyDecoderRegistry::contains (name)) {
746+ auto dem = dem_from_stim_text (dem_text);
747+
748+ // Keep in sync with make_pcm_decoder in decoder.h.
749+ auto defaults = dem_defaults_for_missing_keys (
750+ [&](const std::string &key) { return options.contains (key); }, dem);
751+ if (defaults.O )
752+ options[" O" ] = toPyArray (*defaults.O );
753+ if (defaults.error_rate_vec )
754+ options[" error_rate_vec" ] = toPyArray (*defaults.error_rate_vec );
755+
756+ nb::object H_obj = toPyArray (dem.detector_error_matrix );
757+ return PyDecoderRegistry::get_decoder (name, H_obj, options);
758+ }
759+
760+ return get_decoder (name, decoder_init{dem_text}, hetMapFromKwargs (options));
761+ };
762+
738763 qecmod.def (
739764 " get_decoder" ,
740- [](const std::string &name, nb::object H, nb::kwargs options)
765+ [get_decoder_from_dem_text](const std::string &name, nb::object H,
766+ nb::kwargs options)
741767 -> std::variant<nb::object, std::unique_ptr<decoder>> {
768+ if (nb::isinstance<nb::str>(H)) {
769+ return get_decoder_from_dem_text (name, nb::cast<std::string>(H),
770+ options);
771+ }
772+
742773 if (PyDecoderRegistry::contains (name)) {
743774 return PyDecoderRegistry::get_decoder (name, H, options);
744775 }
@@ -779,6 +810,9 @@ void bindDecoder(nb::module_ &mod) {
779810 builds ``sparse_binary_matrix`` directly (no dense tensor for ``H``),
780811 allowing native C++ decoders like ``pymatching`` to be constructed
781812 from very large parity-check matrices.
813+ - A Stim detector error model string: native C++ decoders receive the
814+ raw DEM text via ``decoder_init``; Python-registered decoders receive
815+ the DEM-derived PCM plus ``O`` and ``error_rate_vec`` defaults.
782816
783817 For Python-registered decoders (``cudaq.qec.decoder`` decorator), ``H``
784818 is passed through to ``__init__`` unchanged (NumPy array or sparse dict).
@@ -787,31 +821,6 @@ void bindDecoder(nb::module_ &mod) {
787821 allocation.
788822 )pbdoc" );
789823
790- // Shared implementation for constructing a decoder from a Stim DEM string,
791- // used by both the get_decoder(str) overload and the (deprecated)
792- // get_decoder_from_stim_dem entry point.
793- auto get_decoder_from_dem_text = [](const std::string &name,
794- const std::string &dem_text,
795- nb::kwargs options)
796- -> std::variant<nb::object, std::unique_ptr<decoder>> {
797- if (PyDecoderRegistry::contains (name)) {
798- auto dem = dem_from_stim_text (dem_text);
799-
800- // Keep in sync with make_pcm_decoder in decoder.h.
801- auto defaults = dem_defaults_for_missing_keys (
802- [&](const std::string &key) { return options.contains (key); }, dem);
803- if (defaults.O )
804- options[" O" ] = toPyArray (*defaults.O );
805- if (defaults.error_rate_vec )
806- options[" error_rate_vec" ] = toPyArray (*defaults.error_rate_vec );
807-
808- nb::object H_obj = toPyArray (dem.detector_error_matrix );
809- return PyDecoderRegistry::get_decoder (name, H_obj, options);
810- }
811-
812- return get_decoder (name, decoder_init{dem_text}, hetMapFromKwargs (options));
813- };
814-
815824 // Unified entry point: get_decoder also accepts a Stim DEM string. nanobind
816825 // resolves this overload when the second argument is a str rather than a
817826 // numpy array.
0 commit comments