Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions docs/source/data-structures/order/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ Contents
rev_rpo_cmp
rpo_cmp
shortlex_compare
wr_cmp

Full API
--------
Expand All @@ -47,3 +48,5 @@ Full API
.. autofunction:: rpo_cmp

.. autofunction:: shortlex_compare

.. autofunction:: wr_cmp
4 changes: 4 additions & 0 deletions src/libsemigroups_pybind11/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
knuth_bendix,
konieczny,
matrix,
order,
paths,
pbr,
presentation,
Expand Down Expand Up @@ -51,6 +52,7 @@
from .knuth_bendix import KnuthBendix
from .konieczny import Konieczny
from .matrix import Matrix, MatrixKind
from .order import wr_cmp
from .presentation import InversePresentation, Presentation
from .schreier_sims import SchreierSims
from .sims import MinimalRepOrc, RepOrc, Sims1, Sims2, SimsRefinerFaithful, SimsRefinerIdeals
Expand Down Expand Up @@ -182,6 +184,7 @@
"shortlex_compare",
"side",
"tril",
"wr_cmp",
# Submodules
"action",
"adapters",
Expand All @@ -198,6 +201,7 @@
"knuth_bendix",
"konieczny",
"matrix",
"order",
"paths",
"pbr",
"presentation",
Expand Down
15 changes: 15 additions & 0 deletions src/libsemigroups_pybind11/order.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Copyright (c) 2026 J. D. Mitchell
#
# Distributed under the terms of the GPL license version 3.
#
# The full license is in the file LICENSE, distributed with this software.

"""Word-ordering comparison functions."""

from _libsemigroups_pybind11 import wr_cmp as _wr_cmp

from .detail.cxx_wrapper import wrap_cxx_free_fn as _wrap_cxx_free_fn

wr_cmp = _wrap_cxx_free_fn(_wr_cmp)

__all__ = ["wr_cmp"]
82 changes: 81 additions & 1 deletion src/order.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

// C++ stl headers....
#include <string> // for string
#include <vector> // for vector

// libsemigroups....
#include <libsemigroups/order.hpp> // for *_cmp, Order
Expand Down Expand Up @@ -260,6 +261,85 @@ Compare two words using reversed recursive-path ordering.
This will be removed from ``libsemigroups_pybind11`` in v2. Instead, use
:any:`rev_rpo_cmp`.
)pbdoc");

m.def(
"wr_cmp",
[](std::vector<size_t> const& levels, Word const& x, Word const& y) {
return wr_cmp(levels, x, y);
},
py::arg("levels"),
py::arg("x"),
py::arg("y"),
R"pbdoc(
:sig=(levels: list[int], x: str | list[int], y: str | list[int]) -> bool:
:only-document-once:
Compare two words using wreath-product ordering.

The *i*-th entry of *levels* is the level assigned to generator *i*.
Differences at higher levels dominate differences at lower levels, and
differences within one level are compared using len-lex ordering.

:param levels: the level assigned to each generator.
:type levels: list[int]
:param x: the first word.
:type x: str | list[int]
:param y: the second word.
:type y: str | list[int]
:returns: Whether *x* is less than *y*.
:rtype: bool

:raises LibsemigroupsError: if a letter is not a valid index into *levels*.

.. doctest:: python

>>> from libsemigroups_pybind11 import wr_cmp
>>> levels = [1, 1, 0]
>>> wr_cmp(levels, [2, 1, 2, 2], [2, 2, 1, 2])
True
)pbdoc");

m.def(
"wr_cmp",
[](Alphabet<Word> const& alphabet,
std::vector<size_t> const& levels,
Word const& x,
Word const& y) { return wr_cmp(alphabet, levels, x, y); },
py::arg("alphabet"),
py::arg("levels"),
py::arg("x"),
py::arg("y"),
R"pbdoc(
:sig=(alphabet: Alphabet, levels: list[int], x: str | list[int], y: str | list[int]) -> bool:
:only-document-once:
Compare two words using alphabet-aware wreath-product ordering.

Letters are mapped to their positions in *alphabet*, and the *i*-th entry of
*levels* is the level assigned to the *i*-th letter of *alphabet*.
Differences at higher levels dominate differences at lower levels, and
differences within one level are compared using len-lex ordering.

:param alphabet: the ordered alphabet containing the letters of both words.
:type alphabet: Alphabet
:param levels: the level assigned to each letter of *alphabet*.
:type levels: list[int]
:param x: the first word.
:type x: str | list[int]
:param y: the second word.
:type y: str | list[int]
:returns: Whether *x* is less than *y*.
:rtype: bool

:raises LibsemigroupsError: if a letter does not belong to *alphabet*, or its
position in *alphabet* is not a valid index into *levels*.

.. doctest:: python

>>> from libsemigroups_pybind11 import Alphabet, wr_cmp
>>> alphabet = Alphabet("bac")
>>> levels = [1, 1, 0]
>>> wr_cmp(alphabet, levels, "cbcc", "ccbc")
True
)pbdoc");
}
} // namespace

Expand Down Expand Up @@ -322,7 +402,7 @@ respectively, in new code.

The recursive-path ordering, as described in :cite:`Jantzen2012aa`
(Definition 1.2.14, page 24).

This is deprecated; use :any:`Order.rpo` instead.
)pbdoc")
.value("none", Order::none)
Expand Down
29 changes: 29 additions & 0 deletions tests/test_order.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
rev_rpo_cmp,
rpo_cmp,
shortlex_compare,
wr_cmp,
)


Expand Down Expand Up @@ -73,3 +74,31 @@ def test_deprecated_comparisons(old_compare, new_compare):
with pytest.deprecated_call():
result = old_compare("ab", "ba")
assert result == new_compare("ab", "ba")


def test_wr_cmp_for_integer_words():
"""Check wreath-product comparison, validation, and its unchecked form."""
levels = [0, 0, 1]
x = [0, 2]
y = [1, 2]

assert wr_cmp(levels, x, y)
assert not wr_cmp(levels, y, x)

with pytest.raises(LibsemigroupsError):
wr_cmp([0, 1], [0, 2], [0, 1])


def test_wr_cmp_with_alphabet():
"""Check wreath-product comparison over an explicitly ordered alphabet."""
alphabet = Alphabet("bac")
levels = [1, 1, 0]

assert wr_cmp(alphabet, levels, "cbcc", "ccbc")
assert wr_cmp(alphabet, levels, "ac", "ca")

word_alphabet = Alphabet([1, 0])
assert wr_cmp(word_alphabet, [0, 0], [1], [0])

with pytest.raises(LibsemigroupsError):
wr_cmp(alphabet, levels, "d", "b")
Loading