libsemigroups  v3.3.0
C++ library for semigroups and monoids
Loading...
Searching...
No Matches
transf.hpp
1//
2// libsemigroups - C++ library for semigroups and monoids
3// Copyright (C) 2021-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// This file contains the declaration of the partial transformation class and
20// its subclasses.
21
22// TODO(later)
23// * benchmarks
24// * add some tests for PTransf themselves
25// * allocator
26
27#ifndef LIBSEMIGROUPS_TRANSF_HPP_
28#define LIBSEMIGROUPS_TRANSF_HPP_
29
30#include <algorithm> // for sort, max_element, unique
31#include <array> // for array
32#include <cstddef> // for size_t
33#include <cstdint> // for uint64_t, uint32_t
34#include <initializer_list> // for initializer_list
35#include <iterator> // for distance
36#include <limits> // for numeric_limits
37#include <numeric> // for iota
38#include <tuple> // for tuple_size
39#include <type_traits> // for enable_if_t
40#include <unordered_map> // for unordered_map
41#include <unordered_set> // for unordered_set
42#include <utility> // for forward
43#include <vector> // for vector
44
45#include "config.hpp" // for LIBSEMIGROUPS_HPCOMBI_ENABLED
46
47#include "adapters.hpp" // for Hash etc
48#include "bitset.hpp" // for BitSet
49#include "constants.hpp" // for UNDEFINED, Undefined
50#include "debug.hpp" // for LIBSEMIGROUPS_ASSERT
51#include "exception.hpp" // for LIBSEMIGROUPS_EXCEPTION
52#include "hpcombi.hpp" // for HPCombi::Transf16
53#include "is-transf.hpp" // for throw_if_not_perm etc
54#include "is_specialization_of.hpp" // for is_specialization_of
55#include "types.hpp" // for SmallestInteger
56
57#include "detail/stl.hpp" // for is_array_v
58
59namespace libsemigroups {
69
70 namespace detail {
75 } // namespace detail
76
91 // TODO(1) example
92
100 template <typename T>
101 static constexpr bool IsDerivedFromPTransf
102 = std::is_base_of_v<detail::PTransfPolymorphicBase, T>;
103
104 namespace detail {
105
106 template <typename T>
107 struct IsStaticHelper : std::false_type {};
108
109 template <typename T>
110 struct IsDynamicHelper : std::false_type {};
111
112 } // namespace detail
113
127 template <typename Scalar, typename Container>
129 static_assert(std::is_integral_v<Scalar>,
130 "template parameter Scalar must be an integral type");
131 static_assert(std::is_unsigned_v<Scalar>,
132 "template parameter Scalar must be unsigned");
133
134 public:
138 using point_type = Scalar;
139
143 using container_type = Container;
144
145 // Required by python bindings
156 [[nodiscard]] static point_type undef() noexcept {
157 return static_cast<point_type>(UNDEFINED);
158 }
159
169 PTransfBase() = default;
170
171 // No constructor from size_t this is delegated to StaticPTransf and
172 // DynamicPTransf
173
194 explicit PTransfBase(Container const& cont) : _container(cont) {}
195
197 explicit PTransfBase(Container&& cont) : _container(std::move(cont)) {}
198
219 template <typename Iterator>
220 explicit PTransfBase(Iterator first, Iterator last) : PTransfBase() {
221 using OtherScalar = typename std::iterator_traits<Iterator>::value_type;
222 // The below assertions exist to insure that we are not badly assigning
223 // values. The subsequent pragmas exist to suppress the false-positive
224 // warnings produced by g++ 13.2.0
225 static_assert(
226 std::is_same_v<OtherScalar, Undefined>
227 || std::is_convertible_v<OtherScalar, point_type>,
228 "the template parameter Iterator must have "
229 "value_type \"Undefined\" or convertible to \"point_type\"!");
230 static_assert(std::is_same_v<std::decay_t<decltype(*_container.begin())>,
231 point_type>);
232 resize(_container, std::distance(first, last));
233#pragma GCC diagnostic push
234#if defined(__GNUC__) && !defined(__clang__)
235#pragma GCC diagnostic ignored "-Wstringop-overflow"
236#endif
237 std::copy(first, last, _container.begin());
238#pragma GCC diagnostic pop
239 }
240
244
266 template <typename Subclass, typename OtherContainer = Container>
267 [[nodiscard]] static Subclass make(OtherContainer&& cont);
268
289 template <typename Subclass, typename OtherScalar>
290 [[nodiscard]] static Subclass make(std::initializer_list<OtherScalar> cont);
291
295 PTransfBase(PTransfBase const&) = default;
296
301
306
311
327 [[nodiscard]] bool operator<(PTransfBase const& that) const {
328 return _container < that._container;
329 }
330
346 [[nodiscard]] bool operator>(PTransfBase const& that) const {
347 return that < *this;
348 }
349
365 [[nodiscard]] bool operator==(PTransfBase const& that) const {
366 return _container == that._container;
367 }
368
384 [[nodiscard]] bool operator<=(PTransfBase const& that) const {
385 return _container < that._container || _container == that._container;
386 }
387
403 [[nodiscard]] bool operator>=(PTransfBase const& that) const {
404 return that <= *this;
405 }
406
422 [[nodiscard]] bool operator!=(PTransfBase const& that) const {
423 return !(*this == that);
424 }
425
440 [[nodiscard]] point_type& operator[](size_t i) {
441 return _container[i];
442 }
443
458 [[nodiscard]] point_type const& operator[](size_t i) const {
459 return _container[i];
460 }
461
475 // TODO(1) better exception message for python bindings
476 [[nodiscard]] point_type& at(size_t i) {
477 return _container.at(i);
478 }
479
493 // TODO(1) better exception message for python bindings
494 [[nodiscard]] point_type const& at(size_t i) const {
495 return _container.at(i);
496 }
497
518 // TODO(later) other operators such as power
519 // TODO to tpp
520 template <typename Subclass>
521 [[nodiscard]] Subclass operator*(Subclass const& that) const {
522 static_assert(IsDerivedFromPTransf<Subclass>,
523 "the template parameter Subclass must be derived from "
524 "PTransfPolymorphicBase");
525 Subclass xy(that.degree());
526 xy.product_inplace(*static_cast<Subclass const*>(this), that);
527 return xy;
528 }
529
533 using iterator = typename Container::iterator;
534
538 using const_iterator = typename Container::const_iterator;
539
551 [[nodiscard]] const_iterator cbegin() const noexcept {
552 return _container.cbegin();
553 }
554
566 [[nodiscard]] const_iterator cend() const noexcept {
567 return _container.cend();
568 }
569
571 [[nodiscard]] const_iterator begin() const noexcept {
572 return _container.begin();
573 }
574
576 [[nodiscard]] const_iterator end() const noexcept {
577 return _container.end();
578 }
579
591 [[nodiscard]] iterator begin() noexcept {
592 return _container.begin();
593 }
594
606 [[nodiscard]] iterator end() noexcept {
607 return _container.end();
608 }
609
623 [[nodiscard]] size_t rank() const {
625 return (vals.find(UNDEFINED) == vals.end() ? vals.size()
626 : vals.size() - 1);
627 }
628
639 // not noexcept because Hash<T>::operator() isn't
640 [[nodiscard]] size_t hash_value() const {
641 return Hash<Container>()(_container);
642 }
643
650 void swap(PTransfBase& that) noexcept {
651 std::swap(_container, that._container);
652 }
653
665 [[nodiscard]] size_t degree() const noexcept {
666 return _container.size();
667 }
668
682 template <typename Subclass>
683 [[nodiscard]] static Subclass one(size_t N) {
684 static_assert(IsDerivedFromPTransf<Subclass>,
685 "the template parameter Subclass must be derived from "
686 "PTransfPolymorphicBase");
687 Subclass result(N);
688 std::iota(result.begin(), result.end(), 0);
689 return result;
690 }
691
692 protected:
693 static void resize(container_type& c, size_t N, point_type val = 0);
694 void resize(size_t N, point_type val = 0) {
695 resize(_container, N, val);
696 }
697
698 private:
699 Container _container;
700 };
701
703 // Helper variable templates
705
713 template <typename T>
714 static constexpr bool IsStatic = detail::IsStaticHelper<T>::value;
715
723 template <typename T>
724 static constexpr bool IsDynamic = detail::IsDynamicHelper<T>::value;
725
727 // DynamicPTransf
729
742 template <typename Scalar>
743 class DynamicPTransf : public PTransfBase<Scalar, std::vector<Scalar>> {
745
746 public:
752 using point_type = Scalar;
753
760
762 using base_type::begin;
763 using base_type::degree;
764 using base_type::end;
765
766 // No default constructor, because the degree would be 0, and so we can
767 // just use the PTransfBase default constructor for that. Note that there's
768 // a default constructor for StaticPTransf since there we do know the degree
769 // (at compile time) and we can fill it with UNDEFINED values.
770
783 explicit DynamicPTransf(size_t n) : base_type() {
784 resize(n, UNDEFINED);
785 }
786
802 resize(degree() + m);
803 std::iota(end() - m, end(), degree() - m);
804 return *this;
805 }
806
807 protected:
808 using base_type::resize;
809 };
810
812 // StaticPTransf
814
827 template <size_t N, typename Scalar>
828 class StaticPTransf : public PTransfBase<Scalar, std::array<Scalar, N>> {
830
831 public:
833 using point_type = Scalar;
834
839
841 using base_type::begin;
842 using base_type::end;
843
854 StaticPTransf() : base_type() {
856 }
857
868 explicit StaticPTransf(size_t n);
869
876 // do nothing can't increase the degree
877 LIBSEMIGROUPS_EXCEPTION("cannot increase the degree of a StaticPTransf!");
878 return *this;
879 }
880 };
881
883 // PTransf
885
903 template <
904 size_t N = 0,
905 typename Scalar
906 = std::conditional_t<N == 0, uint32_t, typename SmallestInteger<N>::type>>
907 using PTransf = std::
908 conditional_t<N == 0, DynamicPTransf<Scalar>, StaticPTransf<N, Scalar>>;
909
910 namespace detail {
911 template <typename T>
912 struct IsPTransfHelper : std::false_type {};
913
914 template <typename Scalar>
915 struct IsPTransfHelper<DynamicPTransf<Scalar>> : std::true_type {};
916
917 template <size_t N, typename Scalar>
918 struct IsPTransfHelper<StaticPTransf<N, Scalar>> : std::true_type {};
919
920 template <size_t N, typename Scalar>
921 struct IsStaticHelper<StaticPTransf<N, Scalar>> : std::true_type {};
922
923 template <typename Scalar>
924 struct IsDynamicHelper<DynamicPTransf<Scalar>> : std::true_type {};
925
926 } // namespace detail
927
938 template <typename T>
939 static constexpr bool IsPTransf = detail::IsPTransfHelper<T>::value;
940
958 template <typename Scalar, typename Container>
959 [[deprecated]] void
961
963 // Transf
965
992 template <
993 size_t N = 0,
994 typename Scalar
995 = std::conditional_t<N == 0, uint32_t, typename SmallestInteger<N>::type>>
996 class Transf : public PTransf<N, Scalar> {
997 using base_type = PTransf<N, Scalar>;
998
999 public:
1003 using point_type = Scalar;
1004
1008 using container_type = typename base_type::container_type;
1009
1010 using PTransf<N, Scalar>::PTransf;
1011 using base_type::degree;
1012
1032 void product_inplace(Transf const& f, Transf const& g);
1033
1047 [[nodiscard]] static Transf one(size_t M) {
1048 return base_type::template one<Transf>(M);
1049 }
1050 };
1051
1052 namespace detail {
1053 template <typename T>
1054 struct IsTransfHelper : std::false_type {};
1055
1056 template <size_t N, typename Scalar>
1057 struct IsTransfHelper<Transf<N, Scalar>> : std::true_type {};
1058
1059 template <size_t N, typename Scalar>
1060 struct IsStaticHelper<Transf<N, Scalar>>
1061 : IsStaticHelper<PTransf<N, Scalar>> {};
1062
1063 template <size_t N, typename Scalar>
1064 struct IsDynamicHelper<Transf<N, Scalar>>
1065 : IsDynamicHelper<PTransf<N, Scalar>> {};
1066 } // namespace detail
1067
1069 // Transf helpers
1071
1079 template <typename T>
1080 static constexpr bool IsTransf = detail::IsTransfHelper<T>::value;
1081
1083 // Transf throw_if_image_value_out_of_range
1085
1101 template <size_t N, typename Scalar>
1102 [[deprecated]] void
1104
1106 // make<Transf>
1108
1119
1142 template <typename Return, typename OtherContainer>
1143 [[nodiscard]] std::enable_if_t<IsTransf<Return>, Return>
1144 make(OtherContainer&& cont) {
1145 return Return::template make<Return>(std::forward<OtherContainer>(cont));
1146 }
1147
1171 template <typename Return, typename OtherScalar>
1172 [[nodiscard]] std::enable_if_t<IsTransf<Return>, Return>
1176
1178 // PPerm
1180
1208 template <
1209 size_t N = 0,
1210 typename Scalar
1211 = std::conditional_t<N == 0, uint32_t, typename SmallestInteger<N>::type>>
1212 class PPerm : public PTransf<N, Scalar> {
1213 using base_type = PTransf<N, Scalar>;
1214
1215 public:
1219 using point_type = Scalar;
1220
1224 using container_type = typename base_type::container_type;
1225
1226 using PTransf<N, point_type>::PTransf;
1227 using base_type::degree;
1228 using base_type::undef;
1229
1249 //
1250 // Note: we use vectors here not container_type (which might be array),
1251 // because the length of dom and img might not equal degree().
1252 // Also we don't use a universal reference because we can't actually use an
1253 // rvalue reference here (we don't store dom or img).
1254 template <typename OtherScalar>
1256 std::vector<OtherScalar> const& img,
1257 size_t M);
1258
1263 size_t M)
1264 : PPerm(std::vector<point_type>(dom), std::vector<point_type>(img), M) {
1265 }
1266
1283 void product_inplace(PPerm const& f, PPerm const& g);
1284
1286 [[nodiscard]] static PPerm one(size_t M) {
1287 return base_type::template one<PPerm>(M);
1288 }
1289 };
1290
1291 namespace detail {
1292
1294 // PPerm helpers
1296
1297 template <typename T>
1298 struct IsPPermHelper : std::false_type {};
1299
1300 template <size_t N, typename Scalar>
1301 struct IsPPermHelper<PPerm<N, Scalar>> : std::true_type {};
1302
1303 template <size_t N, typename Scalar>
1304 struct IsStaticHelper<PPerm<N, Scalar>>
1305 : IsStaticHelper<PTransf<N, Scalar>> {};
1306
1307 template <size_t N, typename Scalar>
1308 struct IsDynamicHelper<PPerm<N, Scalar>>
1309 : IsDynamicHelper<PTransf<N, Scalar>> {};
1310 } // namespace detail
1311
1319 template <typename T>
1320 static constexpr bool IsPPerm = detail::IsPPermHelper<T>::value;
1321
1323 // PPerm check
1325
1342 template <size_t N, typename Scalar>
1343 [[deprecated]] void throw_if_not_pperm(PPerm<N, Scalar> const& f) {
1345 detail::throw_if_duplicates(f.begin(), f.end(), "image");
1346 }
1347
1349 // make<PPerm>
1351
1362
1386 template <typename Return, typename OtherContainer>
1387 [[nodiscard]] std::enable_if_t<IsPPerm<Return>, Return>
1388 make(OtherContainer&& cont) {
1389 return Return::template make<Return>(std::forward<OtherContainer>(cont));
1390 }
1391
1413 template <typename Return>
1414 [[nodiscard]] std::enable_if_t<IsPPerm<Return>, Return>
1419
1443 template <typename Return>
1444 [[nodiscard]] std::enable_if_t<IsPPerm<Return>, Return>
1447 size_t M);
1448
1472 template <typename Return>
1473 [[nodiscard]] std::enable_if_t<IsPPerm<Return>, Return>
1481
1483 // Perm
1485
1512 template <
1513 size_t N = 0,
1514 typename Scalar
1515 = std::conditional_t<N == 0, uint32_t, typename SmallestInteger<N>::type>>
1516 class Perm : public Transf<N, Scalar> {
1517 using base_type = PTransf<N, Scalar>;
1518
1519 public:
1523 using point_type = Scalar;
1524
1529
1530 using Transf<N, Scalar>::Transf;
1531 using base_type::degree;
1532
1534 [[nodiscard]] static Perm one(size_t M) {
1535 return base_type::template one<Perm>(M);
1536 }
1537 };
1538
1540 // Perm helpers
1542
1543 namespace detail {
1544 template <typename T>
1545 struct IsPermHelper : std::false_type {};
1546
1547 template <size_t N, typename Scalar>
1548 struct IsPermHelper<Perm<N, Scalar>> : std::true_type {};
1549 } // namespace detail
1550
1558 template <typename T>
1559 static constexpr bool IsPerm = detail::IsPermHelper<T>::value;
1560
1562 // Perm throw_if_not_perm
1564
1581 template <size_t N, typename Scalar>
1582 [[deprecated]] void throw_if_not_perm(Perm<N, Scalar> const& f) {
1584 detail::throw_if_duplicates(f.begin(), f.end(), "image");
1585 }
1586
1588 // make<Perm>
1590
1601
1625 template <typename Return, typename OtherContainer>
1626 [[nodiscard]] std::enable_if_t<IsPerm<Return>, Return>
1627 make(OtherContainer&& cont) {
1628 return Return::template make<Return>(std::forward<OtherContainer>(cont));
1629 }
1630
1653 template <typename Return>
1654 [[nodiscard]] std::enable_if_t<IsPerm<Return>, Return>
1659
1661 // Helper functions
1663
1690 template <typename T, typename Scalar>
1691 void image(T const& f, std::vector<Scalar>& im);
1692
1714 template <typename T>
1716
1743 template <typename T, typename Scalar>
1744 void domain(T const& f, std::vector<Scalar>& dom);
1745
1767 template <typename T>
1769
1788 template <typename T>
1789 [[nodiscard]] auto one(T const& f)
1790 -> std::enable_if_t<IsDerivedFromPTransf<T>, T> {
1791 return T::one(f.degree());
1792 }
1793
1811 template <size_t N, typename Scalar>
1813 // TODO(1) void pass by reference version
1814
1832 template <size_t N, typename Scalar>
1834 // TODO(1) void pass by reference version
1835
1851 // Put the inverse of this into that
1852 template <size_t N, typename Scalar>
1854
1877 template <size_t N, typename Scalar>
1879 PPerm<N, Scalar> to(f.degree());
1880 inverse(f, to);
1881 return to;
1882 }
1883
1902 template <size_t N, typename Scalar>
1904
1925 template <size_t N, typename Scalar>
1926 [[nodiscard]] Perm<N, Scalar> inverse(Perm<N, Scalar> const& f);
1927
1929 // Adapters
1931
1932 template <typename T>
1933 struct Degree<T, std::enable_if_t<IsDerivedFromPTransf<T>>> {
1934 [[nodiscard]] constexpr size_t operator()(T const& x) const noexcept {
1935 return x.degree();
1936 }
1937 };
1938
1939 template <typename T>
1940 struct One<T, std::enable_if_t<IsDerivedFromPTransf<T>>> {
1941 [[nodiscard]] T operator()(T const& x) const {
1942 return (*this)(x.degree());
1943 }
1944
1945 [[nodiscard]] T operator()(size_t N) const {
1946 return T::one(N);
1947 }
1948 };
1949
1950 template <size_t N, typename Scalar>
1951 struct Inverse<Perm<N, Scalar>> {
1952 [[nodiscard]] Perm<N, Scalar> operator()(Perm<N, Scalar> const& x) {
1953 return inverse(x);
1954 }
1955 };
1956
1957 template <typename Subclass>
1958 struct Product<Subclass, std::enable_if_t<IsDerivedFromPTransf<Subclass>>> {
1959 void
1960 operator()(Subclass& xy, Subclass const& x, Subclass const& y, size_t = 0) {
1961 xy.product_inplace(x, y);
1962 }
1963 };
1964
1965 template <typename T>
1966 struct Hash<T, std::enable_if_t<IsDerivedFromPTransf<T>>> {
1967 [[nodiscard]] constexpr size_t operator()(T const& x) const {
1968 return x.hash_value();
1969 }
1970 };
1971
1972 template <typename T>
1973 struct Complexity<T, std::enable_if_t<IsDerivedFromPTransf<T>>> {
1974 [[nodiscard]] constexpr size_t operator()(T const& x) const noexcept {
1975 return x.degree();
1976 }
1977 };
1978
1983 template <typename T>
1984 struct IncreaseDegree<T, std::enable_if_t<IsDerivedFromPTransf<T>>> {
1986 inline void operator()(T& x, size_t n) const {
1987 x.increase_degree_by(n);
1988 }
1989 };
1990
1992 // ImageRight/LeftAction - Transf
1994
1995 // Equivalent to OnSets in GAP
1996 // Slowest
1997 // works for T = std::vector and T = StaticVector1
2002 template <size_t N, typename Scalar, typename T>
2003 struct ImageRightAction<Transf<N, Scalar>, T> {
2005 void operator()(T& res, T const& pt, Transf<N, Scalar> const& x) const;
2006 };
2007
2008 // Fastest, but limited to at most degree 64
2013 template <size_t N, typename Scalar, size_t M>
2014 struct ImageRightAction<Transf<N, Scalar>, BitSet<M>> {
2016 void operator()(BitSet<M>& res,
2017 BitSet<M> const& pt,
2018 Transf<N, Scalar> const& x) const {
2019 res.reset();
2020 // Apply the lambda to every set bit in pt
2021 pt.apply([&x, &res](size_t i) { res.set(x[i]); });
2022 }
2023 };
2024
2025 // OnKernelAntiAction
2026 // T = StaticVector1<S> or std::vector<S>
2031 template <size_t N, typename Scalar, typename T>
2032 struct ImageLeftAction<Transf<N, Scalar>, T> {
2034 void operator()(T& res, T const& pt, Transf<N, Scalar> const& x) const;
2035 };
2036
2038 // Lambda/Rho - Transformation
2040
2041 // This currently limits the use of Konieczny to transformation of degree at
2042 // most 64 with the default traits class, since we cannot know the degree at
2043 // compile time, only at run time.
2050 template <size_t N, typename Scalar>
2051 struct LambdaValue<Transf<N, Scalar>> {
2054 using type = BitSet<BitSet<1>::max_size()>;
2055 };
2056
2057 // Benchmarks indicate that using std::vector yields similar performance to
2058 // using StaticVector1's.
2062 template <size_t N, typename Scalar>
2063 struct RhoValue<Transf<N, Scalar>> {
2067 };
2068
2069 // T = std::vector or StaticVector1
2074 template <size_t N, typename Scalar, typename T>
2075 struct Lambda<Transf<N, Scalar>, T> {
2076 // not noexcept because std::vector::resize isn't (although
2077 // StaticVector1::resize is).
2080 void operator()(T& res, Transf<N, Scalar> const& x) const;
2081 };
2082
2087 template <size_t N, typename Scalar, size_t M>
2088 struct Lambda<Transf<N, Scalar>, BitSet<M>> {
2089 // not noexcept because it can throw
2092 void operator()(BitSet<M>& res, Transf<N, Scalar> const& x) const;
2093 };
2094
2095 // T = std::vector<S> or StaticVector1<S, N>
2100 template <size_t N, typename Scalar, typename T>
2101 struct Rho<Transf<N, Scalar>, T> {
2113 // not noexcept because std::vector::resize isn't (although
2114 // StaticVector1::resize is).
2115 void operator()(T& res, Transf<N, Scalar> const& x) const;
2116 };
2117
2121 template <size_t N, typename Scalar>
2122 struct Rank<Transf<N, Scalar>> {
2135 [[nodiscard]] size_t operator()(Transf<N, Scalar> const& x) const {
2136 return x.rank();
2137 }
2138 };
2139
2141 // ImageRight/LeftAction - PPerm
2143
2144 // Slowest
2149 template <size_t N, typename Scalar>
2150 struct ImageRightAction<PPerm<N, Scalar>, PPerm<N, Scalar>> {
2153 PPerm<N, Scalar> const& pt,
2154 PPerm<N, Scalar> const& x) const noexcept {
2155 LIBSEMIGROUPS_ASSERT(res.degree() == pt.degree());
2156 LIBSEMIGROUPS_ASSERT(res.degree() == x.degree());
2157 res.product_inplace(pt, x);
2158 res = right_one(res);
2159 }
2160 };
2161
2162 // Faster than the above, but slower than the below
2163 // works for T = std::vector and T = StaticVector1
2168 template <size_t N, typename Scalar, typename T>
2169 struct ImageRightAction<PPerm<N, Scalar>, T> {
2171 void operator()(T& res, T const& pt, PPerm<N, Scalar> const& x) const;
2172 };
2173
2174 // Fastest, but limited to at most degree 64
2179 template <size_t N, typename Scalar, size_t M>
2180 struct ImageRightAction<PPerm<N, Scalar>, BitSet<M>> {
2182 void operator()(BitSet<M>& res,
2183 BitSet<M> const& pt,
2184 PPerm<N, Scalar> const& x) const;
2185 };
2186
2187 // Slowest
2192 template <size_t N, typename Scalar>
2193 struct ImageLeftAction<PPerm<N, Scalar>, PPerm<N, Scalar>> {
2197 PPerm<N, Scalar> const& pt,
2198 PPerm<N, Scalar> const& x) const noexcept {
2199 res.product_inplace(x, pt);
2200 res = left_one(res);
2201 }
2202 };
2203
2204 // Fastest when used with BitSet<N>.
2205 // works for T = std::vector and T = BitSet<N>
2206 // Using BitSet<N> limits this to size 64. However, if we are trying to
2207 // compute a LeftAction object, then the max size of such is 2 ^ 64, which
2208 // is probably not achievable. So, for higher degrees, we will only be able
2209 // to compute relatively sparse LeftActions (i.e. not containing the
2210 // majority of the 2 ^ n possible subsets), in which case using vectors or
2211 // StaticVector1's might be not be appreciable slower anyway. All of this is
2212 // to say that it probably isn't worthwhile trying to make BitSet's work for
2213 // more than 64 bits.
2218 template <size_t N, typename Scalar, typename T>
2219 struct ImageLeftAction<PPerm<N, Scalar>, T> {
2220 void operator()(T& res, T const& pt, PPerm<N, Scalar> const& x) const {
2222 static PPerm<N, Scalar> xx(x.degree());
2223 inverse(x, xx); // invert x into xx
2224 ImageRightAction<PPerm<N, Scalar>, T>()(res, pt, xx);
2225 }
2226 };
2227
2229 // Lambda/Rho - PPerm
2231
2232 // This currently limits the use of Konieczny to partial perms of degree at
2233 // most 64 with the default traits class, since we cannot know the degree
2234 // at compile time, only at run time.
2240 template <size_t N, typename Scalar>
2241 struct LambdaValue<PPerm<N, Scalar>> {
2244 using type = BitSet<BitSet<1>::max_size()>;
2245 };
2246
2252 template <size_t N, typename Scalar>
2253 struct RhoValue<PPerm<N, Scalar>> {
2257 };
2258
2263 template <size_t N, typename Scalar, size_t M>
2264 struct Lambda<PPerm<N, Scalar>, BitSet<M>> {
2267 void operator()(BitSet<M>& res, PPerm<N, Scalar> const& x) const;
2268 };
2269
2274 template <size_t N, typename Scalar, size_t M>
2275 struct Rho<PPerm<N, Scalar>, BitSet<M>> {
2278 void operator()(BitSet<M>& res, PPerm<N, Scalar> const& x) const;
2279 };
2280
2284 template <size_t N, typename Scalar>
2285 struct Rank<PPerm<N, Scalar>> {
2289 [[nodiscard]] size_t operator()(PPerm<N, Scalar> const& x) const {
2290 return x.rank();
2291 }
2292 };
2293
2295 // Perm
2297
2302 // TODO(later) this could work for everything derived from PTransf
2303 template <size_t N, typename Scalar, typename T>
2304 struct ImageRightAction<Perm<N, Scalar>,
2305 T,
2306 std::enable_if_t<std::is_integral_v<T>>> {
2308 void operator()(T& res,
2309 T const& pt,
2310 Perm<N, Scalar> const& p) const noexcept {
2311 LIBSEMIGROUPS_ASSERT(pt < p.degree());
2312 res = p[pt];
2313 }
2314
2316 [[nodiscard]] T operator()(T pt, Perm<N, Scalar> const& x) {
2317 return x[pt];
2318 }
2319 };
2320
2322 // Helpers
2324
2325 namespace detail {
2326 template <size_t N>
2327 struct LeastTransfHelper {
2328#ifdef LIBSEMIGROUPS_HPCOMBI_ENABLED
2329 using type = std::conditional_t<N >= 17, Transf<N>, HPCombi::Transf16>;
2330#else
2331 using type = Transf<N>;
2332#endif
2333 };
2334
2335 template <size_t N>
2336 struct LeastPPermHelper {
2337#ifdef LIBSEMIGROUPS_HPCOMBI_ENABLED
2338 using type = std::conditional_t<N >= 17, PPerm<N>, HPCombi::PPerm16>;
2339#else
2340 using type = PPerm<N>;
2341#endif
2342 };
2343
2344 template <size_t N>
2345 struct LeastPermHelper {
2346#ifdef LIBSEMIGROUPS_HPCOMBI_ENABLED
2347 using type = std::conditional_t<N >= 17, Perm<N>, HPCombi::Perm16>;
2348#else
2349 using type = Perm<N>;
2350#endif
2351 };
2352 } // namespace detail
2353
2366 template <size_t N>
2367 using LeastTransf = typename detail::LeastTransfHelper<N>::type;
2368
2381 template <size_t N>
2382 using LeastPPerm = typename detail::LeastPPermHelper<N>::type;
2383
2396 template <size_t N>
2397 using LeastPerm = typename detail::LeastPermHelper<N>::type;
2398
2423 template <size_t N, typename Scalar>
2425 std::string_view prefix = "",
2426 std::string_view braces = "{}");
2427
2452 template <size_t N, typename Scalar>
2454 std::string_view prefix = "",
2455 std::string_view braces = "{}");
2456
2482 template <size_t N, typename Scalar>
2484 std::string_view prefix = "",
2485 std::string_view braces = "{}");
2486
2516 template <size_t N, typename Scalar>
2518 std::string_view prefix = "",
2519 std::string_view braces
2520 = "{}",
2521 size_t max_width = 72);
2522
2551 template <size_t N, typename Scalar>
2553 std::string_view prefix = "",
2554 std::string_view braces
2555 = "{}",
2556 size_t max_width = 72);
2557
2588 template <size_t N, typename Scalar>
2590 std::string_view prefix = "",
2591 std::string_view braces
2592 = "{}",
2593 size_t max_width = 72);
2594} // namespace libsemigroups
2595
2596#include "transf.tpp"
2597
2598#endif // LIBSEMIGROUPS_TRANSF_HPP_
Partial transformations with dynamic degree.
Definition transf.hpp:743
DynamicPTransf(size_t n)
Construct with given degree.
Definition transf.hpp:783
size_t degree() const noexcept
Returns the degree of a partial transformation.
Definition transf.hpp:665
const_iterator end() const noexcept
Returns a const_iterator (random access iterator) pointing one past the last image value.
Definition transf.hpp:576
DynamicPTransf & increase_degree_by(size_t m)
Increase the degree in-place.
Definition transf.hpp:801
Scalar point_type
Type of the image values.
Definition transf.hpp:752
std::vector< point_type > container_type
Type of the underlying container.
Definition transf.hpp:759
Partial permutations with static or dynamic degree.
Definition transf.hpp:1212
PPerm(std::initializer_list< point_type > dom, std::initializer_list< point_type > img, size_t M)
Construct from domain, range, and degree.
Definition transf.hpp:1261
PPerm(std::vector< OtherScalar > const &dom, std::vector< OtherScalar > const &img, size_t M)
Construct from domain, range, and degree.
Scalar point_type
Type of the image values.
Definition transf.hpp:1219
void product_inplace(PPerm const &f, PPerm const &g)
Multiply two partial perms and store the product in this.
static PPerm one(size_t M)
Returns the identity transformation on the given number of points.
Definition transf.hpp:1286
typename base_type::container_type container_type
Type of the underlying container.
Definition transf.hpp:1224
Base class for partial transformations.
Definition transf.hpp:128
typename Container::iterator iterator
Type of iterators pointing to image values.
Definition transf.hpp:533
bool operator==(PTransfBase const &that) const
Compare for equality.
Definition transf.hpp:365
Subclass operator*(Subclass const &that) const
Multiply by another partial transformation.
Definition transf.hpp:521
size_t rank() const
Returns the number of distinct image values.
Definition transf.hpp:623
typename Container::const_iterator const_iterator
Type of const iterators pointing to image values.
Definition transf.hpp:538
PTransfBase(PTransfBase const &)=default
Default copy constructor.
const_iterator begin() const noexcept
Definition transf.hpp:571
PTransfBase()=default
Default constructor.
bool operator>=(PTransfBase const &that) const
Compare for greater than or equal.
Definition transf.hpp:403
PTransfBase & operator=(PTransfBase const &)=default
Default copy assignment operator.
PTransfBase(std::initializer_list< Scalar > cont)
Construct from a container of images.
Definition transf.hpp:242
point_type const & at(size_t i) const
Get a const reference to the image of a point.
Definition transf.hpp:494
size_t degree() const noexcept
Returns the degree of a partial transformation.
Definition transf.hpp:665
const_iterator end() const noexcept
Definition transf.hpp:576
bool operator>(PTransfBase const &that) const
Compare for greater.
Definition transf.hpp:346
static Subclass make(OtherContainer &&cont)
Construct from universal reference container and check.
PTransfBase & operator=(PTransfBase &&)=default
Default move assignment operator.
PTransfBase(PTransfBase &&)=default
Default move constructor.
Scalar point_type
Type of the image values.
Definition transf.hpp:138
static Subclass make(std::initializer_list< OtherScalar > cont)
Construct from std::initializer_list and check.
iterator begin() noexcept
Returns an iterator (random access iterator) pointing at the first image value.
Definition transf.hpp:591
const_iterator cend() const noexcept
Returns a const_iterator (random access iterator) pointing one past the last image value.
Definition transf.hpp:566
Container container_type
Type of the underlying container.
Definition transf.hpp:143
const_iterator cbegin() const noexcept
Returns a const_iterator (random access iterator) pointing at the first image value.
Definition transf.hpp:551
point_type & at(size_t i)
Get a reference to the image of a point.
Definition transf.hpp:476
static Subclass one(size_t N)
Returns the identity transformation on the given number of points.
Definition transf.hpp:683
PTransfBase(Iterator first, Iterator last)
Construct from a range of images.
Definition transf.hpp:220
point_type & operator[](size_t i)
Get a reference to the image of a point.
Definition transf.hpp:440
static point_type undef() noexcept
Returns the value used to represent "undefined".
Definition transf.hpp:156
size_t hash_value() const
Returns a hash value.
Definition transf.hpp:640
bool operator<=(PTransfBase const &that) const
Compare for less than or equal.
Definition transf.hpp:384
bool operator<(PTransfBase const &that) const
Compare for less.
Definition transf.hpp:327
PTransfBase(Container const &cont)
Construct from a container of images.
Definition transf.hpp:194
point_type const & operator[](size_t i) const
Get a const reference to the image of a point.
Definition transf.hpp:458
void swap(PTransfBase &that) noexcept
Swap with another partial transformation.
Definition transf.hpp:650
PTransfBase(Container &&cont)
Construct from a container of images.
Definition transf.hpp:197
bool operator!=(PTransfBase const &that) const
Compare for inequality.
Definition transf.hpp:422
iterator end() noexcept
Returns an iterator (random access iterator) pointing one past the last image value.
Definition transf.hpp:606
Permutations with static or dynamic degree.
Definition transf.hpp:1516
static Perm one(size_t M)
Returns the identity transformation on the given number of points.
Definition transf.hpp:1534
Scalar point_type
Type of the image values.
Definition transf.hpp:1523
typename PTransf< N, point_type >::container_type container_type
Type of the underlying container.
Definition transf.hpp:1528
Partial transformations with static degree.
Definition transf.hpp:828
StaticPTransf & increase_degree_by(size_t)
Increase the degree in-place.
Definition transf.hpp:875
const_iterator begin() const noexcept
Returns a const_iterator (random access iterator) pointing at the first image value.
Definition transf.hpp:571
std::array< Scalar, N > container_type
Type of the underlying container.
Definition transf.hpp:838
const_iterator end() const noexcept
Returns a const_iterator (random access iterator) pointing one past the last image value.
Definition transf.hpp:576
StaticPTransf(size_t n)
Construct with given degree.
StaticPTransf()
Default constructor.
Definition transf.hpp:854
Scalar point_type
Type of the image values.
Definition transf.hpp:833
Transformations with static or dynamic degree.
Definition transf.hpp:996
static Transf one(size_t M)
Returns the identity transformation on the given number of points.
Definition transf.hpp:1047
Scalar point_type
Type of the image values.
Definition transf.hpp:1003
void product_inplace(Transf const &f, Transf const &g)
Multiply two transformations and store the product in this.
typename base_type::container_type container_type
Type of the underlying container.
Definition transf.hpp:1008
T copy(T... args)
T distance(T... args)
T fill(T... args)
T forward(T... args)
std::string to_human_readable_repr(Action< Element, Point, Func, Traits, LeftOrRight > const &action)
Return a human readable representation of an Action object.
Undefined const UNDEFINED
Value for something undefined.
#define LIBSEMIGROUPS_EXCEPTION(...)
Throw a LibsemigroupsException.
Definition exception.hpp:99
enable_if_is_same< Return, Blocks > make(Container const &cont)
Check the arguments, construct a Blocks object, and check it.
Definition bipart.hpp:856
typename detail::LeastPermHelper< N >::type LeastPerm
Type of perms using the least memory for a given degree.
Definition transf.hpp:2397
static constexpr bool IsPPerm
Helper variable template.
Definition transf.hpp:1320
auto one(T const &f) -> std::enable_if_t< IsDerivedFromPTransf< T >, T >
Returns the identity transformation of same degree as a sample.
Definition transf.hpp:1789
static constexpr bool IsTransf
Helper variable template.
Definition transf.hpp:1080
void throw_if_not_perm(Perm< N, Scalar > const &f)
Check a permutation.
Definition transf.hpp:1582
typename detail::LeastTransfHelper< N >::type LeastTransf
Type of transformations using the least memory for a given degree.
Definition transf.hpp:2367
PPerm< N, Scalar > left_one(PPerm< N, Scalar > const &f)
Returns the left one of a partial perm.
typename detail::LeastPPermHelper< N >::type LeastPPerm
Type of partial perms using the least memory for a given degree.
Definition transf.hpp:2382
void domain(T const &f, std::vector< Scalar > &dom)
Replace the contents of a vector by the set of points where a partial transformation is defined.
static constexpr bool IsPTransf
Helper variable template.
Definition transf.hpp:939
PPerm< N, Scalar > right_one(PPerm< N, Scalar > const &f)
Returns the right one of a partial perm.
static constexpr bool IsDynamic
Helper variable template.
Definition transf.hpp:724
static constexpr bool IsStatic
Helper variable template.
Definition transf.hpp:714
void throw_if_not_pperm(PPerm< N, Scalar > const &f)
Check a partial perm.
Definition transf.hpp:1343
void image(T const &f, std::vector< Scalar > &im)
Replace the contents of a vector by the set of images of a partial transformation.
void throw_if_image_value_out_of_range(PTransfBase< Scalar, Container > const &f)
Check a partial transformation.
std::string to_input_string(Transf< N, Scalar > const &x, std::string_view prefix="", std::string_view braces="{}")
Return a string that can be used to recreate a transformation.
static constexpr bool IsPerm
Helper variable template.
Definition transf.hpp:1559
static constexpr bool IsDerivedFromPTransf
Helper variable template.
Definition transf.hpp:102
std:: conditional_t< N==0, DynamicPTransf< Scalar >, StaticPTransf< N, Scalar > > PTransf
Partial transformations with static or dynamic degree.
Definition transf.hpp:907
void inverse(PPerm< N, Scalar > const &from, PPerm< N, Scalar > &to)
Replace contents of a partial perm with the inverse of another.
T iota(T... args)
T move(T... args)
Namespace for everything in the libsemigroups library.
Definition action.hpp:44
auto to(detail::KnuthBendixImpl< Rewriter, ReductionOrder > &kb) -> std::enable_if_t< std::is_same_v< Presentation< typename Result::word_type >, Result >, Result >
No doc.
Adapter for the complexity of multiplication.
Definition adapters.hpp:128
Adapter for the degree of an element.
Definition adapters.hpp:166
Adapter for hashing.
Definition adapters.hpp:453
size_t operator()(Value const &x) const
Hash x using std::hash.
Definition adapters.hpp:462
void operator()(PPerm< N, Scalar > &res, PPerm< N, Scalar > const &pt, PPerm< N, Scalar > const &x) const noexcept
Definition transf.hpp:2196
void operator()(T &res, T const &pt, PPerm< N, Scalar > const &x) const
Definition transf.hpp:2220
void operator()(T &res, T const &pt, Transf< N, Scalar > const &x) const
Stores the image of pt under the left action of x in res.
Adapter for the value of a left action.
Definition adapters.hpp:357
void operator()(BitSet< M > &res, BitSet< M > const &pt, PPerm< N, Scalar > const &x) const
Stores the image set of pt under x in res.
void operator()(PPerm< N, Scalar > &res, PPerm< N, Scalar > const &pt, PPerm< N, Scalar > const &x) const noexcept
Stores the idempotent in res.
Definition transf.hpp:2152
void operator()(T &res, T const &pt, PPerm< N, Scalar > const &x) const
Stores the image set of pt under x in res.
void operator()(T &res, T const &pt, Perm< N, Scalar > const &p) const noexcept
Stores the image of pt under the action of p in res.
Definition transf.hpp:2308
T operator()(T pt, Perm< N, Scalar > const &x)
Returns the image of pt under the action of p.
Definition transf.hpp:2316
void operator()(BitSet< M > &res, BitSet< M > const &pt, Transf< N, Scalar > const &x) const
Stores the image set of pt under x in res.
Definition transf.hpp:2016
void operator()(T &res, T const &pt, Transf< N, Scalar > const &x) const
Stores the image set of pt under x in res.
Adapter for the value of a right action.
Definition adapters.hpp:399
void operator()(T &x, size_t n) const
Returns x->increase_degree_by(n).
Definition transf.hpp:1986
Adapter for increasing the degree of an element.
Definition adapters.hpp:206
Adapter for the inverse of an element.
Definition adapters.hpp:326
void operator()(BitSet< M > &res, PPerm< N, Scalar > const &x) const
void operator()(BitSet< M > &res, Transf< N, Scalar > const &x) const
void operator()(T &res, Transf< N, Scalar > const &x) const
Adapter for the action on LambdaValue's.
Definition adapters.hpp:840
BitSet< BitSet< 1 >::max_size()> type
Definition transf.hpp:2244
BitSet< BitSet< 1 >::max_size()> type
Definition transf.hpp:2054
Adapter for lambda functions.
Definition adapters.hpp:800
Adapter for the identity element of the given type.
Definition adapters.hpp:253
Adapter for the product of two elements.
Definition adapters.hpp:291
size_t operator()(PPerm< N, Scalar > const &x) const
Definition transf.hpp:2289
size_t operator()(Transf< N, Scalar > const &x) const
Definition transf.hpp:2135
Adapter for calculating ranks.
Definition adapters.hpp:937
void operator()(BitSet< M > &res, PPerm< N, Scalar > const &x) const
void operator()(T &res, Transf< N, Scalar > const &x) const
Adapter for the action on RhoValue's.
Definition adapters.hpp:861
typename LambdaValue< PPerm< N, Scalar > >::type type
Definition transf.hpp:2256
std::vector< Scalar > type
Definition transf.hpp:2066
Adapter for rho functions.
Definition adapters.hpp:819
T swap(T... args)