1 //
2 // libsemigroups - C++ library for semigroups and monoids
3 // Copyright (C) 2019 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 stuff for creating congruence over FroidurePin objects or
20 // over FpSemigroup objects.
21 
22 #ifndef LIBSEMIGROUPS_INCLUDE_CONG_HPP_
23 #define LIBSEMIGROUPS_INCLUDE_CONG_HPP_
24 
25 #include <cstddef>  // for size_t
26 #include <memory>   // for shared_ptr
27 
28 #include "cong-intf.hpp"     // for congruence::type
29 #include "knuth-bendix.hpp"  // for KnuthBendix
30 #include "race.hpp"          // for Race
31 #include "runner.hpp"        // for Runner
32 #include "todd-coxeter.hpp"  // for ToddCoxeter
33 #include "types.hpp"         // for word_type
34 
35 namespace libsemigroups {
36   class FpSemigroup;      // Forward declaration
37   class FroidurePinBase;  // Forward declaration, constructor parameters
38 
39   //! Defined in ``cong.hpp``.
40   //!
41   //! On this page we describe the functionality relating to the
42   //! Congruence class. This class can be used for computing a congruence
43   //! over a semigroup by running every applicable algorithm from
44   //! ``libsemigroups`` (and some variants of the same algorithm) in parallel.
45   //! This class is provided for convenience, at present it is not very
46   //! customisable, and lacks some of the fine grained control offered by the
47   //! classes implementing individual algorithms, such as
48   //! congruence::ToddCoxeter and congruence::KnuthBendix.
49   //!
50   //! \sa congruence_type and tril.
51   //! \par Example
52   //! \code
53   //! FpSemigroup S;
54   //! S.set_alphabet(3);
55   //! S.set_identity(0);
56   //! S.add_rule({1, 2}, {0});
57   //! S.is_obviously_infinite();  // false
58   //!
59   //! Congruence cong(twosided, S);
60   //! cong.add_pair({1, 1, 1}, {0});
61   //! cong.nr_classes(); // 3
62   //! \endcode
63   class Congruence final : public CongruenceInterface {
64    public:
65     //! This struct holds various enums which effect the coset enumeration
66     //! process used by ToddCoxeter::run.
67     //!
68     //! \sa policy::runners.
69     struct policy {
70       //! This enum allows setting the policy used when adding runners to an
71       //! instance of this type during construction.
72       enum class runners {
73         //! Adds a predetermined selection of runners.
74         standard,
75         //! Adds no runners.
76         none
77       };
78     };
79 
80     //////////////////////////////////////////////////////////////////////////
81     // Congruence - constructors - public
82     //////////////////////////////////////////////////////////////////////////
83 
84     //! Constructs an empty instance of an interface to a congruence of type
85     //! specified by the argument.
86     //!
87     //! \param type the type of the congruence.
88     //!
89     //! \par Complexity
90     //! Constant.
91     //!
92     //! \sa set_nr_generators and add_pair.
93     explicit Congruence(congruence_type type,
94                         policy::runners = policy::runners::standard);
95 
96     //! Constructs a Congruence over the FroidurePin instance \p S
97     //! representing a left/right/2-sided congruence according to \p type.
98     //!
99     //! \tparam T a class derived from FroidurePinBase.
100     //!
101     //! \param type whether the congruence is left, right, or 2-sided
102     //! \param S  a const reference to the semigroup over which the congruence
103     //! is defined.
104     //!
105     //! \par Exceptions
106     //! Does not throw itself but functions called by this function may
107     //! throw.
108     //!
109     //! \par Complexity
110     //! Linear in `S.size()`.
111     //!
112     //! \warning the parameter `T const& S` is copied, this might be expensive,
113     //! use a std::shared_ptr to avoid the copy!
114     template <typename T>
Congruence(congruence_type type,T const & S)115     Congruence(congruence_type type, T const& S)
116         : Congruence(type,
117                      static_cast<std::shared_ptr<FroidurePinBase>>(
118                          std::make_shared<T>(S))) {
119       static_assert(
120           std::is_base_of<FroidurePinBase, T>::value,
121           "the template parameter must be a derived class of FroidurePinBase");
122     }
123 
124     //! Constructs a Congruence over the FroidurePin instance \p S
125     //! representing a left/right/2-sided congruence according to \p type.
126     //! \param type whether the congruence is left, right, or 2-sided
127     //! \param S  a shared_ptr to the semigroup over which the congruence is
128     //! defined.
129     //!
130     //! \par Exceptions
131     //! Does not throw itself but functions called by this function may
132     //! throw.
133     //!
134     //! \par Complexity
135     //! Constant.
136     //!
137     //! \note
138     //! The FroidurePinBase pointed to by \p S is not copied.
139     Congruence(congruence_type type, std::shared_ptr<FroidurePinBase> S);
140 
141     //! Constructs a Congruence over the FpSemigroup instance \p S
142     //! representing a left/right/2-sided congruence according to \p type.
143     //! \param type whether the congruence is left, right, or 2-sided
144     //! \param S  a const reference to the finitely presented semigroup over
145     //! which the congruence is defined.
146     //!
147     //! \par Exceptions
148     //! Does not throw itself but functions called by this function may
149     //! throw.
150     //!
151     //! \par Complexity
152     //! Constant.
153     Congruence(congruence_type type, FpSemigroup& S);
154 
155     ~Congruence() = default;
156 
157     //! A Congruence instance is not default-constructible.
158     //! This constructor is deleted.
159     Congruence() = delete;
160 
161     //! A Congruence instance is not copyable.
162     //! This constructor is deleted.
163     Congruence(Congruence const&) = delete;
164 
165     //! A Congruence instance is not copy assignable.
166     //! This constructor is deleted.
167     Congruence& operator=(Congruence const&) = delete;
168 
169     //! A Congruence instance is not move copyable.
170     //! This constructor is deleted.
171     Congruence(Congruence&&) = delete;
172 
173     //! A Congruence instance is not move assignable.
174     //! This constructor is deleted.
175     Congruence& operator=(Congruence&&) = delete;
176 
177     //////////////////////////////////////////////////////////////////////////
178     // CongruenceInterface - non-pure virtual member functions - public
179     //////////////////////////////////////////////////////////////////////////
180 
181     bool contains(word_type const&, word_type const&) override;
182     tril const_contains(word_type const&, word_type const&) const override;
183 
184     //////////////////////////////////////////////////////////////////////////
185     // Congruence - member functions - public
186     //////////////////////////////////////////////////////////////////////////
187 
188     //! Returns the congruence::KnuthBendix instance used to compute the
189     //! congruence (if any).
190     //!
191     //! \par Parameters
192     //! (None)
193     //!
194     //! \returns A shared_ptr to a congruence::KnuthBendix or nullptr.
195     //!
196     //! \par Exceptions
197     //! Does not throw itself but functions called by this function may
198     //! throw.
199     //!
200     //! \par Complexity
201     //! Constant.
202     //!
203     //! \sa has_knuth_bendix().
knuth_bendix() const204     std::shared_ptr<congruence::KnuthBendix> knuth_bendix() const {
205       using KnuthBendix = congruence::KnuthBendix;
206       return _race.find_runner<KnuthBendix>();
207     }
208 
209     //! Checks if a congruence::KnuthBendix instance is being used to compute
210     //! the congruence.
211     //!
212     //! \par Parameters
213     //! (None)
214     //!
215     //! \returns A `bool`.
216     //!
217     //! \par Exceptions
218     //! Does not throw itself but functions called by this function may
219     //! throw.
220     //!
221     //! \par Complexity
222     //! Constant.
223     //!
224     //! \sa knuth_bendix().
has_knuth_bendix() const225     bool has_knuth_bendix() const {
226       return knuth_bendix() != nullptr;
227     }
228 
229     //! Returns the congruence::ToddCoxeter instance used to compute the
230     //! congruence (if any).
231     //!
232     //! \par Parameters
233     //! (None)
234     //!
235     //! \returns A shared_ptr to a congruence::ToddCoxeter or nullptr.
236     //!
237     //! \par Exceptions
238     //! Does not throw itself but functions called by this function may
239     //! throw.
240     //!
241     //! \par Complexity
242     //! Constant.
243     //!
244     //! \sa has_todd_coxeter.
todd_coxeter() const245     std::shared_ptr<congruence::ToddCoxeter> todd_coxeter() const {
246       using congruence::ToddCoxeter;
247       return _race.find_runner<ToddCoxeter>();
248     }
249 
250     //! Checks if a congruence::ToddCoxeter instance is being used to compute
251     //! the congruence.
252     //!
253     //! \par Parameters
254     //! (None)
255     //!
256     //! \returns A `bool`.
257     //!
258     //! \par Exceptions
259     //! Does not throw itself but functions called by this function may
260     //! throw.
261     //!
262     //! \par Complexity
263     //! Constant.
264     //!
265     //! \sa todd_coxeter.
has_todd_coxeter() const266     bool has_todd_coxeter() const {
267       return todd_coxeter() != nullptr;
268     }
269 
270     // The next function is required by the GAP package Semigroups.
271     //! No doc
272     template <typename T>
add_runner(T const & r)273     void add_runner(T const& r) {
274       static_assert(std::is_base_of<CongruenceInterface, T>::value,
275                     "the template parameter T must be a derived class of "
276                     "CongruenceInterface");
277       _race.add_runner(std::make_shared<T>(r));
278     }
279 
280    private:
281     //////////////////////////////////////////////////////////////////////////
282     // CongruenceInterface - pure virtual member functions - private
283     //////////////////////////////////////////////////////////////////////////
284 
285     word_type class_index_to_word_impl(class_index_type) override;
286     size_t    nr_classes_impl() override;
287     std::shared_ptr<FroidurePinBase> quotient_impl() override;
288     class_index_type word_to_class_index_impl(word_type const&) override;
289 
run_impl()290     void run_impl() override {
291       _race.run();
292     }
293 
finished_impl() const294     bool finished_impl() const override {
295       return _race.finished();
296     }
297 
298     //////////////////////////////////////////////////////////////////////////
299     // CongruenceInterface - non-pure virtual member functions - private
300     //////////////////////////////////////////////////////////////////////////
301 
302     void add_pair_impl(word_type const&, word_type const&) override;
303     std::shared_ptr<CongruenceInterface::non_trivial_classes_type const>
304          non_trivial_classes_impl() override;
305     bool is_quotient_obviously_finite_impl() override;
306     bool is_quotient_obviously_infinite_impl() override;
307     void set_nr_generators_impl(size_t) override;
308 
309     /////////////////////////////////////////////////////////////////////////
310     // Congruence - data - private
311     /////////////////////////////////////////////////////////////////////////
312     detail::Race _race;
313   };
314 }  // namespace libsemigroups
315 
316 #endif  // LIBSEMIGROUPS_INCLUDE_CONG_HPP_
317