Skip to content

Commit 3f79375

Browse files
todd-coxeter: add new features from libsemigroups
Namely: - presentation_no_checks (can be used to change the presentation after started) - number_of_nodes_active - number_of_edges_active - complete - number_of_large_collapses
1 parent 3dfd24b commit 3f79375

5 files changed

Lines changed: 179 additions & 3 deletions

File tree

dev-environment.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,4 @@ dependencies:
2424
- sphinxcontrib-bibtex
2525
- pip:
2626
- accepts
27+
- pkgconfig

docs/source/main-algorithms/todd-coxeter/class/accessors.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,20 @@ This page contains the documentation of the various member functions of the
1616
Those functions with the prefix ``current_`` do not perform any further
1717
enumeration.
1818

19+
.. automethod:: ToddCoxeter.complete
20+
1921
.. automethod:: ToddCoxeter.current_spanning_tree
2022

2123
.. automethod:: ToddCoxeter.current_word_graph
2224

2325
.. automethod:: ToddCoxeter.is_standardized
2426

27+
.. automethod:: ToddCoxeter.number_of_edges_active
28+
29+
.. automethod:: ToddCoxeter.number_of_large_collapses
30+
31+
.. automethod:: ToddCoxeter.number_of_nodes_active
32+
2533
.. automethod:: ToddCoxeter.spanning_tree
2634

2735
.. automethod:: ToddCoxeter.standardization_order

src/aho-corasick.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818

1919
// C++ stl headers....
2020
#include <string> // for string
21-
#include <vector> // for vector
2221

2322
// libsemigroups....
2423
#include <libsemigroups/aho-corasick.hpp> // for AhoCorasick, AhoCorasick::...
@@ -289,7 +288,7 @@ node; either active or inactive.
289288
)pbdoc");
290289

