libsemigroups  v3.0.0
C++ library for semigroups and monoids
Loading...
Searching...
No Matches
schreier-sims.hpp
1//
2// libsemigroups - C++ library for semigroups and monoids
3// Copyright (C) 2019-2025 James D. Mitchell
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// TODO(later)
20//
21// 0. check use of:
22// * element_type []
23// * const_value_type []
24// * reference []
25// * const_element_reference []
26// * internal_element_type []
27// * internal_const_element_type []
28// * internal_reference []
29// * internal_const_reference []
30// 1. iterator to the elements (Finn requires this)
31// 2. stabilizer member func
32// 3. change base
33// 4. random version
34// 5. try it with Digraphs
35
36// TODO:
37// * code coverage (can't do it on MacBook Pro at present)
38
39#ifndef LIBSEMIGROUPS_SCHREIER_SIMS_HPP_
40#define LIBSEMIGROUPS_SCHREIER_SIMS_HPP_
41
42#include <array> // for array
43#include <cstddef> // for size_t
44#include <cstdint> // for uint64_t
45#include <iterator> // for distance
46#include <limits> // for numeric_limits
47#include <memory> // for make_unique
48#include <string> // for operator+, basic_string
49#include <string_view> // for string_view
50#include <type_traits> // for is_same
51#include <unordered_set> // for unordered_set
52
53#include "adapters.hpp" // for action, degree, inverse
54#include "config.hpp" // for LIBSEMIGROUPS_HPCOMBI_ENABLED
55#include "debug.hpp" // for LIBSEMIGROUPS_ASSERT
56#include "exception.hpp" // for LIBSEMIGROUPS_EXCEPTION
57#include "transf.hpp" // for Perm
58#include "types.hpp" // for SmallestInteger
59
60#include "detail/bruidhinn-traits.hpp" // for BruidhinnTraits
61#include "detail/containers.hpp" // for Array2, StaticTriVector2
62#include "detail/fmt.hpp" // for format
63#include "detail/int-range.hpp" // for IntRange
64
65namespace libsemigroups {
66
81
98 template <size_t N, typename Point, typename Element>
142
172 template <size_t N,
173 typename Point = typename SmallestInteger<N>::type,
174 typename Element = LeastPerm<N>,
176 class SchreierSims : private detail::BruidhinnTraits<Element> {
178 "incompatible point types, Traits::point_type and Point "
179 "must be the same");
180 static_assert(
182 "incompatible element types, Traits::element_type and Element "
183 "must be the same");
184 static_assert(N <= std::numeric_limits<Point>::max(),
185 "the first template parameter N cannot be expressed as value "
186 "of type equal to the second template parameter Point");
187
188 using internal_element_type =
189 typename detail::BruidhinnTraits<Element>::internal_value_type;
190 using internal_reference =
191 typename detail::BruidhinnTraits<Element>::internal_reference;
192 using internal_const_element_type =
193 typename detail::BruidhinnTraits<Element>::internal_const_value_type;
194
195 public:
201 using element_type = typename detail::BruidhinnTraits<Element>::value_type;
202
208 typename detail::BruidhinnTraits<Element>::const_reference;
209
214 typename detail::BruidhinnTraits<Element>::reference;
215
219 using point_type = Point;
220
224 using domain_type = typename Traits::domain_type;
225
229 using index_type = typename Traits::index_type;
230
234 using Action = typename Traits::Action;
235
237 using Degree = typename Traits::Degree;
238
240 using EqualTo = typename Traits::EqualTo;
241
243 using Inverse = typename Traits::Inverse;
244
246 using One = typename Traits::One;
247
249 using Product = typename Traits::Product;
250
252 using Swap = typename Traits::Swap;
253
254 private:
255 // TODO replace Array2 by TriArray2 everywhere below
257 index_type _base_size;
258 domain_type _domain;
259 bool _finished;
260 internal_element_type _one;
261 detail::StaticTriVector2<point_type, N> _orbits;
262 detail::Array2<bool, N> _orbits_lookup;
263 detail::StaticTriVector2<internal_element_type, N> _strong_gens;
264 mutable internal_element_type _tmp_element1;
265 mutable internal_element_type _tmp_element2;
266 detail::Array2<internal_element_type, N> _transversal;
267 detail::Array2<internal_element_type, N> _inversal;
268
269 public:
280
292
294
299
303 // TODO this requires more tests
305
309 // TODO fix in the same way as the move constructor above
311
315 // TODO this requires more tests
317
338
357
372 // Not noexcept because strong_generator isn't
373 [[nodiscard]] const_element_reference generator(index_type index) const {
374 return strong_generator(0, index);
375 }
376
391 // Not noexcept because strong_generator_no_checks isn't
392 [[nodiscard]] const_element_reference
394 return strong_generator_no_checks(0, index);
395 }
396
409 // Not noexcept because number_of_strong_generators_no_checks is not.
410 [[nodiscard]] size_t number_of_generators() const;
411
426 [[nodiscard]] size_t number_of_strong_generators(index_type depth) const {
427 throw_if_bad_depth(depth);
429 }
430
449 // Not noexcept because StaticTriVector2::size(size_t) is not.
450 [[nodiscard]] size_t
452 return _strong_gens.size(depth);
453 }
454
471 [[nodiscard]] const_element_reference
473
494 // not noexcept because StaticTriVector2 isn't
495 [[nodiscard]] const_element_reference
497 return this->to_external_const(_strong_gens.at(depth, index));
498 }
499
520 // not noexcept because Array2::operator[] isn't
521 [[nodiscard]] const_element_reference
523 return this->to_external_const(_transversal[depth][pt]);
524 }
525
543 // Not noexcept because throws
544 [[nodiscard]] const_element_reference
546
567 // Not noexcept because std::array::operator[] isn't
568 [[nodiscard]] const_element_reference
570 point_type pt) const {
571 return this->to_external_const(_inversal[depth][pt]);
572 }
573
592 [[nodiscard]] const_element_reference
594
615 // Not noexcept because std::array::operator[] isn't
616 [[nodiscard]] bool orbit_lookup_no_checks(index_type depth,
617 point_type pt) const {
618 return _orbits_lookup[depth][pt];
619 }
620
637 [[nodiscard]] bool orbit_lookup(index_type depth, point_type pt) const {
638 throw_if_bad_depth(depth);
639 throw_if_point_gt_degree(pt);
640 return orbit_lookup_no_checks(depth, pt);
641 }
642
655 // Not noexcept because StaticTriVector2::size isn't
656 [[nodiscard]] bool empty() const {
657 return _strong_gens.size(0) == 0;
658 }
659
668 // not noexcept because run isn't
669 [[nodiscard]] uint64_t size();
670
681 [[nodiscard]] uint64_t current_size() const;
682
692 // TODO tests
693 // not noexcept because internal_sift isn't
695 // changes x in place, and uses _tmp_element1
696 internal_sift(this->to_internal(x));
697 }
698
708 // TODO tests
709 // not noexcept because can throw
711 throw_if_bad_degree(x);
713 }
714
726 // not noexcept because internal_sift isn't
728 this->to_external(_tmp_element2) = x;
729 // changes _tmp_element2 in place, and uses _tmp_element1
730 internal_sift(_tmp_element2);
731 return this->to_external_const(_tmp_element2);
732 }
733
745 // not noexcept because can throw
746 [[nodiscard]] const_element_reference
748 throw_if_bad_degree(x);
749 return sift_no_checks(x);
750 }
751
766 // At present JDM thinks this will always return false if finished()
767 // isn't true, because we either run to the end or haven't done anything at
768 // all.
769 // not noexcept because sift_no_checks isn't
770 [[nodiscard]] bool currently_contains(const_element_reference x) const;
771
786 [[nodiscard]] bool contains(const_element_reference x);
787
796 [[nodiscard]] const_element_reference one() const
797 noexcept(noexcept(this->to_external_const(_one))) {
798 return this->to_external_const(_one);
799 }
800
814 [[nodiscard]] bool finished() const noexcept {
815 return _finished;
816 }
817
830 // TODO rename to add_basepoint?
831 // not noexcept because can throw
833
850 // Not noexcept because std::array::operator[] isn't
851 [[nodiscard]] point_type base_no_checks(index_type index) const {
852 return _base[index];
853 }
854
867 // not noexcept because can throw
868 [[nodiscard]] point_type base(index_type index) const {
869 throw_if_bad_depth(index);
870 return base_no_checks(index);
871 }
872
885 [[nodiscard]] size_t base_size() const noexcept {
886 return _base_size;
887 }
888
900 // not noexcept because it can call mem fns that aren't
901 void run();
902
903 private:
905 // SchreierSims - validation - private
907
908 bool is_valid_degree(point_type x) const noexcept {
909 return
910#ifdef LIBSEMIGROUPS_HPCOMBI_ENABLED
912#endif
913 x == N;
914 }
915
916 void throw_if_bad_degree(const_element_reference x,
917 std::string_view arg_pos = "1st") const;
918
919 void throw_if_bad_depth(size_t depth,
920 std::string_view arg_pos = "1st") const;
921
922 void throw_if_point_gt_degree(point_type pt,
923 std::string_view arg_pos = "1st") const;
924
925 void throw_if_point_not_in_orbit(index_type depth,
926 point_type pt,
927 std::string_view depth_arg_pos = "1st",
928 std::string_view pt_arg_pos = "2nd") const;
929
931 // SchreierSims - member functions - private
933
934 bool internal_equal_to(internal_const_element_type x,
935 internal_const_element_type y) const
936 noexcept(noexcept(
937 EqualTo()(this->to_external_const(x),
938 this->to_external_const(
939 y)) && noexcept(this->to_external_const(x)))) {
940 return EqualTo()(this->to_external_const(x), this->to_external_const(y));
941 }
942
943 // Used by copy constructor and assignment operator.
944 void init_strong_gens_traversal_inversal(SchreierSims const& that);
945 void free_strong_gens_traversal_inversal();
946
947 void internal_add_base_point(point_type pt);
948 void orbit_enumerate(index_type depth, index_type first = 0);
949 void orbit_add_gen(index_type depth, internal_element_type gen);
950 void orbit_add_point(index_type depth,
951 internal_element_type x,
952 point_type pt);
953 // Changes _tmp_element2 in-place, and returns the depth reached in the
954 // sifting.
955 index_type internal_sift(internal_reference x) const;
956
957 typename domain_type::const_iterator
958 first_non_fixed_point(internal_const_element_type x) const {
959 auto const& y = this->to_external_const(x);
960 return std::find_if(_domain.cbegin(), _domain.cend(), [&y](auto pt) {
961 return pt != Action()(pt, y);
962 });
963 }
964 };
965
970 namespace schreier_sims {
971
986 // TODO(later) example
987 // TODO (from RC):
988 // 1. Implement orbit refinement heuristic for intersection.
989 // 2. Make the Screier-Sims object during runtime, since we compute the
990 // stabilizers of the intersection already.
991 // 3. Refactor for more generality (i.e. so the template parameters N don't
992 // all have to be the same.
993 //
994 // TODO (from JDM):
995 // * use the no_checks mem fns of SchreierSims now that they exist
996 template <size_t N, typename Point, typename Element, typename Traits>
1000 } // namespace schreier_sims
1001
1015 template <size_t N, typename Point, typename Element, typename Traits>
1016 [[nodiscard]] std::string
1018 size_t max_width = 72);
1019} // namespace libsemigroups
1020
1021#include "schreier-sims.tpp"
1022
1023#endif // LIBSEMIGROUPS_SCHREIER_SIMS_HPP_
A deterministic version of the Schreier-Sims algorithm acting on a small number of points.
Definition schreier-sims.hpp:176
SchreierSims(SchreierSims &&)
Default move constructor.
const_element_reference strong_generator_no_checks(index_type depth, index_type index) const
Get a strong generator.
Definition schreier-sims.hpp:496
bool orbit_lookup(index_type depth, point_type pt) const
Check if a point is in the orbit of a basepoint.
Definition schreier-sims.hpp:637
bool currently_contains(const_element_reference x) const
Test membership of an element without running.
void run()
Run the Schreier-Sims algorithm.
const_element_reference generator(index_type index) const
Get a generator.
Definition schreier-sims.hpp:373
const_element_reference sift(const_element_reference x) const
Sift an element through the stabiliser chain.
Definition schreier-sims.hpp:747
const_element_reference transversal_element_no_checks(index_type depth, point_type pt) const
Get a transversal element.
Definition schreier-sims.hpp:522
typename Traits::EqualTo EqualTo
Adapter for testing equality.
Definition schreier-sims.hpp:240
void sift_inplace(element_reference x) const
Sift an element through the stabiliser chain in-place.
Definition schreier-sims.hpp:710
size_t base_size() const noexcept
Get the size of the current base.
Definition schreier-sims.hpp:885
size_t number_of_strong_generators_no_checks(index_type depth) const
The number of strong generators at a given depth.
Definition schreier-sims.hpp:451
size_t number_of_strong_generators(index_type depth) const
The number of strong generators at a given depth.
Definition schreier-sims.hpp:426
typename detail::BruidhinnTraits< Element >::reference element_reference
Type of a reference to the elements.
Definition schreier-sims.hpp:213
bool finished() const noexcept
Check if the stabiliser chain is fully enumerated.
Definition schreier-sims.hpp:814
typename Traits::One One
Adapter for the identity element of the given type.
Definition schreier-sims.hpp:246
point_type base(index_type index) const
Get a base point.
Definition schreier-sims.hpp:868
const_element_reference generator_no_checks(index_type index) const
Get a generator.
Definition schreier-sims.hpp:393
typename Traits::Degree Degree
Adapter for the degree of an element.
Definition schreier-sims.hpp:237
typename detail::BruidhinnTraits< Element >::value_type element_type
Type of the elements.
Definition schreier-sims.hpp:201
void sift_inplace_no_checks(element_reference x) const
Sift an element through the stabiliser chain in-place.
Definition schreier-sims.hpp:694
typename Traits::index_type index_type
Type of indices.
Definition schreier-sims.hpp:229
uint64_t size()
Returns the size of the group represented by this.
typename Traits::Inverse Inverse
Adapter for the inverse of an element.
Definition schreier-sims.hpp:243
bool empty() const
Check if any generators have been added so far.
Definition schreier-sims.hpp:656
const_element_reference inverse_transversal_element_no_checks(index_type depth, point_type pt) const
Get an inverse of a transversal element.
Definition schreier-sims.hpp:569
typename Traits::Action Action
Alias for Traits::Action.
Definition schreier-sims.hpp:234
const_element_reference transversal_element(index_type depth, point_type pt) const
Get a transversal element.
const_element_reference sift_no_checks(const_element_reference x) const
Sift an element through the stabiliser chain.
Definition schreier-sims.hpp:727
Point point_type
Type of the points acted on.
Definition schreier-sims.hpp:219
SchreierSims()
Default constructor.
bool add_generator(const_element_reference x)
Add a generator.
const_element_reference one() const noexcept(noexcept(this->to_external_const(_one)))
Returns a const reference to the identity.
Definition schreier-sims.hpp:796
typename Traits::domain_type domain_type
Type of the object containing all points acted on.
Definition schreier-sims.hpp:224
bool add_generator_no_checks(const_element_reference x)
Add a generator.
point_type base_no_checks(index_type index) const
Get a base point.
Definition schreier-sims.hpp:851
typename Traits::Swap Swap
Adapter for swapping.
Definition schreier-sims.hpp:252
size_t number_of_generators() const
The number of generators.
bool orbit_lookup_no_checks(index_type depth, point_type pt) const
Check if a point is in the orbit of a basepoint.
Definition schreier-sims.hpp:616
typename Traits::Product Product
Adapter for the product of two elements.
Definition schreier-sims.hpp:249
bool contains(const_element_reference x)
Test membership of an element.
uint64_t current_size() const
Returns the size of the group represented by this, without running.
SchreierSims & init()
Reset to the trivial group.
typename detail::BruidhinnTraits< Element >::const_reference const_element_reference
Type of a const reference to the elements.
Definition schreier-sims.hpp:207
SchreierSims & operator=(SchreierSims const &that)
Default copy assignment.
const_element_reference strong_generator(index_type depth, index_type index) const
Get a strong generator.
void add_base_point(point_type pt)
Add a base point to the stabiliser chain.
SchreierSims(SchreierSims const &that)
Default copy constructor.
const_element_reference inverse_transversal_element(index_type depth, point_type pt) const
Get an inverse of a transversal element.
SchreierSims & operator=(SchreierSims &&)
Default move assignment.
T find_if(T... args)
std::string to_human_readable_repr(AhoCorasick const &ac)
Return a string representation.
typename detail::LeastPermHelper< N >::type LeastPerm
Type of perms using the least memory for a given degree.
Definition transf.hpp:2408
Namespace for SchreierSims helper functions.
Definition schreier-sims.hpp:970
void intersection(SchreierSims< N, Point, Element, Traits > &T, SchreierSims< N, Point, Element, Traits > &S1, SchreierSims< N, Point, Element, Traits > &S2)
Find the intersection of two permutation groups.
Namespace for everything in the libsemigroups library.
Definition action.hpp:44
Adapter for the degree of an element.
Definition adapters.hpp:159
Adapter for testing equality.
Definition adapters.hpp:413
Adapter for the value of a right action.
Definition adapters.hpp:392
Adapter for the inverse of an element.
Definition adapters.hpp:319
Adapter for the identity element of the given type.
Definition adapters.hpp:246
Adapter for the product of two elements.
Definition adapters.hpp:284
Traits class for use with the class template SchreierSims.
Definition schreier-sims.hpp:99
libsemigroups::Swap< element_type > Swap
Adapter for swapping.
Definition schreier-sims.hpp:140
detail::IntRange< Point > domain_type
Type of the object containing all points acted on.
Definition schreier-sims.hpp:108
libsemigroups::One< element_type > One
Adapter for the identity element of the given type.
Definition schreier-sims.hpp:134
libsemigroups::ImageRightAction< element_type, Point > Action
Adapter for the value of a right action.
Definition schreier-sims.hpp:122
Element element_type
Type of the elements.
Definition schreier-sims.hpp:119
libsemigroups::Inverse< element_type > Inverse
Adapter for increasing the degree of an element.
Definition schreier-sims.hpp:131
size_t index_type
The type of indices to be used by a SchreierSims instance.
Definition schreier-sims.hpp:103
libsemigroups::EqualTo< element_type > EqualTo
Adapter for testing equality.
Definition schreier-sims.hpp:128
Point point_type
Type of the points acted on.
Definition schreier-sims.hpp:114
libsemigroups::Product< element_type > Product
Adapter for the product of two elements.
Definition schreier-sims.hpp:137
libsemigroups::Degree< element_type > Degree
Adapter for the degree of an element.
Definition schreier-sims.hpp:125
std::conditional_t< N >=0x100000000, uint64_t, std::conditional_t< N >=0x10000, uint32_t, std::conditional_t< N >=0x100, uint16_t, uint8_t > > > type
Definition types.hpp:89
Adapter for swapping.
Definition adapters.hpp:666