Skip to content

Commit 004af1e

Browse files
Joseph-Edwardsjames-d-mitchell
authored andcommitted
presentation: Add more rules functions
1 parent 01fcec4 commit 004af1e

4 files changed

Lines changed: 252 additions & 0 deletions

File tree

docs/source/data-structures/presentations/present-helpers.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,13 @@ Contents
3434
.. autosummary::
3535
:signatures: short
3636

37+
add_commutes_rules
3738
add_commutator_rule
3839
add_cyclic_conjugates
40+
add_idempotent_rules
3941
add_identity_rules
4042
add_inverse_rules
43+
add_involution_rules
4144
add_rule
4245
add_rules
4346
add_zero_rules

src/libsemigroups_pybind11/presentation/__init__.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,12 @@
1414
PresentationString as _PresentationString,
1515
PresentationWord as _PresentationWord,
1616
presentation_add_commutator_rule as _add_commutator_rule,
17+
presentation_add_commutes_rules as _add_commutes_rules,
1718
presentation_add_cyclic_conjugates as _add_cyclic_conjugates,
19+
presentation_add_idempotent_rules as _add_idempotent_rules,
1820
presentation_add_identity_rules as _add_identity_rules,
1921
presentation_add_inverse_rules as _add_inverse_rules,
22+
presentation_add_involution_rules as _add_involution_rules,
2023
presentation_add_rule as _add_rule,
2124
presentation_add_rules as _add_rules,
2225
presentation_add_zero_rules as _add_zero_rules,
@@ -232,8 +235,11 @@ def __init__(self: _Self, *args, **kwargs) -> None:
232235

233236

