libsemigroups
rws.h
1 //
2 // libsemigroups - C++ library for semigroups and monoids
3 // Copyright (C) 2017 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 #ifndef LIBSEMIGROUPS_SRC_RWS_H_
20 #define LIBSEMIGROUPS_SRC_RWS_H_
21 
22 #include <atomic>
23 #include <list>
24 #include <stack>
25 #include <string>
26 #include <utility>
27 #include <vector>
28 
29 #include "cong.h"
30 #include "semigroups.h"
31 
32 namespace libsemigroups {
34  typedef char rws_letter_t;
35 
37  typedef std::string rws_word_t;
38 
48  public:
56  std::function<bool(rws_word_t const*, rws_word_t const*)> func)
57  : _func(func) {}
58 
61  size_t operator()(rws_word_t const* p, rws_word_t const* q) const {
62  return _func(p, q);
63  }
64 
67  size_t operator()(rws_word_t const& p, rws_word_t const& q) const {
68  return _func(&p, &q);
69  }
70 
71  private:
72  std::function<bool(rws_word_t const*, rws_word_t const*)> _func;
73  };
74 
77  class SHORTLEX : public ReductionOrdering {
78  public:
82  : ReductionOrdering([](rws_word_t const* p, rws_word_t const* q) {
83  return (p->size() > q->size()
84  || (p->size() == q->size() && *p > *q));
85  }) {}
86 
92  explicit SHORTLEX(std::function<bool(rws_letter_t const&,
93  rws_letter_t const&)> letter_order)
94  : ReductionOrdering([this](rws_word_t const* p, rws_word_t const* q) {
95  // FIXME This is unsafe since we don't check that p and q consist of
96  // the correct letters
97  if (p->size() > q->size()) {
98  return true;
99  } else if (p->size() < q->size()) {
100  return false;
101  }
102  auto itp = p->cbegin();
103  auto itq = q->cbegin();
104  while (itp < p->cend() && *itp == *itq) {
105  itp++;
106  itq++;
107  }
108  return (itp != p->cend() && this->_letter_order(*itp, *itq));
109  }),
110  _letter_order(letter_order) {}
111 
112  private:
113  std::function<bool(rws_letter_t const&, rws_letter_t const&)> _letter_order;
114  };
115 
116  // TODO add more reduction orderings
117 
121 
122  class RWS {
123  public:
124  // Forward declaration of Rule
125  class Rule;
126 
132  explicit RWS(ReductionOrdering* order)
133  : _active_rules(),
134  _confluence_known(false),
135  _inactive_rules(),
136  _is_confluent(),
137  _order(order),
138  _report_next(0),
139  _report_interval(1000),
140  _stack(),
141  _total_rules(0) {
142  _next_rule_it1 = _active_rules.end(); // null
143  _next_rule_it2 = _active_rules.end(); // null
144 #ifdef LIBSEMIGROUPS_STATS
145  _max_stack_depth = 0;
146  _max_word_length = 0;
147  _max_active_word_length = 0;
148  _max_active_rules = 0;
149 #endif
150  }
151 
154  RWS() : RWS(new SHORTLEX()) {}
155 
158  explicit RWS(std::vector<relation_t> const& relations) : RWS() {
159  add_rules(relations);
160  }
161 
167  RWS(ReductionOrdering* order, std::vector<relation_t> const& relations)
168  : RWS(order) {
169  add_rules(relations);
170  }
171 
178  explicit RWS(Congruence& cong) : RWS() {
179  add_rules(cong);
180  }
181 
186  ~RWS();
187 
191  bool is_confluent() const {
192  std::atomic<bool> killed(false);
193  return is_confluent(killed);
194  }
195 
197  size_t nr_rules() const {
198  return _active_rules.size();
199  }
200 
203  void rewrite(rws_word_t* w) const;
204 
207  rws_word_t rewrite(rws_word_t w) const {
208  rewrite(&w);
209  return w;
210  }
211 
218  void knuth_bendix() {
219  std::atomic<bool> killed(false);
220  knuth_bendix(killed);
221  }
222 
230  void knuth_bendix(std::atomic<bool>& killed);
231 
234  void set_confluent(bool val) {
235  _is_confluent = val;
236  _confluence_known = true;
237  }
238 
251  void add_rule(rws_word_t* p, rws_word_t* q);
252 
260  void add_rule(rws_word_t const& p, rws_word_t const& q);
261 
266  void add_rules(std::vector<relation_t> const& relations) {
267  for (relation_t const& rel : relations) {
268  if (rel.first != rel.second) {
269  add_rule(word_to_rws_word(rel.first), word_to_rws_word(rel.second));
270  }
271  }
272  }
273 
276  void add_rules(Congruence& cong) {
277  add_rules(cong.relations());
278  add_rules(cong.extra());
279  }
280 
285  static rws_letter_t letter_to_rws_letter(letter_t const& a);
286 
289  static rws_word_t* letter_to_rws_word(letter_t const& a);
290 
295  static rws_word_t* word_to_rws_word(word_t const& w);
296 
301  static letter_t rws_letter_to_letter(rws_letter_t const& rws_letter);
302 
307  static word_t* rws_word_to_word(rws_word_t const* rws_word);
308 
313  void set_report(bool val) const {
314  glob_reporter.set_report(val);
315  }
316 
325  bool test_less_than(word_t const& p, word_t const& q);
326 
335  bool test_less_than(rws_word_t const& p, rws_word_t const& q);
336 
345  bool test_equals(word_t const& p, word_t const& q);
346 
354  bool test_equals(rws_word_t const& p, rws_word_t const& q);
355 
357  std::list<Rule const*>::const_iterator rules_cbegin() const {
358  return _active_rules.cbegin();
359  }
360 
362  std::list<Rule const*>::const_iterator rules_cend() const {
363  return _active_rules.cend();
364  }
365 
366  private:
367  // internal only, rewrites in-place and deletes p and q.
368  bool test(rws_word_t* p,
369  rws_word_t* q,
370  std::function<bool(rws_word_t* p, rws_word_t* q)> func) {
371  knuth_bendix();
372  rewrite(p);
373  rewrite(q);
374  bool out = func(q, p);
375  delete p;
376  delete q;
377  return out;
378  }
379 
380  void add_rule(Rule* rule);
381  std::list<Rule const*>::iterator
382  remove_rule(std::list<Rule const*>::iterator it);
383 
384  Rule* new_rule() const;
385  Rule* new_rule(rws_word_t const* lhs, rws_word_t const* rhs) const;
386  Rule* new_rule(Rule const* rule) const;
387  Rule* new_rule(rws_word_t::const_iterator begin_lhs,
388  rws_word_t::const_iterator end_lhs,
389  rws_word_t::const_iterator begin_rhs,
390  rws_word_t::const_iterator end_rhs) const;
391 
392  bool is_confluent(std::atomic<bool>& killed) const;
393  void clear_stack(std::atomic<bool>& killed);
394  void overlap(Rule const* u, Rule const* v, std::atomic<bool>& killed);
395 
396  std::list<Rule const*> _active_rules;
397  mutable bool _confluence_known;
398  mutable std::list<Rule*> _inactive_rules;
399  mutable bool _is_confluent;
400  std::list<Rule const*>::iterator _next_rule_it1;
401  std::list<Rule const*>::iterator _next_rule_it2;
402  ReductionOrdering const* _order;
403  size_t _report_next;
404  size_t _report_interval;
405  std::stack<Rule*> _stack;
406  mutable size_t _total_rules;
407 
408 #ifdef LIBSEMIGROUPS_STATS
409  size_t max_active_word_length();
410  size_t _max_stack_depth;
411  size_t _max_word_length;
412  size_t _max_active_word_length;
413  size_t _max_active_rules;
414  std::unordered_set<rws_word_t> _unique_lhs_rules;
415 #endif
416  };
417 
421  class RWS::Rule {
422  friend RWS;
423 
424  public:
428  rws_word_t const* lhs() const {
429  return const_cast<rws_word_t const*>(_lhs);
430  }
431 
435  rws_word_t const* rhs() const {
436  return const_cast<rws_word_t const*>(_rhs);
437  }
438 
439  private:
440  // The Rule class does not support an assignment contructor to avoid
441  // accidental copying.
442  Rule& operator=(Rule const& copy) = delete;
443 
444  // The Rule class does not support a copy contructor to avoid
445  // accidental copying.
446  Rule(Rule const& copy) = delete;
447 
448  // Construct from RWS, and pointers to libsemigroups::rws_word_t.
449  //
450  // A rule is guaranteed to have its left hand side greater than its right
451  // hand side according to the reduction ordering of \p rws. The Rule
452  // object constructed here takes ownership of \p p and \p q and deletes
453  // them in its destructor.
454  Rule(RWS const* rws, rws_word_t* p, rws_word_t* q)
455  : _rws(rws), _lhs(p), _rhs(q), _active(false) {
456  LIBSEMIGROUPS_ASSERT(*_lhs != *_rhs);
457  reorder();
458  }
459 
460  // Construct from RWS with new but empty rws_word_t's
461  explicit Rule(RWS const* rws)
462  : _rws(rws),
463  _lhs(new rws_word_t()),
464  _rhs(new rws_word_t()),
465  _active(false) {}
466 
467  // Destructor, deletes pointers used to create the rule.
468  ~Rule() {
469  delete _lhs;
470  delete _rhs;
471  }
472 
473  void rewrite() {
474  _rws->rewrite(_lhs);
475  _rws->rewrite(_rhs);
476  reorder();
477  }
478 
479  void rewrite_rhs() {
480  _rws->rewrite(_rhs);
481  }
482 
483  void clear() {
484  _lhs->clear();
485  _rhs->clear();
486  }
487 
488  inline bool is_active() const {
489  return _active;
490  }
491 
492  void deactivate() {
493  _active = false;
494  }
495 
496  void activate() {
497  _active = true;
498  }
499 
500  void reorder() {
501  if ((*(_rws->_order))(_rhs, _lhs)) {
502  std::swap(_lhs, _rhs);
503  }
504  }
505 
506  RWS const* _rws;
507  rws_word_t* _lhs;
508  rws_word_t* _rhs;
509  bool _active;
510  };
511 
512 } // namespace libsemigroups
513 #endif // LIBSEMIGROUPS_SRC_RWS_H_
RWS(Congruence &cong)
Constructs a rewriting system from Congruence::relations and Congruence::extra applied to cong...
Definition: rws.h:178
size_t operator()(rws_word_t const *p, rws_word_t const *q) const
Returns true if the word pointed to by p is greater than the word pointed to by q in the reduction or...
Definition: rws.h:61
This class implements the shortlex reduction ordering derived from an ordering on libsemigroups::rws_...
Definition: rws.h:77
rws_word_t const * lhs() const
Returns the left hand side of the rule, which is guaranteed to be greater than its right hand side ac...
Definition: rws.h:428
std::vector< letter_t > word_t
Type for a word over the generators of a semigroup.
Definition: semigroups.h:49
RWS(std::vector< relation_t > const &relations)
Constructs a rewriting system with rules derived from the parameter relations, and with the SHORTLEX ...
Definition: rws.h:158
std::vector< relation_t > const & relations()
Returns the vector of relations used to define the semigroup over which the congruence is defined...
Definition: cong.h:271
SHORTLEX(std::function< bool(rws_letter_t const &, rws_letter_t const &)> letter_order)
A constructor.
Definition: rws.h:92
char rws_letter_t
Type for letters for rewriting systems.
Definition: rws.h:34
size_t nr_rules() const
Returns the current number of active rules in the rewriting system.
Definition: rws.h:197
SHORTLEX()
Constructs a short-lex reduction ordering object derived from the order of on libsemigroups::rws_lett...
Definition: rws.h:81
std::vector< relation_t > const & extra() const
Returns the vector of extra relations (or equivalently, generating pairs) used to define the congruen...
Definition: cong.h:278
RWS()
Constructs a rewriting system with no rules, and the SHORTLEX reduction ordering. ...
Definition: rws.h:154
void knuth_bendix()
Run the Knuth-Bendix algorithm on the rewriting system.
Definition: rws.h:218
Class for congruence on a semigroup or fintely presented semigroup.
Definition: cong.h:54
void set_confluent(bool val)
If you somehow magically know that the rewriting system is confluent, or not, then you can set this u...
Definition: rws.h:234
rws_word_t const * rhs() const
Returns the right hand side of the rule, which is guaranteed to be less than its left hand side accor...
Definition: rws.h:435
RWS(ReductionOrdering *order)
Constructs rewriting system with no rules and the reduction ordering order.
Definition: rws.h:132
std::string rws_word_t
Type for words for rewriting systems.
Definition: rws.h:37
Namespace for everything in the libsemigroups library.
Definition: blocks.cc:32
Class for rules in rewriting systems, which supports only two methods, Rule::lhs and Rule::rhs...
Definition: rws.h:421
void set_report(bool val) const
Turn reporting on or off.
Definition: rws.h:313
size_t operator()(rws_word_t const &p, rws_word_t const &q) const
Returns true if the word p is greater than the word q in the reduction ordering.
Definition: rws.h:67
bool is_confluent() const
Returns true if the rewriting system is confluent and false if it is not.
Definition: rws.h:191
std::list< Rule const * >::const_iterator rules_cbegin() const
Returns an iterator pointing at the first Rule of this.
Definition: rws.h:357
RWS(ReductionOrdering *order, std::vector< relation_t > const &relations)
Constructs a rewriting system with rules derived from relations, and with the reduction ordering spec...
Definition: rws.h:167
This class is used to represent a string rewriting system defining a finitely presented monoid or sem...
Definition: rws.h:122
void add_rules(Congruence &cong)
Add rules derived from Congruence::relations and Congruence::extra applied to cong.
Definition: rws.h:276
size_t letter_t
Type for the index of a generator of a semigroup.
Definition: semigroups.h:46
std::pair< word_t, word_t > relation_t
Type for a pair of word_t (a relation) of a semigroup.
Definition: semigroups.h:52
ReductionOrdering(std::function< bool(rws_word_t const *, rws_word_t const *)> func)
A constructor.
Definition: rws.h:55
rws_word_t rewrite(rws_word_t w) const
Rewrites a copy of the word w according to the current rules in the rewriting system.
Definition: rws.h:207
std::list< Rule const * >::const_iterator rules_cend() const
Returns an iterator pointing past the last Rule of this.
Definition: rws.h:362
void add_rules(std::vector< relation_t > const &relations)
Adds rules derived from relations via RWS::word_to_rws_word to the rewriting system.
Definition: rws.h:266
This class provides a call operator which can be used to compare libsemigroups::rws_word_t.
Definition: rws.h:47