libsemigroups  v3.0.0
C++ library for semigroups and monoids
Loading...
Searching...
No Matches
bmat-adapters.hpp
1//
2// libsemigroups - C++ library for semigroups and monoids
3// Copyright (C) 2020-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(1): almost all parameters and t-parameters are not documented in this
20// file.
21
22#ifndef LIBSEMIGROUPS_BMAT_ADAPTERS_HPP_
23#define LIBSEMIGROUPS_BMAT_ADAPTERS_HPP_
24
25#include <cstddef> // for size_t
26#include <iterator> // for distance
27#include <type_traits> // for enable_if_t
28#include <utility> // for move
29#include <vector> // for vector, vector<>::ref...
30
31#include "action.hpp" // for RightAction
32#include "adapters.hpp" // for ImageRightAction
33#include "bitset.hpp" // for BitSet, IsBitSet
34#include "debug.hpp" // for LIBSEMIGROUPS_ASSERT
35#include "exception.hpp" // for LIBSEMIGROUPS_EXCEPTION
36#include "matrix.hpp" // for BMat
37
38#include "libsemigroups/detail/containers.hpp" // for StaticVector1
39
40namespace libsemigroups {
52 // ImageRight/LeftAction - BMat
54
70 // T = StaticVector1<BitSet<N>, N> or std::vector<BitSet<N>>
71 // Possibly further container when value_type is BitSet.
72 template <typename Mat, typename Container>
73#ifndef LIBSEMIGROUPS_PARSED_BY_DOXYGEN
74 struct ImageRightAction<
75 Mat,
76 Container,
77 std::enable_if_t<IsBMat<Mat> && IsBitSet<typename Container::value_type>>>
78#else
79 struct ImageRightAction<Mat, Container>
80#endif
81 {
82 // TODO(now) Are pt and x the right way round in the doc?
87 // TODO(1) parameters not documented
88 // not noexcept because BitSet<N>::apply isn'Container
89 void operator()(Container& res, Container const& pt, Mat const& x) const {
90 using value_type = typename Container::value_type;
91 res.clear();
92
93 for (auto const& v : pt) {
94 value_type cup;
95 cup.reset();
96 v.apply([&x, &cup](size_t i) {
97 for (size_t j = 0; j < x.number_of_rows(); ++j) {
98 cup.set(j, cup[j] || x(i, j));
99 }
100 });
101 res.push_back(std::move(cup));
102 }
103 auto tmp = matrix::bitset_row_basis<Mat>(res);
104 std::swap(res, tmp);
105 }
106 };
107
120 // TODO(1) doc tparams
121 template <typename Mat, typename Container>
122#ifndef LIBSEMIGROUPS_PARSED_BY_DOXYGEN
123 struct ImageLeftAction<Mat, Container, std::enable_if_t<IsBMat<Mat>>>
124#else
125 struct ImageLeftAction<Mat, Container>
126#endif
127 {
132 // TODO(1) doc parameters
133 void operator()(Container& res, Container const& pt, Mat const& x) const {
134 const_cast<Mat*>(&x)->transpose();
135 try {
137 } catch (...) {
138 const_cast<Mat*>(&x)->transpose();
139 throw;
140 }
141 const_cast<Mat*>(&x)->transpose();
142 }
143 };
144
146 // Lambda/Rho - BMat
148
164 // This currently limits the use of Konieczny to matrices of dimension at
165 // most 64 with the default traits class, since we cannot know the
166 // dimension of the matrices at compile time, only at run time.
167 // TODO(1) doc tparams
168 template <typename Mat>
169#ifndef LIBSEMIGROUPS_PARSED_BY_DOXYGEN
170 struct LambdaValue<Mat, std::enable_if_t<IsBMat<Mat>>>
171#else
172 struct LambdaValue<Mat>
173#endif
174 {
175 static constexpr size_t N = BitSet<1>::max_size();
176
182 using type = detail::StaticVector1<BitSet<N>, N>;
183 };
184
198 // TODO(1) doc tparams
199 template <typename Mat>
200#ifndef LIBSEMIGROUPS_PARSED_BY_DOXYGEN
201 struct RhoValue<Mat, std::enable_if_t<IsBMat<Mat>>>
202#else
203 struct RhoValue<Mat>
204#endif
205 {
211 using type = typename LambdaValue<Mat>::type;
212 };
213
214 // Benchmarks show that the following is the fastest (i.e. duplicating the
215 // code from ImageRightAction, and using StaticVector1). T =
216 // StaticVector1<BitSet>, std::vector<BitSet>, StaticVector1<std::bitset>,
217 // std::vector<std::bitset>
218
229 // TODO(1) doc tparameters
230 template <typename Mat, typename Container>
231#ifndef LIBSEMIGROUPS_PARSED_BY_DOXYGEN
232 struct Lambda<Mat, Container, std::enable_if_t<IsBMat<Mat>>>
233#else
234 struct Lambda<Mat, Container>
235#endif
236 {
240 // TODO(1) doc parameters
241 void operator()(Container& res, Mat const& x) const {
242 using value_type = typename Container::value_type;
243 size_t const N = value_type().size();
244 if (x.number_of_rows() > N) {
246 "expected matrix of dimension at most {}, found {}",
247 N,
248 x.number_of_rows());
249 }
250 res.clear();
251 for (size_t i = 0; i < x.number_of_rows(); ++i) {
252 value_type cup;
253 cup.reset();
254 for (size_t j = 0; j < x.number_of_rows(); ++j) {
255 cup.set(j, x(i, j));
256 }
257 res.push_back(std::move(cup));
258 }
259 auto tmp = matrix::bitset_row_basis<Mat>(res);
260 std::swap(res, tmp);
261 }
262 };
263
264 // T = StaticVector1<BitSet>, std::vector<BitSet>,
265 // StaticVector1<std::bitset>, std::vector<std::bitset>
266
278 template <typename Mat, typename Container>
279#ifndef LIBSEMIGROUPS_PARSED_BY_DOXYGEN
280 struct Rho<Mat, Container, std::enable_if_t<IsBMat<Mat>>>
281#else
282 struct Rho<Mat, Container>
283#endif
284 {
289 void operator()(Container& res, Mat const& x) const noexcept {
290 const_cast<Mat*>(&x)->transpose();
291 Lambda<Mat, Container>()(res, x);
292 const_cast<Mat*>(&x)->transpose();
293 }
294 };
295
297 // Rank - BMat
299
313 template <size_t N, typename Mat>
314#ifndef LIBSEMIGROUPS_PARSED_BY_DOXYGEN
315 struct ImageRightAction<Mat, BitSet<N>, std::enable_if_t<IsBMat<Mat>>>
316#else
317 struct ImageRightAction<Mat, BitSet<N>>
318#endif
319 {
321 using result_type = BitSet<N>;
322
328 result_type const& pt,
329 Mat const& x) const {
330 static thread_local detail::StaticVector1<BitSet<N>, N> x_rows;
331 x_rows.clear();
332 for (size_t i = 0; i < x.number_of_rows(); ++i) {
333 BitSet<N> row(0);
334 for (size_t j = 0; j < x.number_of_rows(); ++j) {
335 if (x(i, j)) {
336 row.set(j, true);
337 }
338 }
339 x_rows.push_back(std::move(row));
340 }
341 res.reset();
342 pt.apply([&res](size_t i) { res |= x_rows[i]; });
343 }
344 };
345
357 template <typename Mat>
358#ifndef LIBSEMIGROUPS_PARSED_BY_DOXYGEN
359 class RankState<Mat, std::enable_if_t<IsBMat<Mat>>>
360#else
361 class RankState<Mat>
362#endif
363 {
364 public:
368 using MaxBitSet = BitSet<BitSet<1>::max_size()>;
369
372
374 RankState() = delete;
375
377 RankState(RankState const&) = default;
378
380 RankState(RankState&&) = delete;
381
383 RankState& operator=(RankState const&) = delete;
384
387
399 template <typename T>
400 RankState(T first, T last) {
401 static thread_local std::vector<MaxBitSet> seeds;
402 LIBSEMIGROUPS_ASSERT(_orb.empty());
403 if (std::distance(first, last) == 0) {
405 "expected a positive number of generators in the second argument");
406 }
407 for (auto it = first; it < last; ++it) {
408 _orb.add_generator(*it);
409 }
410 for (size_t i = 0; i < first->number_of_rows(); ++i) {
411 MaxBitSet seed(0);
412 seed.set(i, true);
413 _orb.add_seed(seed);
414 }
415 }
416
420 type const& get() const {
421 _orb.run();
422 LIBSEMIGROUPS_ASSERT(_orb.finished());
423 return _orb;
424 }
425
426 private:
427 mutable type _orb;
428 };
429
439 template <typename Mat>
440#ifndef LIBSEMIGROUPS_PARSED_BY_DOXYGEN
441 struct Rank<Mat, RankState<Mat>, std::enable_if_t<IsBMat<Mat>>>
442#else
443 struct Rank<Mat, RankState<Mat>>
444#endif
445 {
453 size_t operator()(RankState<Mat> const& state, Mat const& x) const {
454 using bitset_type = BitSet<BitSet<1>::max_size()>;
455 using orb_type = typename RankState<Mat>::type;
456 static thread_local std::vector<bool> seen;
457 static thread_local std::vector<bitset_type> x_rows;
458 seen.clear();
459 x_rows.clear();
460 orb_type const& orb = state.get();
461 LIBSEMIGROUPS_ASSERT(orb.finished());
462 seen.resize(orb.current_size());
463 for (size_t i = 0; i < x.number_of_rows(); ++i) {
464 bitset_type row(0);
465 for (size_t j = 0; j < x.number_of_rows(); ++j) {
466 if (x(i, j)) {
467 row.set(j, true);
468 }
469 }
470 x_rows.push_back(std::move(row));
471 }
472 size_t rnk = 0;
473 for (size_t i = 0; i < orb.current_size(); ++i) {
474 bitset_type const& row = orb[i];
475 bitset_type cup;
476 cup.reset();
477 row.apply([&cup](size_t j) { cup |= x_rows[j]; });
478 size_t pos = orb.position(cup);
479 LIBSEMIGROUPS_ASSERT(pos != UNDEFINED);
480 if (!seen[pos]) {
481 rnk++;
482 seen[pos] = true;
483 }
484 }
485 return rnk;
486 }
487 };
488
489} // namespace libsemigroups
490#endif // LIBSEMIGROUPS_BMAT_ADAPTERS_HPP_
RankState & operator=(RankState const &)=delete
Deleted.
RankState(RankState const &)=default
Deleted.
RankState & operator=(RankState &&)=delete
Deleted.
BitSet< BitSet< 1 >::max_size()> MaxBitSet
The maximum size of a bit set.
Definition bmat-adapters.hpp:368
RightAction< Mat, MaxBitSet, ImageRightAction< Mat, MaxBitSet > > type
Type of the RankState
Definition bmat-adapters.hpp:371
type const & get() const
Returns the row orbit.
Definition bmat-adapters.hpp:420
RankState(RankState &&)=delete
Deleted.
RankState(T first, T last)
Construct a RankState instance using iterators.
Definition bmat-adapters.hpp:400
Base class for states for ranks.
Definition adapters.hpp:877
void type
Definition adapters.hpp:881
void run()
Run until finished.
T clear(T... args)
T distance(T... args)
Action< Element, Point, Func, Traits, side::right > RightAction
Definition action.hpp:870
Undefined const UNDEFINED
Value for something undefined.
#define LIBSEMIGROUPS_EXCEPTION(...)
Throw a LibsemigroupsException.
Definition exception.hpp:95
T move(T... args)
void bitset_row_basis(Container &&rows, std::decay_t< Container > &result)
Appends a basis for the space spanned by some bitsets to a container.
Definition matrix.hpp:7452
Namespace for everything in the libsemigroups library.
Definition action.hpp:44
T push_back(T... args)
T resize(T... args)
void operator()(Container &res, Container const &pt, Mat const &x) const
Store the image of pt under the left action of x.
Definition bmat-adapters.hpp:133
Adapter for the value of a left action.
Definition adapters.hpp:350
BitSet< N > result_type
The type of result.
Definition bmat-adapters.hpp:321
void operator()(result_type &res, result_type const &pt, Mat const &x) const
Store the image of pt under the right action of x.
Definition bmat-adapters.hpp:327
void operator()(Container &res, Container const &pt, Mat const &x) const
Store the image of pt under the right action of x.
Definition bmat-adapters.hpp:89
Adapter for the value of a right action.
Definition adapters.hpp:392
void operator()(Container &res, Mat const &x) const
Modifies res in-place to contain the row space basis of x.
Definition bmat-adapters.hpp:241
Adapter for the action on LambdaValue's.
Definition adapters.hpp:833
detail::StaticVector1< BitSet< N >, N > type
The type of Lambda Values.
Definition bmat-adapters.hpp:182
Adapter for lambda functions.
Definition adapters.hpp:793
size_t operator()(RankState< Mat > const &state, Mat const &x) const
Returns the rank of x.
Definition bmat-adapters.hpp:453
Adapter for calculating ranks.
Definition adapters.hpp:930
void operator()(Container &res, Mat const &x) const noexcept
Modifies res in-place to contain the column space basis of x.
Definition bmat-adapters.hpp:289
Adapter for the action on RhoValue's.
Definition adapters.hpp:854
typename LambdaValue< Mat >::type type
The type of Rho Values.
Definition bmat-adapters.hpp:211
Adapter for rho functions.
Definition adapters.hpp:812
T swap(T... args)