From db60766cf299859735a12c014e34ea22eeb2d64e Mon Sep 17 00:00:00 2001 From: James Mitchell Date: Thu, 19 Mar 2026 16:09:50 +0000 Subject: [PATCH 1/3] todd-coxeter: move lookahead/behind to correct part of file --- src/todd-coxeter.cpp | 65 ++++++++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 29 deletions(-) diff --git a/src/todd-coxeter.cpp b/src/todd-coxeter.cpp index b7ce76e8..4e8589cb 100644 --- a/src/todd-coxeter.cpp +++ b/src/todd-coxeter.cpp @@ -261,6 +261,8 @@ semigroup. :rtype: ToddCoxeter )pbdoc"); + //////////////////////////////////////////////////////////////////////// + thing.def( "current_index_of", [](ToddCoxeter_ const& self, Word const& w) { @@ -377,36 +379,9 @@ node corresponding to index *i* back to the root of that tree. )pbdoc"); //////////////////////////////////////////////////////////////////////// - // Helpers from cong-common.hpp . . . + // Lookahead/behind //////////////////////////////////////////////////////////////////////// - auto raises = R"pbdoc( -:raises LibsemigroupsError: - if the number of classes in *tc* is infinite. In this case, the - enumeration of *tc* will not terminate successfully.)pbdoc"sv; - - def_partition>( - m, - "ToddCoxeter", - "todd_coxeter", - doc{.only_document_once = true, .raises = raises, .var = "tc"}); - - def_non_trivial_classes>( - m, - "ToddCoxeter", - "todd_coxeter", - doc{.only_document_once = true, .raises = raises, .var = "tc"}); - - def_normal_forms>(m, - "ToddCoxeter", - "todd_coxeter", - doc{.detail = R"pbdoc( -The order of the classes, and the normal forms, that are returned are -controlled by :any:`ToddCoxeter.standardize`. This function triggers a full -enumeration of ``tc``.)pbdoc", - .only_document_once = true, - .raises = raises, - .var = "tc"}); thing.def( "perform_lookahead", [](ToddCoxeter_& self) { return self.perform_lookahead(); }, @@ -739,6 +714,38 @@ whichever happens first. does nothing but still might take some time to run). )pbdoc"); + //////////////////////////////////////////////////////////////////////// + // Helpers from cong-common.hpp . . . + //////////////////////////////////////////////////////////////////////// + + auto raises = R"pbdoc( +:raises LibsemigroupsError: + if the number of classes in *tc* is infinite. In this case, the + enumeration of *tc* will not terminate successfully.)pbdoc"sv; + + def_partition>( + m, + "ToddCoxeter", + "todd_coxeter", + doc{.only_document_once = true, .raises = raises, .var = "tc"}); + + def_non_trivial_classes>( + m, + "ToddCoxeter", + "todd_coxeter", + doc{.only_document_once = true, .raises = raises, .var = "tc"}); + + def_normal_forms>(m, + "ToddCoxeter", + "todd_coxeter", + doc{.detail = R"pbdoc( +The order of the classes, and the normal forms, that are returned are +controlled by :any:`ToddCoxeter.standardize`. This function triggers a full +enumeration of ``tc``.)pbdoc", + .only_document_once = true, + .raises = raises, + .var = "tc"}); + //////////////////////////////////////////////////////////////////////// // Helper functions - specific to ToddCoxeter //////////////////////////////////////////////////////////////////////// @@ -964,7 +971,7 @@ Pro). :param tc: the :any:`ToddCoxeter` instance. :type tc: ToddCoxeter)pbdoc"); } // bind_todd_coxeter - } // namespace + } // namespace void init_todd_coxeter(py::module& m) { bind_todd_coxeter(m, "ToddCoxeterWord"); From 24af1a943921d5be642a57a3861ad3bf6c05ad7d Mon Sep 17 00:00:00 2001 From: James Mitchell Date: Thu, 19 Mar 2026 16:24:50 +0000 Subject: [PATCH 2/3] todd-coxeter: fix rtype of lookahead/behind methods --- src/todd-coxeter.cpp | 29 ++++++++++++++++++++--------- tests/test_todd_coxeter.py | 36 +++++++++++++++++++++++------------- 2 files changed, 43 insertions(+), 22 deletions(-) diff --git a/src/todd-coxeter.cpp b/src/todd-coxeter.cpp index 4e8589cb..6856fd57 100644 --- a/src/todd-coxeter.cpp +++ b/src/todd-coxeter.cpp @@ -384,7 +384,9 @@ node corresponding to index *i* back to the root of that tree. thing.def( "perform_lookahead", - [](ToddCoxeter_& self) { return self.perform_lookahead(); }, + [](ToddCoxeter_& self) -> detail::ToddCoxeterImpl& { + return self.perform_lookahead(); + }, R"pbdoc( :sig=(self: ToddCoxeter) -> ToddCoxeter: @@ -404,7 +406,8 @@ style and extent of this lookahead are controlled by the settings thing.def( "perform_lookahead_for", - [](ToddCoxeter_& self, std::chrono::nanoseconds t) { + [](ToddCoxeter_& self, + std::chrono::nanoseconds t) -> detail::ToddCoxeterImpl& { return self.perform_lookahead_for(t); }, py::arg("t"), @@ -426,7 +429,8 @@ happens first. thing.def( "perform_lookahead_until", - [](ToddCoxeter_& self, std::function const& pred) { + [](ToddCoxeter_& self, + std::function const& pred) -> detail::ToddCoxeterImpl& { return self.perform_lookahead_until(pred); }, py::arg("pred"), @@ -447,7 +451,9 @@ This function runs a lookahead until the nullary predicate *pred* returns thing.def( "perform_lookbehind", - [](ToddCoxeter_& self) { return self.perform_lookbehind(); }, + [](ToddCoxeter_& self) -> detail::ToddCoxeterImpl& { + return self.perform_lookbehind(); + }, R"pbdoc( :sig=(self: ToddCoxeter) -> ToddCoxeter: @@ -510,7 +516,8 @@ Pro). thing.def( "perform_lookbehind_no_checks", [](ToddCoxeter_& self, - std::function const& collapser) { + std::function const& collapser) + -> detail::ToddCoxeterImpl& { auto wrap = [&collapser](auto d_it, auto first, auto last) { Word copy(first, last); // Shame to do so much copying here but couldn't figure out how to @@ -578,7 +585,8 @@ function :any:`ToddCoxeter.reduce_no_run`. thing.def( "perform_lookbehind_for", - [](ToddCoxeter_& self, std::chrono::nanoseconds t) { + [](ToddCoxeter_& self, + std::chrono::nanoseconds t) -> detail::ToddCoxeterImpl& { return self.perform_lookbehind_for(t); }, py::arg("t"), @@ -606,7 +614,8 @@ happens first. "perform_lookbehind_for_no_checks", [](ToddCoxeter_& self, std::chrono::nanoseconds t, - std::function const& collapser) { + std::function const& collapser) + -> detail::ToddCoxeterImpl& { auto wrap = [&collapser](auto d_it, auto first, auto last) { Word copy(first, last); // Shame to do so much copying here but couldn't figure out how to @@ -649,7 +658,8 @@ happens first. See :any:`perform_lookbehind_no_checks` for more details. thing.def( "perform_lookbehind_until", - [](ToddCoxeter_& self, std::function const& pred) { + [](ToddCoxeter_& self, + std::function const& pred) -> detail::ToddCoxeterImpl& { return self.perform_lookbehind_until(pred); }, py::arg("pred"), @@ -676,7 +686,8 @@ This function runs a lookbehind until the nullary predicate *pred* returns "perform_lookbehind_until_no_checks", [](ToddCoxeter_& self, std::function const& pred, - std::function const& collapser) { + std::function const& collapser) + -> detail::ToddCoxeterImpl& { auto wrap = [&collapser](auto d_it, auto first, auto last) { Word copy(first, last); // Shame to do so much copying here but couldn't figure out how to diff --git a/tests/test_todd_coxeter.py b/tests/test_todd_coxeter.py index f504c7dc..1a9a5296 100644 --- a/tests/test_todd_coxeter.py +++ b/tests/test_todd_coxeter.py @@ -420,22 +420,24 @@ def test_todd_coxeter_return_policy(): def test_todd_coxeter_perform_lookahead(): p = examples.full_transformation_monoid_Aiz58(10) tc = ToddCoxeter(congruence_kind.twosided, p) - tc.perform_lookahead() + assert tc.perform_lookahead() is tc tc.run_for(timedelta(seconds=0.01)) num_nodes = tc.number_of_nodes_active() - tc.perform_lookahead() + # Check the return type is correct + assert tc.perform_lookahead() is tc assert tc.number_of_nodes_active() < num_nodes def test_todd_coxeter_perform_lookahead_for(): p = examples.full_transformation_monoid_Aiz58(10) tc = ToddCoxeter(congruence_kind.twosided, p) - tc.perform_lookahead() + assert tc.perform_lookahead() is tc tc.run_for(timedelta(seconds=0.01)) num_nodes = tc.number_of_nodes_active() start_time = time.time() - tc.perform_lookahead_for(timedelta(seconds=0.1)) - assert time.time() - start_time <= 0.2 + # Check the return type is correct + assert tc.perform_lookahead_for(timedelta(seconds=0.1)) is tc + assert time.time() - start_time <= 1.0 assert tc.number_of_nodes_active() < num_nodes @@ -445,7 +447,8 @@ def test_todd_coxeter_perform_lookahead_until(): tc.perform_lookahead() tc.run_for(timedelta(seconds=0.01)) num_nodes = tc.number_of_nodes_active() - tc.perform_lookahead_until(lambda: tc.number_of_nodes_active() < num_nodes) + # Check the return type is correct + assert tc.perform_lookahead_until(lambda: tc.number_of_nodes_active() < num_nodes) is tc assert tc.number_of_nodes_active() < num_nodes @@ -456,8 +459,9 @@ def test_todd_coxeter_perform_lookbehind_for(): tc.run_for(timedelta(seconds=0.01)) num_nodes = tc.number_of_nodes_active() start_time = time.time() - tc.perform_lookbehind_for(timedelta(seconds=0.1)) - assert time.time() - start_time <= 0.2 + # Run and check the return type is correct + assert tc.perform_lookbehind_for(timedelta(seconds=0.1)) is tc + assert time.time() - start_time <= 1.0 assert tc.number_of_nodes_active() < num_nodes @@ -467,7 +471,8 @@ def test_todd_coxeter_perform_lookbehind_until(): tc.perform_lookbehind() tc.run_for(timedelta(seconds=0.01)) num_nodes = tc.number_of_nodes_active() - tc.perform_lookbehind_until(lambda: tc.number_of_nodes_active() < num_nodes) + # Run and check the return type is correct + assert tc.perform_lookbehind_until(lambda: tc.number_of_nodes_active() < num_nodes) is tc assert tc.number_of_nodes_active() < num_nodes @@ -478,8 +483,9 @@ def test_todd_coxeter_perform_lookbehind_for_no_checks(): tc.run_for(timedelta(seconds=0.01)) num_nodes = tc.number_of_nodes_active() start_time = time.time() - tc.perform_lookbehind_for_no_checks(timedelta(seconds=0.1), lambda w: []) - assert time.time() - start_time <= 0.2 + # Run and check the return type is correct + assert tc.perform_lookbehind_for_no_checks(timedelta(seconds=0.1), lambda w: []) is tc + assert time.time() - start_time <= 1.0 assert tc.number_of_nodes_active() < num_nodes @@ -489,7 +495,11 @@ def test_todd_coxeter_perform_lookbehind_until_no_checks(): tc.perform_lookbehind() tc.run_for(timedelta(seconds=0.01)) num_nodes = tc.number_of_nodes_active() - tc.perform_lookbehind_until_no_checks( - lambda: tc.number_of_nodes_active() < num_nodes, lambda w: [] + # Run and check the return type is correct + assert ( + tc.perform_lookbehind_until_no_checks( + lambda: tc.number_of_nodes_active() < num_nodes, lambda w: [] + ) + is tc ) assert tc.number_of_nodes_active() < num_nodes From 378433b19dbabd60d9f6796c06a91549c59b1877 Mon Sep 17 00:00:00 2001 From: James Mitchell Date: Thu, 19 Mar 2026 17:29:32 +0000 Subject: [PATCH 3/3] Format --- src/todd-coxeter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/todd-coxeter.cpp b/src/todd-coxeter.cpp index 6856fd57..d851c3e8 100644 --- a/src/todd-coxeter.cpp +++ b/src/todd-coxeter.cpp @@ -982,7 +982,7 @@ Pro). :param tc: the :any:`ToddCoxeter` instance. :type tc: ToddCoxeter)pbdoc"); } // bind_todd_coxeter - } // namespace + } // namespace void init_todd_coxeter(py::module& m) { bind_todd_coxeter(m, "ToddCoxeterWord");