22#ifndef LIBSEMIGROUPS_DETAIL_REWRITERS_HPP_
23#define LIBSEMIGROUPS_DETAIL_REWRITERS_HPP_
29#include <unordered_map>
30#include <unordered_set>
32#include "../aho-corasick.hpp"
33#include "../debug.hpp"
34#include "../order.hpp"
36#include "multi-string-view.hpp"
99 Rule& operator=(
Rule const& copy) =
delete;
102 Rule& operator=(
Rule&& copy) =
delete;
166 [[nodiscard]]
bool empty() const noexcept {
167 return _lhs->empty() && _rhs->empty();
181 [[nodiscard]]
inline bool active() const noexcept {
182 LIBSEMIGROUPS_ASSERT(_id != 0);
231 LIBSEMIGROUPS_ASSERT(
id > 0);
232 LIBSEMIGROUPS_ASSERT(!
active());
246 "invalid id, expected a value greater than 0, found {}",
id);
265 [[nodiscard]] int64_t
id() const noexcept {
266 LIBSEMIGROUPS_ASSERT(_id != 0);
292 RuleLookup() : _rule(nullptr) {}
294 explicit RuleLookup(Rule* rule)
295 : _first(rule->lhs()->cbegin()),
296 _last(rule->lhs()->cend()),
299 RuleLookup& operator()(internal_string_type::iterator
const& first,
300 internal_string_type::iterator
const& last) {
306 Rule
const* rule()
const {
314 bool operator<(RuleLookup
const& that)
const;
317 internal_string_type::const_iterator _first;
318 internal_string_type::const_iterator _last;
324 using iterator = std::list<Rule const*>::iterator;
325 using const_iterator = std::list<Rule const*>::const_iterator;
326 using const_reverse_iterator
327 = std::list<Rule const*>::const_reverse_iterator;
332 Stats& init() noexcept;
334 Stats(Stats const&) noexcept = default;
335 Stats(Stats&&) noexcept = default;
336 Stats& operator=(Stats const&) noexcept = default;
337 Stats& operator=(Stats&&) noexcept = default;
339 size_t max_word_length;
340 size_t max_active_word_length;
341 size_t max_active_rules;
342 size_t min_length_lhs_rule;
343 uint64_t total_rules;
348 std::list<Rule const*> _active_rules;
349 std::array<iterator, 2> _cursors;
350 std::list<Rule*> _inactive_rules;
351 mutable Stats _stats;
358 Rules& operator=(Rules const&);
366 const_iterator begin() const noexcept {
367 return _active_rules.cbegin();
370 const_iterator
end() const noexcept {
371 return _active_rules.cend();
374 iterator
begin() noexcept {
375 return _active_rules.begin();
378 iterator
end() noexcept {
379 return _active_rules.end();
382 const_reverse_iterator rbegin() const noexcept {
383 return _active_rules.crbegin();
386 const_reverse_iterator rend() const noexcept {
387 return _active_rules.crend();
390 [[nodiscard]]
size_t number_of_active_rules() const noexcept {
391 return _active_rules.size();
394 [[nodiscard]]
size_t number_of_inactive_rules() const noexcept {
395 return _inactive_rules.size();
398 [[nodiscard]]
size_t max_active_word_length()
const;
400 iterator& cursor(
size_t index) {
401 LIBSEMIGROUPS_ASSERT(index < _cursors.size());
402 return _cursors[index];
406 void add_active_rule(Rule* rule) {
407 _active_rules.push_back(rule);
410 void add_inactive_rule(Rule* rule) {
411 _inactive_rules.push_back(rule);
414 Stats
const& stats()
const {
418 [[nodiscard]] iterator erase_from_active_rules(iterator it);
424 [[nodiscard]] Rule* copy_rule(Rule
const* rule);
427 [[nodiscard]] Rule* new_rule();
430 template <
typename Iterator>
431 [[nodiscard]] Rule* new_rule(Iterator begin_lhs,
435 Rule* rule = new_rule();
436 rule->lhs()->assign(begin_lhs, end_lhs);
437 rule->rhs()->assign(begin_rhs, end_rhs);
443 class RewriterBase :
public Rules {
444 std::unordered_set<internal_char_type> _alphabet;
445 mutable std::atomic<bool> _cached_confluent;
446 mutable std::atomic<bool> _confluence_known;
447 size_t _max_stack_depth;
448 std::stack<Rule*> _pending_rules;
449 std::atomic<bool> _requires_alphabet;
451 using alphabet_citerator
452 = std::unordered_set<internal_char_type>::const_iterator;
458 _cached_confluent(false),
459 _confluence_known(false),
462 _requires_alphabet() {}
464 RewriterBase&
init();
466 explicit RewriterBase(
bool requires_alphabet) : RewriterBase() {
467 _requires_alphabet = requires_alphabet;
472 RewriterBase& operator=(RewriterBase
const& that) {
473 Rules::operator=(that);
474 _cached_confluent = that._cached_confluent.load();
475 _confluence_known = that._confluence_known.load();
476 _requires_alphabet = that._requires_alphabet.load();
477 while (!_pending_rules.
empty()) {
478 _pending_rules.
pop();
480 decltype(_pending_rules) tmp = that._pending_rules;
481 while (!tmp.empty()) {
482 auto const* rule = tmp.top();
483 _pending_rules.
push(copy_rule(rule));
487 if (_requires_alphabet) {
488 _alphabet = that._alphabet;
493 bool requires_alphabet()
const {
494 return _requires_alphabet;
497 decltype(_alphabet) alphabet()
const {
501 alphabet_citerator alphabet_cbegin()
const {
502 return _alphabet.
cbegin();
505 alphabet_citerator alphabet_cend()
const {
506 return _alphabet.
cend();
509 void set_cached_confluent(tril val)
const;
511 bool cached_confluent() const noexcept {
512 return _cached_confluent;
515 [[nodiscard]]
bool consistent() const noexcept {
516 return _pending_rules.
empty();
519 [[nodiscard]]
bool confluence_known()
const {
520 return _confluence_known;
523 [[nodiscard]]
size_t max_stack_depth()
const {
524 return _max_stack_depth;
527 bool add_pending_rule(Rule* rule);
529 bool process_pending_rules();
535 void rewrite(Rule* rule)
const {
536 rewrite(*rule->lhs());
537 rewrite(*rule->rhs());
542 virtual void rewrite(internal_string_type& u)
const = 0;
544 virtual void add_rule(Rule* rule) = 0;
546 virtual Rules::iterator make_active_rule_pending(Rules::iterator it) = 0;
548 size_t number_of_pending_rules() const noexcept {
549 return _pending_rules.
size();
552 Rule* next_pending_rule() {
553 LIBSEMIGROUPS_ASSERT(_pending_rules.
size() != 0);
554 Rule* rule = _pending_rules.
top();
555 _pending_rules.
pop();
559 template <
typename StringLike>
560 void add_rule(StringLike
const& lhs, StringLike
const& rhs) {
562 if (add_pending_rule(new_rule(
563 lhs.cbegin(), lhs.cend(), rhs.cbegin(), rhs.cend()))) {
565 process_pending_rules();
570 template <
typename StringLike>
571 void add_pending_rule(StringLike
const& lhs, StringLike
const& rhs) {
574 new_rule(lhs.cbegin(), lhs.cend(), rhs.cbegin(), rhs.cend()));
578 void add_to_alphabet(internal_char_type letter) {
583 class RewriteFromLeft :
public RewriterBase {
584 std::set<RuleLookup> _set_rules;
587 using RewriterBase::cached_confluent;
590 RewriteFromLeft() =
default;
592 RewriteFromLeft& operator=(RewriteFromLeft
const&);
598 RewriteFromLeft&
init();
600 void rewrite(internal_string_type& u)
const;
602 [[nodiscard]]
bool confluent()
const;
607 using RewriterBase::add_rule;
610 void rewrite(Rule* rule)
const;
612 iterator make_active_rule_pending(iterator);
614 void report_from_confluent(
615 std::atomic_uint64_t
const&,
616 std::chrono::high_resolution_clock::time_point
const&)
const;
618 bool confluent_impl(std::atomic_uint64_t&)
const;
621 class RewriteTrie :
public RewriterBase {
624 std::map<index_type, Rule*> _rules;
628 using RewriterBase::cached_confluent;
630 using iterator = internal_string_type::iterator;
631 using rule_iterator = std::map<index_type, Rule*>::iterator;
633 RewriteTrie() : RewriterBase(true), _rules(), _trie() {}
635 RewriteTrie(RewriteTrie
const& that);
637 RewriteTrie& operator=(RewriteTrie
const& that);
644 rule_iterator rules_begin() {
645 return _rules.
begin();
648 rule_iterator rules_end() {
654 void rule_overlaps(index_type node);
656 void add_overlaps(Rule* rule, index_type node,
size_t overlap_length);
658 void rewrite(internal_string_type& u)
const;
660 [[nodiscard]]
bool confluent()
const;
663 Rules::add_rule(rule);
664 add_rule_to_trie(rule);
665 set_cached_confluent(tril::unknown);
668 using RewriterBase::add_rule;
671 [[nodiscard]]
bool descendants_confluent(Rule
const* rule1,
672 index_type current_node,
673 size_t backtrack_depth)
const;
676 void rewrite(Rule* rule)
const {
677 rewrite(*rule->lhs());
678 rewrite(*rule->rhs());
682 void add_rule_to_trie(Rule* rule) {
683 index_type node = _trie.add_word_no_checks(rule->lhs()->cbegin(),
684 rule->lhs()->cend());
688 Rules::iterator make_active_rule_pending(Rules::iterator it);
690 void report_from_confluent(
691 std::atomic_uint64_t
const&,
692 std::chrono::high_resolution_clock::time_point
const&)
const;
694 bool confluent_impl(std::atomic_uint64_t&)
const;
internal_string_type * lhs() const noexcept
Return the left-hand side of the rule.
Definition rewriters.hpp:130
void activate() noexcept
Activate a rule.
bool empty() const noexcept
Check if the left-hand and right-hand sides are empty.
Definition rewriters.hpp:166
void reorder()
Reorder the left-hand and right-hand sides.
Definition rewriters.hpp:283
bool active() const noexcept
Check if the Rule is active.
Definition rewriters.hpp:181
void deactivate() noexcept
Deactivate a rule.
void set_id(int64_t id)
Set the id of a rule.
Definition rewriters.hpp:243
int64_t id() const noexcept
Return the id of a rule.
Definition rewriters.hpp:265
void set_id_no_checks(int64_t id) noexcept
Set the id of a rule.
Definition rewriters.hpp:230
Rule(int64_t id)
Construct with new empty left-hand and right-hand sides.
internal_string_type * rhs() const noexcept
Return the right-hand side of the rule.
Definition rewriters.hpp:150
Thing::native_word_type reduce(Thing const &thing, typename Thing::native_word_type const &w)
Reduce a word.
#define LIBSEMIGROUPS_EXCEPTION(...)
Throw a LibsemigroupsException.
Definition exception.hpp:95
bool shortlex_compare(T const &first1, T const &last1, T const &first2, T const &last2)
Compare two objects of the same type using the short-lex reduction ordering.
Definition order.hpp:267
std::string internal_string_type
Definition rewriters.hpp:58
char external_char_type
Definition rewriters.hpp:63
std::string external_string_type
Definition rewriters.hpp:53
char internal_char_type
Definition rewriters.hpp:68
AhoCorasick::index_type index_type
Alias for the index of a node in the trie.
Definition aho-corasick.hpp:748
FroidurePin< typename Container::value_type > & init(FroidurePin< typename Container::value_type > &fp, Container const &gens)
Re-initialize a FroidurePin object from a container of generators.
Definition froidure-pin.hpp:1634
void add_rule(Presentation< Word > &p, Word const &lhop, Word const &rhop)
Add a rule to the presentation by reference and check.
Definition presentation.hpp:806
Namespace for everything in the libsemigroups library.
Definition action.hpp:44