234237
add_commutator_rule = _wrap_cxx_free_fn(_add_commutator_rule)
238+
add_commutes_rules = _wrap_cxx_free_fn(_add_commutes_rules)
239+
add_idempotent_rules = _wrap_cxx_free_fn(_add_idempotent_rules)
235240
add_identity_rules = _wrap_cxx_free_fn(_add_identity_rules)
236241
add_inverse_rules = _wrap_cxx_free_fn(_add_inverse_rules)
242+
add_involution_rules = _wrap_cxx_free_fn(_add_involution_rules)
237243
add_rule = _wrap_cxx_free_fn(_add_rule)
238244
add_rules = _wrap_cxx_free_fn(_add_rules)
239245
add_zero_rules = _wrap_cxx_free_fn(_add_zero_rules)
@@ -277,9 +283,12 @@ def __init__(self: _Self, *args, **kwargs) -> None:
277283
__all__ = [
278284
"Presentation",
279285
"InversePresentation",
286+
"add_commutes_rules",
280287
"add_commutator_rule",
288+
"add_idempotent_rules",
281289
"add_identity_rules",
282290
"add_inverse_rules",
291+
"add_involution_rules",
283292
"add_rule",
284293
"add_rules",
285294
"add_zero_rules",

src/present.cpp

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,7 +491,29 @@ the alphabet is :math:`\{a_1, \ldots, a_n\}`; the 2nd parameter *vals* is
491491
if :math:`e ^ {-1} = e` does not hold.
492492
493493
:complexity: :math:`O(n)` where :math:`n` is ``p.alphabet().size()``.)pbdoc");
494+
m.def("presentation_add_involution_rules",
495+
&presentation::add_involution_rules<Word>,
496+
py::arg("p"),
497+
py::arg("letters"),
498+
R"pbdoc(
499+
:sig=(p: Presentation, letters: Word) -> None:
500+
:only-document-once:
501+
502+
Add rules that define involutions.
503+
504+
Adds rules to *p* of the form :math:`a^2 = \varepsilon` for every letter
505+
:math:`a` in *letters*.
506+
507+
:param p: the presentation to add rules to.
508+
:type p: Presentation
509+
510+
:param letters: the letters to add involution rules for.
511+
:type letters: :ref:`Word<pseudo_word_type_helper>`
494512
513+
:raises LibsemigroupsError:
514+
if any letter in *letters* is not in ``p.alphabet()``, or if
515+
``p.contains_empty_word()`` returns ``False``.
516+
)pbdoc");
495517
m.def(
496518
"presentation_add_rule",
497519
[](Presentation_& p, Word const& lhop, Word const& rhop) {
@@ -829,6 +851,91 @@ inverses from the rules in *p*, using :any:`try_detect_inverses`. If
829851
if *x*, *y*, or *id* contains a letter not belonging to
830852
``p.alphabet()``, if :any:`try_detect_inverses` throws, or if *x* or
831853
*y* contains a letter for which no inverse was detected.
854+
)pbdoc");
855+
m.def(
856+
"presentation_add_commutes_rules",
857+
[](Presentation_& p, Word const& letters) {
858+
presentation::add_commutes_rules(p, letters);
859+
},
860+
py::arg("p"),
861+
py::arg("letters"),
862+
R"pbdoc(
863+
:sig=(p: Presentation, letters: Word) -> None:
864+
:only-document-once:
865+
866+
Add rules so specific letters commute.
867+
868+
Adds rules to *p* of the form :math:`uv = vu` for every pair of letters
869+
:math:`u, v` in *letters*.
870+
871+
:param p: the presentation to add rules to.
872+
:type p: Presentation
873+
874+
:param letters: the collection of letters to add rules for.
875+
:type letters: :ref:`Word<pseudo_word_type_helper>`
876+
877+
:raises LibsemigroupsError:
878+
if any letter in *letters* is not in ``p.alphabet()``.
879+
)pbdoc");
880+
m.def(
881+
"presentation_add_commutes_rules",
882+
[](Presentation_& p, Word const& letters1, Word const& letters2) {
883+
presentation::add_commutes_rules(p, letters1, letters2);
884+
},
885+
py::arg("p"),
886+
py::arg("letters1"),
887+
py::arg("letters2"),
888+
R"pbdoc(
889+
:sig=(p: Presentation, letters1: Word, letters2: Word) -> None:
890+
:only-document-once:
891+
892+
Add rules so specific letters commute.
893+
894+
Adds rules to *p* of the form :math:`uv = vu` for every letter :math:`u` in
895+
*letters1* and :math:`v` in *letters2*.
896+
897+
:param p: the presentation to add rules to.
898+
:type p: Presentation
899+
900+
:param letters1: the first collection of letters to add rules for.
901+
:type letters1: :ref:`Word<pseudo_word_type_helper>`
902+
903+
:param letters2: the second collection of letters to add rules for.
904+
:type letters2: :ref:`Word<pseudo_word_type_helper>`
905+
906+
:raises LibsemigroupsError:
907+
if any letter in *letters1* or *letters2* is not in ``p.alphabet()``.
908+
)pbdoc");
909+
m.def(
910+
"presentation_add_commutes_rules",
911+
[](Presentation_& p, Word const& letters, std::vector<Word> words) {
912+
presentation::add_commutes_rules(p, letters, words);
913+
},
914+
py::arg("p"),
915+
py::arg("letters"),
916+
py::arg("words"),
917+
R"pbdoc(
918+
:sig=(p: Presentation, letters: Word, words: list[Word]) -> None:
919+
:only-document-once:
920+
921+
Add rules so specific letters commute.
922+
923+
Adds rules to *p* of the form :math:`uv = vu` for every letter :math:`u` in
924+
*letters* and word :math:`v` in *words*.
925+
926+
:param p: the presentation to add rules to.
927+
:type p: Presentation
928+
929+
:param letters: the collection of letters to add rules for.
930+
:type letters: :ref:`Word<pseudo_word_type_helper>`
931+
932+
:param words: the collection of words to add rules for.
933+
:type words: list[:ref:`Word<pseudo_word_type_helper>`]
934+
935+
936+
:raises LibsemigroupsError:
937+
if any letter in *letters*, or any letter in any word in *words* is not in
938+
``p.alphabet()``.
832939
)pbdoc");
833940
m.def(
834941
"presentation_are_rules_sorted",
@@ -1666,6 +1773,27 @@ empty word to the presentation *p*, for every cyclic permutation ``w`` of
16661773
if *relator* contains any letters not belonging to ``p.alphabet()``.
16671774
16681775
:raises LibsemigroupsError: if *p* does not contain the empty word.)pbdoc");
1776+
m.def("presentation_add_idempotent_rules",
1777+
&presentation::add_idempotent_rules<Word>,
1778+
py::arg("p"),
1779+
py::arg("letters"),
1780+
R"pbdoc(
1781+
:sig=(p: Presentation, letters: Word) -> None:
1782+
:only-document-once:
1783+
Add rules that define idempotents.
1784+
1785+
Adds rules to *p* of the form :math:`a^2 = a` for every letter :math:`a` in
1786+
*letters*.
1787+
1788+
:param p: the presentation to add rules to.
1789+
:type p: Presentation
1790+
1791+
:param letters: the letters to make idempotent.
1792+
:type letters: :ref:`Word<pseudo_word_type_helper>`
1793+
1794+
:raises LibsemigroupsError:
1795+
if any letter in *letters* is not in ``p.alphabet()``.
1796+
)pbdoc");
16691797

16701798
// We do not bind presentation::find_rule because it returns an iterator
16711799
//

tests/test_present.py

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,78 @@ def check_add_commutator_rule(W):
468468
]
469469

470470

