2929#include < libsemigroups/presentation.hpp> // for Presentation
3030#include < libsemigroups/ranges.hpp> // for is_sorted
3131#include < libsemigroups/types.hpp> // for word_type
32+ #include < libsemigroups/word-range.hpp> // for operator+
3233
3334// pybind11....
34- #include < pybind11/cast.h> // for arg
35+ #include < pybind11/cast.h> // for arg
36+
37+ PYBIND11_MAKE_OPAQUE (std::vector<std::string>);
38+ PYBIND11_MAKE_OPAQUE (std::vector<libsemigroups::word_type>);
39+
3540#include < pybind11/detail/common.h> // for const_, overload_cast, ove...
3641#include < pybind11/detail/descr.h> // for operator+
3742#include < pybind11/functional.h> // for std::function conversion
3843#include < pybind11/pybind11.h> // for class_, init, module
3944#include < pybind11/pytypes.h> // for sequence, str_attr_accessor
4045#include < pybind11/stl.h> // for std::vector conversion
46+ #include < pybind11/stl_bind.h> // for bind_vector
4147
4248// libsemigroups_pybind11....
4349#include " main.hpp" // for init_present
@@ -46,6 +52,104 @@ namespace libsemigroups {
4652 namespace py = pybind11;
4753
4854 namespace {
55+ // TODO there are probably more functions like the vector_* functions
56+ // below that could be implemented.
57+
58+ [[nodiscard]] bool
59+ vector_equals_sequence (std::vector<word_type> const & self,
60+ py::object other) {
61+ if (py::isinstance<py::sequence>(other)) {
62+ py::sequence other_seq = other.cast <py::sequence>();
63+
64+ if (other_seq.size () != self.size ()) {
65+ return false ;
66+ }
67+
68+ for (size_t i = 0 ; i < self.size (); ++i) {
69+ py::sequence other_item_seq = other_seq[i].cast <py::sequence>();
70+ word_type const & self_item = self[i];
71+ if (other_item_seq.size () != self_item.size ()) {
72+ return false ;
73+ }
74+ for (size_t j = 0 ; j < self_item.size (); ++j) {
75+ if (self_item[j] != other_item_seq[j].cast <letter_type>()) {
76+ return false ;
77+ }
78+ }
79+ }
80+ return true ;
81+ }
82+ return false ;
83+ }
84+
85+ [[nodiscard]] bool
86+ vector_equals_sequence (std::vector<std::string> const & self,
87+ py::object other) {
88+ if (py::isinstance<py::sequence>(other)) {
89+ py::sequence other_seq = other.cast <py::sequence>();
90+
91+ if (other_seq.size () != self.size ()) {
92+ return false ;
93+ }
94+
95+ for (size_t i = 0 ; i < self.size (); ++i) {
96+ if (self[i] != other_seq[i].cast <std::string>()) {
97+ return false ;
98+ }
99+ }
100+ return true ;
101+ }
102+ return false ;
103+ }
104+
105+ template <typename Word>
106+ [[nodiscard]] std::vector<Word>
107+ vector_add_sequence (std::vector<Word> const & self, py::object other) {
108+ if (!py::isinstance<py::sequence>(other)) {
109+ throw py::type_error (" unsupported operand type(s) for +" );
110+ }
111+ py::sequence other_seq = other.cast <py::sequence>();
112+
113+ std::vector<Word> result (self);
114+ result.reserve (self.size () + other_seq.size ());
115+
116+ for (auto const & item : other_seq) {
117+ result.push_back (item.cast <Word>());
118+ }
119+
120+ return result;
121+ }
122+
123+ template <typename Word>
124+ [[nodiscard]] std::vector<Word>
125+ vector_add_vector (std::vector<Word> const & self,
126+ std::vector<Word> const & other) {
127+ std::vector<Word> result (self);
128+ result.insert (result.end (), other.begin (), other.end ());
129+ return result;
130+ }
131+
132+ template <typename Word>
133+ void bind_vector (py::module & m, std::string const & name) {
134+ py::bind_vector<std::vector<Word>>(
135+ m, name.c_str (), py::module_local (false ))
136+ .def (" __repr__" ,
137+ [](std::vector<Word> const & self) {
138+ return fmt::format (" [{}]" ,
139+ fmt::join (self.begin (), self.end (), " , " ));
140+ })
141+ .def (" __eq__" ,
142+ [](std::vector<Word> const & self, py::object other) {
143+ return vector_equals_sequence (self, other);
144+ })
145+ .def (" __ne__" ,
146+ [](std::vector<Word> const & self, py::object other) {
147+ return !vector_equals_sequence (self, other);
148+ })
149+ .def (" __add__" , &vector_add_sequence<Word>)
150+ .def (" __add__" , &vector_add_vector<Word>);
151+ }
152+
49153 template <typename Word>
50154 void bind_present (py::module & m, std::string const & name) {
51155 using Presentation_ = Presentation<Word>;
@@ -71,18 +175,22 @@ available in the module :any:`libsemigroups_pybind11.presentation`.)pbdoc");
71175 [](Presentation_ const & lhop, Presentation_ rhop) -> bool {
72176 return lhop == rhop;
73177 });
178+
74179 thing.def_readwrite (" rules" ,
75180 &Presentation_::rules,
76181 R"pbdoc(
77182Data member holding the rules of the presentation.
78183
79184The rules can be altered using the member functions of ``list``, and the
80- presentation can be checked for validity using :any:`throw_if_bad_alphabet_or_rules`.)pbdoc" );
185+ presentation can be checked for validity using
186+ :any:`throw_if_bad_alphabet_or_rules`.)pbdoc" );
187+
81188 thing.def (py::init<>(), R"pbdoc(
82189:sig=(self: Presentation) -> None:
83190Default constructor.
84191
85192Constructs an empty presentation with no rules and no alphabet.)pbdoc" );
193+
86194 thing.def (
87195 " copy" ,
88196 [](Presentation_ const & self) { return Presentation_ (self); },
@@ -94,6 +202,7 @@ Copy a :any:`Presentation` object.
94202:returns: A copy.
95203:rtype: Presentation
96204)pbdoc" );
205+
97206 thing.def (" __copy__" ,
98207 [](Presentation_ const & that) { return Presentation_ (that); });
99208 thing.def (
@@ -1655,9 +1764,11 @@ defined in the alphabet, and that the inverses act as semigroup inverses.
16551764 * :any:`presentation.throw_if_bad_inverses`
16561765)pbdoc" );
16571766 } // bind_inverse_present
1658- } // namespace
1767+ } // namespace
16591768
16601769 void init_present (py::module & m) {
1770+ bind_vector<word_type>(m, " RulesWord" );
1771+ bind_vector<std::string>(m, " RulesString" );
16611772 bind_present<word_type>(m, " PresentationWord" );
16621773 bind_present<std::string>(m, " PresentationString" );
16631774 }
0 commit comments