291290
thing.def(
292-
"is_terminal",
291+
"is_terminal", // TODO rename "terminal"
293292
[](AhoCorasick const& ac, size_t i) {
294293
ac.throw_if_node_index_out_of_range(i);
295294
ac.throw_if_node_index_not_active(i);

src/todd-coxeter-impl.cpp

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1422,6 +1422,7 @@ settings are ignored.
14221422
too few nodes are killed.
14231423
:type stop_early: bool
14241424
)pbdoc");
1425+
14251426
thing.def("shrink_to_fit",
14261427
&ToddCoxeterImpl_::shrink_to_fit,
14271428
R"pbdoc(
@@ -1432,6 +1433,7 @@ triggers a full enumeration, and standardization, and removes from
14321433
:any:`word_graph` any dead nodes. If :any:`Runner.finished` returns ``False``,
14331434
then this function does nothing.
14341435
)pbdoc");
1436+
14351437
thing.def("standardize",
14361438
&ToddCoxeterImpl_::standardize,
14371439
py::arg("val"),
@@ -1457,6 +1459,160 @@ calling this function.
14571459
:rtype: bool
14581460
14591461
.. seealso:: :any:`word_graph.standardize` and :any:`current_spanning_tree`.
1462+
)pbdoc");
1463+
1464+
thing.def(
1465+
"complete",
1466+
[](ToddCoxeterImpl_ const& self) { return self.complete(); },
1467+
R"pbdoc(
1468+
:sig=(self: ToddCoxeter) -> float:
1469+
1470+
Returns the proportion of edges defined in the active part of the current word
1471+
graph.
1472+
1473+
This function returns the proportion (as a float) of the edges defined. This
1474+
value is :any:`number_of_edges_active` divided by :any:`number_of_nodes_active`
1475+
multiplied by :any:`WordGraph.out_degree` applied to :any:`current_word_graph`.
1476+
1477+
:returns:
1478+
The proportion of edges defined in the active part of
1479+
:any:`current_word_graph`.
1480+
:rtype: float
1481+
1482+
.. doctest:: Python
1483+
1484+
>>> from libsemigroups_pybind11 import (Presentation, presentation, ToddCoxeter,
1485+
... congruence_kind)
1486+
>>> from datetime import timedelta
1487+
>>> p = Presentation("bcd")
1488+
>>> p.contains_empty_word(True)
1489+
<monoid presentation with 3 letters, 0 rules, and length 0>
1490+
>>> presentation.add_rule(p, "bb", "")
1491+
>>> presentation.add_rule(p, "cd", "")
1492+
>>> presentation.add_rule(p, "ccc", "")
1493+
>>> presentation.add_rule(p, "bcbcbcbcbcbcbc", "")
1494+
>>> presentation.add_rule(p, "bcbdbcbdbcbdbc", "")
1495+
>>> tc = ToddCoxeter(congruence_kind.twosided, p)
1496+
>>> tc.run()
1497+
>>> tc.complete()
1498+
1.0
1499+
)pbdoc");
1500+
1501+
thing.def("number_of_edges_active",
1502+
&ToddCoxeterImpl_::number_of_edges_active,
1503+
R"pbdoc(
1504+
:sig=(self: ToddCoxeter) -> int:
1505+
1506+
Return the number of edges in the active part of the current word graph.
1507+
1508+
This function returns the number of edges in the active part of the
1509+
:any:`current_word_graph`. Recall that :any:`current_word_graph` can grow and
1510+
shrink drastically during a congruence enumeration. As such to avoid
1511+
unnecessary memory allocations, where possible, the nodes in the
1512+
:any:`current_word_graph` are "recycled" leading to the situation where some of
1513+
the nodes in :any:`current_word_graph` are "active" and others are "inactive".
1514+
In other words, the "active" nodes correspond to the part of the word graph
1515+
that actually represents the classes of the congruence we are trying to
1516+
enumerate; and the "inactive" nodes are only there to be "recycled" into
1517+
"active" nodes if they are required later on.
1518+
1519+
:returns: The number of edges that are incident to active nodes.
1520+
:rtype: int
1521+
1522+
.. doctest:: Python
1523+
1524+
>>> from libsemigroups_pybind11 import (Presentation, presentation, ToddCoxeter,
1525+
... congruence_kind)
1526+
>>> from datetime import timedelta
1527+
>>> p = Presentation("bcd")
1528+
>>> p.contains_empty_word(True)
1529+
<monoid presentation with 3 letters, 0 rules, and length 0>
1530+
>>> presentation.add_rule(p, "bb", "")
1531+
>>> presentation.add_rule(p, "cd", "")
1532+
>>> presentation.add_rule(p, "ccc", "")
1533+
>>> presentation.add_rule(p, "bcbcbc", "")
1534+
>>> presentation.add_rule(p, "bcbdbcbd", "")
1535+
>>> tc = ToddCoxeter(congruence_kind.twosided, p)
1536+
>>> tc.number_of_classes()
1537+
12
1538+
>>> tc.number_of_edges_active()
1539+
36
1540+
)pbdoc");
1541+
1542+
thing.def("number_of_nodes_active",
1543+
&ToddCoxeterImpl_::number_of_nodes_active,
1544+
R"pbdoc(
1545+
:sig=(self: ToddCoxeter) -> int:
1546+
1547+
Return the number of nodes in the active part of the current word graph.
1548+
1549+
This function returns the number of nodes in the active part of the
1550+
:any:`current_word_graph`. Recall that :any:`current_word_graph` can grow and
1551+
shrink drastically during a congruence enumeration. As such to avoid
1552+
unnecessary memory allocations, where possible, the nodes in the
1553+
:any:`current_word_graph` are "recycled" leading to the situation where some of
1554+
the nodes in :any:`current_word_graph` are "active" and others are "inactive".
1555+
In other words, the "active" nodes correspond to the part of the word graph
1556+
that actually represents the classes of the congruence we are trying to
1557+
enumerate; and the "inactive" nodes are only there to be "recycled" into
1558+
"active" nodes if they are required later on.
1559+
1560+
:returns: The number of nodes that are active.
1561+
:rtype: int
1562+
1563+
.. doctest:: Python
1564+
1565+
>>> from libsemigroups_pybind11 import (Presentation, presentation, ToddCoxeter,
1566+
... congruence_kind)
1567+
>>> from datetime import timedelta
1568+
>>> p = Presentation("bcd")
1569+
>>> p.contains_empty_word(True)
1570+
<monoid presentation with 3 letters, 0 rules, and length 0>
1571+
>>> presentation.add_rule(p, "bb", "")
1572+
>>> presentation.add_rule(p, "cd", "")
1573+
>>> presentation.add_rule(p, "ccc", "")
1574+
>>> presentation.add_rule(p, "bcbcbc", "")
1575+
>>> presentation.add_rule(p, "bcbdbcbd", "")
1576+
>>> tc = ToddCoxeter(congruence_kind.twosided, p)
1577+
>>> tc.number_of_classes()
1578+
12
1579+
>>> tc.number_of_nodes_active()
1580+
12
1581+
)pbdoc");
1582+
1583+
thing.def("number_of_large_collapses",
1584+
&ToddCoxeterImpl_::number_of_large_collapses,
1585+
R"pbdoc(
1586+
:sig=(self: ToddCoxeter) -> int:
1587+
1588+
Return the number of large collapses that have occurred.
1589+
1590+
This function returns the number of "large" collapses that have occurred in the
1591+
graph during any run of a :any:`ToddCoxeter` instance. What qualifies as a "large"
1592+
collapse can be specified using :any:`large_collapse`.
1593+
1594+
:returns: The number of large collapses.
1595+
:rtype: int
1596+
1597+
.. doctest:: Python
1598+
1599+
>>> from libsemigroups_pybind11 import (Presentation, presentation, ToddCoxeter,
1600+
... congruence_kind)
1601+
>>> from datetime import timedelta
1602+
>>> p = Presentation("bcd")
1603+
>>> p.contains_empty_word(True)
1604+
<monoid presentation with 3 letters, 0 rules, and length 0>
1605+
>>> presentation.add_rule(p, "bb", "")
1606+
>>> presentation.add_rule(p, "cd", "")
1607+
>>> presentation.add_rule(p, "ccc", "")
1608+
>>> presentation.add_rule(p, "bcbcbcbcbcbcbc", "")
1609+
>>> presentation.add_rule(p, "bcbdbcbdbcbdbcbdbcbdbcbdbcbdbcbd", "")
1610+
>>> tc = ToddCoxeter(congruence_kind.twosided, p)
1611+
>>> tc.run_for(timedelta(milliseconds=10))
1612+
>>> tc.finished()
1613+
False
1614+
>>> tc.number_of_large_collapses()
1615+
0
14601616
)pbdoc");
14611617
} // init_todd_coxeter
14621618

src/todd-coxeter.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,18 @@ words. This function triggers no congruence enumeration.)pbdoc"sv});
136136

137137
////////////////////////////////////////////////////////////////////////
138138

139+
if constexpr (std::is_same_v<Word, word_type>) {
140+
thing.def("presentation_no_checks",
141+
[](ToddCoxeter_& self, Presentation<Word> const& p) {
142+
self.presentation_no_checks(p);
143+
});
144+
} else {
145+
thing.def("presentation_no_checks",
146+
[](ToddCoxeter_& self, Presentation<Word> const& p) {
147+
self.presentation_no_checks(to<Presentation<word_type>>(p));
148+
});
149+
}
150+
139151
thing.def(py::init<congruence_kind, ToddCoxeter_ const&>(),
140152
py::arg("knd"),
141153
py::arg("tc"),
@@ -620,7 +632,7 @@ Pro).
620632
:param tc: the :any:`ToddCoxeter` instance.
621633
:type tc: ToddCoxeter)pbdoc");
622634
} // bind_todd_coxeter
623-
} // namespace
635+
} // namespace
624636

625637
void init_todd_coxeter(py::module& m) {
626638
bind_todd_coxeter<word_type>(m, "ToddCoxeterWord");

0 commit comments

Comments
 (0)