471+
def check_add_commutes_rules(W):
472+
p = Presentation(W([0]))
473+
with pytest.raises(LibsemigroupsError):
474+
presentation.add_commutes_rules(p, W([0]), W([1]))
475+
476+
p.alphabet(W([0, 1, 2]))
477+
presentation.add_rule(p, W([0, 1, 2, 1]), W([0, 0]))
478+
presentation.add_commutes_rules(p, W([0]), W([1]))
479+
480+
assert p.rules == [W([0, 1, 2, 1]), W([0, 0]), W([0, 1]), W([1, 0])]
481+
482+
presentation.add_commutes_rules(p, W([1, 1]), W([2]))
483+
assert p.rules == [
484+
W([0, 1, 2, 1]),
485+
W([0, 0]),
486+
W([0, 1]),
487+
W([1, 0]),
488+
W([2, 1]),
489+
W([1, 2]),
490+
W([2, 1]),
491+
W([1, 2]),
492+
]
493+
494+
presentation.add_commutes_rules(p, W([2]))
495+
assert p.rules == [
496+
W([0, 1, 2, 1]),
497+
W([0, 0]),
498+
W([0, 1]),
499+
W([1, 0]),
500+
W([2, 1]),
501+
W([1, 2]),
502+
W([2, 1]),
503+
W([1, 2]),
504+
]
505+
506+
presentation.add_commutes_rules(p, W([2, 0]))
507+
assert p.rules == [
508+
W([0, 1, 2, 1]),
509+
W([0, 0]),
510+
W([0, 1]),
511+
W([1, 0]),
512+
W([2, 1]),
513+
W([1, 2]),
514+
W([2, 1]),
515+
W([1, 2]),
516+
W([2, 0]),
517+
W([0, 2]),
518+
]
519+
520+
presentation.add_commutes_rules(p, W([1, 2]), [W([0, 0, 1]), W([1, 0])])
521+
assert p.rules == [
522+
W([0, 1, 2, 1]),
523+
W([0, 0]),
524+
W([0, 1]),
525+
W([1, 0]),
526+
W([2, 1]),
527+
W([1, 2]),
528+
W([2, 1]),
529+
W([1, 2]),
530+
W([2, 0]),
531+
W([0, 2]),
532+
W([1, 0, 0, 1]),
533+
W([0, 0, 1, 1]),
534+
W([1, 1, 0]),
535+
W([1, 0, 1]),
536+
W([2, 0, 0, 1]),
537+
W([0, 0, 1, 2]),
538+
W([2, 1, 0]),
539+
W([1, 0, 2]),
540+
]
541+
542+
471543
def check_add_inverse_rules(W):
472544
p = Presentation(W([0, 1, 2]))
473545
presentation.add_rule(p, W([0, 1, 2, 1]), W([0, 0]))
@@ -487,6 +559,31 @@ def check_add_inverse_rules(W):
487559
assert p.rules == [W([0, 1, 2, 1]), W([0, 0]), W([1, 2]), W([0]), W([2, 1]), W([0])]
488560

489561

562+
def check_add_involution_rules(W):
563+
p = Presentation(W([0]))
564+
with pytest.raises(LibsemigroupsError):
565+
presentation.add_involution_rules(p, W([0, 1]))
566+
p.alphabet(W([0, 1, 2]))
567+
with pytest.raises(LibsemigroupsError):
568+
presentation.add_involution_rules(p, W([0, 1]))
569+
570+
p.contains_empty_word(True)
571+
presentation.add_rule(p, W([0, 1, 2, 1]), W([0, 0]))
572+
presentation.add_involution_rules(p, W([0, 1]))
573+
assert p.rules == [W([0, 1, 2, 1]), W([0, 0]), W([0, 0]), W([]), W([1, 1]), W([])]
574+
575+
576+
def check_add_idempotent_rules(W):
577+
p = Presentation(W([0]))
578+
with pytest.raises(LibsemigroupsError):
579+
presentation.add_idempotent_rules(p, W([0, 1]))
580+
581+
p.alphabet(W([0, 1, 2]))
582+
presentation.add_rule(p, W([0, 1, 2, 1]), W([0, 0]))
583+
presentation.add_idempotent_rules(p, W([0, 1]))
584+
assert p.rules == [W([0, 1, 2, 1]), W([0, 0]), W([0, 0]), W([0]), W([1, 1]), W([1])]
585+
586+
490587
def check_remove_duplicate_rules(W):
491588
p = Presentation(W([0, 1, 2]))
492589
presentation.add_rule(p, W([0, 1, 2, 1]), W([0, 0]))
@@ -1647,3 +1744,18 @@ def test_add_commutator_rule_errors():
16471744
def test_add_commutator_rule():
16481745
check_add_commutator_rule(to_word)
16491746
check_add_commutator_rule(to_string)
1747+
1748+
1749+
def test_add_commutes_rules():
1750+
check_add_commutes_rules(to_word)
1751+
check_add_commutes_rules(to_string)
1752+
1753+
1754+
def test_add_involution_rules():
1755+
check_add_involution_rules(to_word)
1756+
check_add_involution_rules(to_string)
1757+
1758+
1759+
def test_add_idempotent_rules():
1760+
check_add_idempotent_rules(to_word)
1761+
check_add_idempotent_rules(to_string)

0 commit comments

Comments
 (0)