libsemigroups  v3.3.0
C++ library for semigroups and monoids
Loading...
Searching...
No Matches
obvinf.hpp
1//
2// libsemigroups - C++ library for semigroups and monoids
3// Copyright (C) 2020-2025 James D. Mitchell + Reinis Cirpons
4//
5// This program is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with this program. If not, see <http://www.gnu.org/licenses/>.
17//
18
19// This file contains a helper class for checking whether or not a congruence
20// defined by generating pairs or finitely presented semigroup or monoid is
21// obviously infinite.
22
23#ifndef LIBSEMIGROUPS_OBVINF_HPP_
24#define LIBSEMIGROUPS_OBVINF_HPP_
25
26#include <cstddef> // for size_t
27#include <numeric> // for accumulate
28#include <string> // for string
29#include <utility> // for pair
30#include <vector> // for vector
31
32#include "config.hpp" // for LIBSEMIGROUPS_EIGEN_ENABLED
33#include "ranges.hpp" // for rx/ranges
34#include "types.hpp" // for word_type etc
35#include "word-graph-helpers.hpp" // for word_graph
36#include "word-graph.hpp" // for is_acyclic
37#include "word-range.hpp" // for ToWord
38
39#include "detail/eigen.hpp" // for eigen
40#include "detail/uf.hpp" // for Duf
41
42namespace libsemigroups {
43#ifndef LIBSEMIGROUPS_PARSED_BY_DOXYGEN
44
45 namespace detail {
46 template <typename Rewriter, typename ReductionOrder>
47 class KnuthBendixImpl; // forward decl
48 class ToddCoxeterImpl; // forward decl
49 } // namespace detail
50
51 template <typename Word>
52 class Congruence; // forward decl
53
54 template <typename Word>
55 class Kambites; // forward decl
56
57 template <typename Word>
58 class Presentation; // forward decl
59#endif
60
61 namespace presentation {
62 template <typename Word>
64 }
65
78
127 // TODO(1) there are definitely some assumptions about the calls to the member
128 // functions of an IsObviouslyInfinite (see for example the function
129 // is_obviously_infinite for a Presentation). These should be documented.
130 //
131 // TODO(1) this class should be more generic, like detail::CongruenceCommon
132 // and its derived classes, allowing arbitrary iterators of rules to be added
133 class IsObviouslyInfinite {
134 // The default constructor is private since an object that is default
135 // constructed isn't usable with the current public API.
136 IsObviouslyInfinite() = default;
137
138 public:
142
150
154
164 explicit IsObviouslyInfinite(size_t n);
165
181 IsObviouslyInfinite& init(size_t n);
182
192 explicit IsObviouslyInfinite(std::string const& lphbt)
193 : IsObviouslyInfinite(lphbt.size()) {}
194
210 IsObviouslyInfinite& init(std::string const& lphbt) {
211 return init(lphbt.size());
212 }
213
215 IsObviouslyInfinite(IsObviouslyInfinite const&) = delete;
216
218 IsObviouslyInfinite(IsObviouslyInfinite&&) = delete;
219
221 IsObviouslyInfinite& operator=(IsObviouslyInfinite const&) = delete;
222
224 IsObviouslyInfinite& operator=(IsObviouslyInfinite&&) = delete;
225
226 ~IsObviouslyInfinite();
227
246 IsObviouslyInfinite& add_rules_no_checks(word_type const&,
249
271 template <typename Char>
272 IsObviouslyInfinite& add_rules_no_checks(
273 std::basic_string<Char> const& lphbt,
274 typename std::vector<std::basic_string<Char>>::const_iterator first,
275 typename std::vector<std::basic_string<Char>>::const_iterator last) {
276#ifdef LIBSEMIGROUPS_EIGEN_ENABLED
277 auto matrix_start = _matrix.rows();
278 _matrix.conservativeResize(matrix_start + (last - first) / 2,
279 Eigen::NoChange);
280 _matrix.block(matrix_start, 0, (last - first) / 2, _matrix.cols())
281 .setZero();
282#else
283 auto matrix_start = 0;
284 std::fill(_matrix.begin(), _matrix.end(), 0);
285#endif
286
287 v4::ToWord stw(lphbt);
288 word_type lhs, rhs;
289 for (auto it = first; it < last; ++it) {
290 stw(lhs, *it++); // lhs changed in-place
291 stw(rhs, *it); // rhs changed in-place
292 private_add_rule(matrix_start + (it - first) / 2, lhs, rhs);
293 }
294 _nr_letter_components = _letter_components.number_of_blocks();
295 return *this;
296 }
297
319 IsObviouslyInfinite& add_rules_no_checks(
320 char const* lphbt,
323 std::vector<std::string> copy(first, last);
324 return add_rules_no_checks(std::string(lphbt), copy.begin(), copy.end());
325 }
326
345 template <typename Char>
350#ifdef LIBSEMIGROUPS_EIGEN_ENABLED
351 auto matrix_start = _matrix.rows();
352 _matrix.conservativeResize(matrix_start + (last - first) / 2,
353 Eigen::NoChange);
354 _matrix.block(matrix_start, 0, (last - first) / 2, _matrix.cols())
355 .setZero();
356#else
357 auto matrix_start = 0;
358 std::fill(_matrix.begin(), _matrix.end(), 0);
359#endif
360
361 v4::ToWord to_word(lphbt);
362 word_type lhs, rhs;
364 for (auto it = first; it < last; ++it) {
365 // changes lhs in-place
366 tmp.assign(it->begin(), it->end());
367 to_word(lhs, tmp);
368 ++it;
369 // changes rhs in-place
370 tmp.assign(it->begin(), it->end());
371 to_word(rhs, tmp);
372 private_add_rule(matrix_start + (it - first) / 2, lhs, rhs);
373 }
374 _nr_letter_components = _letter_components.number_of_blocks();
375 return *this;
376 }
377
399 IsObviouslyInfinite& add_rules_no_checks(std::string const& lphbt,
402
414 bool result() const;
415
416 // TODO(1) certificate() returning why the thing is obviously infinite
417
418 private:
419 void private_add_rule(size_t const, word_type const&, word_type const&);
420
421 inline void letters_in_word(size_t row, word_type const& w, int64_t adv) {
422 for (size_t const& x : w) {
423 matrix(row, x) += adv;
424 _seen[x] = true;
425 }
426 }
427
428 inline void plus_letters_in_word(size_t row, word_type const& w) {
429 letters_in_word(row, w, 1);
430 }
431
432 inline void minus_letters_in_word(size_t row, word_type const& w) {
433 letters_in_word(row, w, -1);
434 }
435
436 inline int64_t& matrix(size_t row, size_t col) {
437#ifdef LIBSEMIGROUPS_EIGEN_ENABLED
438 return _matrix(row, col);
439#else
440 (void) row;
441 return _matrix[col];
442#endif
443 }
444
445 inline bool matrix_row_sums_to_0(size_t row) {
446#ifdef LIBSEMIGROUPS_EIGEN_ENABLED
447 return _matrix.row(row).sum() == 0;
448#else
449 (void) row;
450 return std::accumulate(_matrix.cbegin(), _matrix.cend(), 0) == 0;
451#endif
452 }
453
454 // letter_type i belongs to "preserve" if there exists a relation where
455 // the number of occurrences of i is not the same on both sides of the
456 // relation letter_type i belongs to "unique" if there is a relation
457 // where one side consists solely of i.
458 bool _empty_word;
459 detail::Duf<> _letter_components;
460 size_t _nr_gens;
461 size_t _nr_letter_components;
462 size_t _nr_relations;
463 bool _preserve_length;
464 std::vector<bool> _preserve;
465 std::vector<bool> _seen;
466 std::vector<bool> _unique;
467
468#ifdef LIBSEMIGROUPS_EIGEN_ENABLED
469 Eigen::Matrix<int64_t, Eigen::Dynamic, Eigen::Dynamic> _matrix;
470#else
471 std::vector<int64_t> _matrix;
472#endif
473 };
474
496 template <typename Word>
499 if (p.alphabet().empty()) {
500 return false;
501 }
502 auto it
504
505 if (*it != p.alphabet().size() - 1) {
506 auto copy_p = p;
508 copy_p,
509 rx::seq<typename Presentation<Word>::letter_type>(0)
510 | rx::take(p.alphabet().size()) | rx::to_vector());
511 IsObviouslyInfinite ioi(copy_p.alphabet().size());
513 p.alphabet(), copy_p.rules.cbegin(), copy_p.rules.cend());
514 return ioi.result();
515 }
516
519 return ioi.result();
520 }
521
541 template <>
543
566 bool is_obviously_infinite(detail::ToddCoxeterImpl const& tc);
567
588 // This function is implemented in cong-class.tpp
589 template <typename Word>
590 bool is_obviously_infinite(Congruence<Word>& c);
591
613 template <typename Word>
614 bool is_obviously_infinite(Kambites<Word>& k) {
615 if (k.finished() && k.small_overlap_class() >= 3) {
616 return true;
617 }
618 auto const& p = k.presentation();
619 IsObviouslyInfinite ioi(p.alphabet().size());
620 ioi.add_rules_no_checks(p.alphabet(), p.rules.cbegin(), p.rules.cend());
621 ioi.add_rules_no_checks(p.alphabet(),
622 k.internal_generating_pairs().cbegin(),
623 k.internal_generating_pairs().cend());
624 if (ioi.result()) {
625 return true;
626 }
627 return k.small_overlap_class() >= 3;
628 }
629
651 template <typename Rewriter, typename ReductionOrder>
652 bool
653 is_obviously_infinite(detail::KnuthBendixImpl<Rewriter, ReductionOrder>& kb) {
654 if (kb.finished()) {
655 return !v4::word_graph::is_acyclic(kb.gilman_graph());
656 }
657 auto const& p = kb.internal_presentation();
658 if (p.alphabet().empty()) {
659 return false;
660 }
661 IsObviouslyInfinite ioi(p.alphabet().size());
662 ioi.add_rules_no_checks(p.alphabet(), p.rules.cbegin(), p.rules.cend());
663 ioi.add_rules_no_checks(p.alphabet(),
664 kb.internal_generating_pairs().cbegin(),
665 kb.internal_generating_pairs().cend());
666 return ioi.result();
667 }
668
669} // namespace libsemigroups
670#endif // LIBSEMIGROUPS_OBVINF_HPP_
T accumulate(T... args)
T assign(T... args)
T begin(T... args)
Class for checking if a finitely presented semigroup or monoid is obviously infinite.
Definition obvinf.hpp:133
typename std::vector< std::pair< std::string, std::string > >::const_iterator const_iterator_pair_string
Alias for std::vector< std::pair<std::string, std::string>>::const_iterator.
Definition obvinf.hpp:148
IsObviouslyInfinite & add_rules_no_checks(word_type const &, const_iterator_word_type first, const_iterator_word_type last)
Add rules from iterators to word_type.
IsObviouslyInfinite(size_t n)
Construct from alphabet size.
IsObviouslyInfinite & add_rules_no_checks(char const *lphbt, typename std::vector< std::string >::const_iterator first, typename std::vector< std::string >::const_iterator last)
Add rules from iterators to std::vector of std::string.
Definition obvinf.hpp:319
IsObviouslyInfinite & add_rules_no_checks(std::string const &lphbt, const_iterator_pair_string first, const_iterator_pair_string last)
Add rules from iterators to std::pair of std::string.
IsObviouslyInfinite(IsObviouslyInfinite &&)=delete
Deleted.
IsObviouslyInfinite(std::string const &lphbt)
Construct from alphabet.
Definition obvinf.hpp:192
IsObviouslyInfinite & operator=(IsObviouslyInfinite const &)=delete
Deleted.
IsObviouslyInfinite & add_rules_no_checks(std::basic_string< Char > const &lphbt, typename std::vector< std::basic_string< Char > >::const_iterator first, typename std::vector< std::basic_string< Char > >::const_iterator last)
Add rules from iterators to std::string.
Definition obvinf.hpp:272
IsObviouslyInfinite & init(std::string const &lphbt)
Definition obvinf.hpp:210
IsObviouslyInfinite & add_rules_no_checks(std::basic_string< Char > const &lphbt, const_iterator_word_type first, const_iterator_word_type last)
Add rules from iterators to word_type.
Definition obvinf.hpp:347
typename std::vector< word_type >::const_iterator const_iterator_word_type
Alias for std::vector<word_type>::const_iterator.
Definition obvinf.hpp:140
typename std::vector< std::string >::const_iterator const_iterator_string
Alias for std::vector<std::string>::const_iterator.
Definition obvinf.hpp:152
IsObviouslyInfinite(IsObviouslyInfinite const &)=delete
Deleted.
IsObviouslyInfinite & init(size_t n)
bool result() const
Returns whether or not the finitely presented semigroup or monoid is obviously infinite.
IsObviouslyInfinite & operator=(IsObviouslyInfinite &&)=delete
Deleted.
For an implementation of presentations for semigroups or monoids.
Definition presentation.hpp:103
void throw_if_bad_alphabet_or_rules() const
Check if the alphabet and rules are valid.
Definition presentation.hpp:639
std::vector< word_type > rules
Data member holding the rules of the presentation.
Definition presentation.hpp:132
word_type const & alphabet() const noexcept
Return the alphabet of the presentation.
Definition presentation.hpp:184
typename word_type::value_type letter_type
Type of the letters in the words that constitute the rules of a Presentation object.
Definition presentation.hpp:110
bool finished() const
Check if run has been run to completion or not.
Class for converting strings to word_type with specified alphabet.
Definition word-range.hpp:772
T empty(T... args)
T end(T... args)
T fill(T... args)
size_t small_overlap_class()
Get the small overlap class.
Presentation< native_word_type > const & presentation() const noexcept
Get the presentation used to define a Kambites instance (if any).
Definition kambites-class.hpp:343
WordGraph< uint32_t > const & gilman_graph()
Return the Gilman WordGraph.
bool is_obviously_infinite(Presentation< Word > const &p)
Function for checking if the finitely presented semigroup or monoid defined by a Presentation object ...
Definition obvinf.hpp:497
std::vector< letter_type > word_type
Type for a word over the generators of a semigroup.
Definition types.hpp:99
T max_element(T... args)
Namespace for Presentation helper functions.
Definition obvinf.hpp:61
void change_alphabet(Presentation< Word > &, Word const &)
Change or re-order the alphabet.
Namespace for everything in the libsemigroups library.
Definition action.hpp:44
T size(T... args)