22#ifndef LIBSEMIGROUPS_DETAIL_REWRITERS_HPP_
23#define LIBSEMIGROUPS_DETAIL_REWRITERS_HPP_
30#include <unordered_map>
32#include "libsemigroups/debug.hpp"
33#include "libsemigroups/order.hpp"
34#include "libsemigroups/types.hpp"
36#include "aho-corasick-impl.hpp"
37#include "multi-view.hpp"
52 using native_word_type = std::string;
55 native_word_type _lhs;
56 native_word_type _rhs;
60 explicit Rule(int64_t
id);
63 Rule& operator=(Rule
const& copy) =
delete;
64 Rule(Rule
const& copy) =
delete;
65 Rule(Rule&& copy) =
delete;
66 Rule& operator=(Rule&& copy) =
delete;
70 [[nodiscard]] native_word_type
const& lhs() const noexcept {
74 [[nodiscard]] native_word_type
const& rhs() const noexcept {
78 [[nodiscard]] native_word_type& lhs() noexcept {
82 [[nodiscard]] native_word_type& rhs() noexcept {
86 [[nodiscard]]
bool empty() const noexcept {
87 return _lhs.empty() && _rhs.empty();
90 [[nodiscard]]
inline bool active() const noexcept {
91 LIBSEMIGROUPS_ASSERT(_id != 0);
95 void activate_no_checks() noexcept;
96 void deactivate_no_checks() noexcept;
98 void set_id_no_checks(int64_t
id) noexcept {
99 LIBSEMIGROUPS_ASSERT(
id > 0);
100 LIBSEMIGROUPS_ASSERT(!active());
104 [[nodiscard]] int64_t id() const noexcept {
105 LIBSEMIGROUPS_ASSERT(_id != 0);
122 using native_word_type = Rule::native_word_type;
124 RuleLookup() : _rule(nullptr) {}
126 explicit RuleLookup(Rule* rule)
127 : _first(rule->lhs().cbegin()),
128 _last(rule->lhs().cend()),
131 RuleLookup& operator()(native_word_type::iterator first,
132 native_word_type::iterator last) {
138 Rule
const* rule()
const {
146 bool operator<(RuleLookup
const& that)
const;
149 native_word_type::const_iterator _first;
150 native_word_type::const_iterator _last;
160 using iterator = std::list<Rule*>::iterator;
161 using const_iterator = std::list<Rule*>::const_iterator;
162 using const_reverse_iterator = std::list<Rule*>::const_reverse_iterator;
167 Stats& init() noexcept;
169 Stats(Stats const&) noexcept = default;
170 Stats(Stats&&) noexcept = default;
171 Stats& operator=(Stats const&) noexcept = default;
172 Stats& operator=(Stats&&) noexcept = default;
174 size_t max_word_length;
175 size_t max_active_word_length;
176 size_t max_active_rules;
177 size_t min_length_lhs_rule;
178 uint64_t total_rules;
181 std::list<Rule*> _active_rules;
182 std::array<iterator, 2> _cursors;
183 std::list<Rule*> _inactive_rules;
184 mutable Stats _stats;
189 Rules(Rules const& that) : Rules() {
192 Rules(Rules&& that) =
default;
194 Rules& operator=(Rules
const&);
195 Rules& operator=(Rules&& that);
201 const_iterator
begin() const noexcept {
202 return _active_rules.cbegin();
205 const_iterator
end() const noexcept {
206 return _active_rules.cend();
209 iterator
begin() noexcept {
210 return _active_rules.begin();
213 iterator
end() noexcept {
214 return _active_rules.end();
217 const_reverse_iterator rbegin() const noexcept {
218 return _active_rules.crbegin();
221 const_reverse_iterator rend() const noexcept {
222 return _active_rules.crend();
225 [[nodiscard]]
size_t number_of_active_rules() const noexcept {
226 return _active_rules.size();
229 [[nodiscard]]
size_t number_of_inactive_rules() const noexcept {
230 return _inactive_rules.size();
233 [[nodiscard]]
size_t max_active_word_length()
const;
235 iterator& cursor(
size_t index) {
236 LIBSEMIGROUPS_ASSERT(index < _cursors.size());
237 return _cursors[index];
240 Stats
const& stats()
const {
247 template <
typename Iterator>
248 [[nodiscard]] Rule* new_rule(Iterator begin_lhs,
252 Rule* rule = new_rule();
253 rule->lhs().assign(begin_lhs, end_lhs);
254 rule->rhs().assign(begin_rhs, end_rhs);
259 [[nodiscard]] Rule* copy_rule(Rule
const* rule);
260 [[nodiscard]] iterator erase_from_active_rules(iterator it);
261 void add_inactive_rule(Rule* rule) {
262 _inactive_rules.push_back(rule);
266 [[nodiscard]] Rule* new_rule();
273 class RewriteBase :
public Rules {
274 mutable std::atomic<bool> _cached_confluent;
275 mutable std::atomic<bool> _confluence_known;
276 size_t _max_pending_rules;
279 enum class State : uint8_t {
281 adding_pending_rules,
282 reducing_pending_rules,
286 std::vector<Rule*> _pending_rules;
288 bool _ticker_running;
291 using native_word_type = Rule::native_word_type;
299 RewriteBase(RewriteBase
const& that) : RewriteBase() {
302 RewriteBase(RewriteBase&& that);
303 RewriteBase& operator=(RewriteBase
const& that);
304 RewriteBase& operator=(RewriteBase&& that);
306 virtual ~RewriteBase();
315 RewriteBase& increase_alphabet_size_by(
size_t) {
319 [[nodiscard]]
bool confluent();
321 bool cached_confluent() const noexcept {
322 return _cached_confluent;
325 void set_cached_confluent(tril val)
const;
327 [[nodiscard]]
bool confluence_known()
const {
328 return _confluence_known;
331 [[nodiscard]]
size_t max_pending_rules()
const {
332 return _max_pending_rules;
335 size_t number_of_pending_rules() const noexcept {
336 return _pending_rules.
size();
339 Rule* next_pending_rule();
341 template <
typename StringLike>
342 void add_rule(StringLike
const& lhs, StringLike
const& rhs);
349 void report_progress_from_thread(
350 std::atomic_uint64_t
const& seen,
351 std::chrono::high_resolution_clock::time_point
const& start_time);
353 void report_progress_from_thread(
354 std::chrono::high_resolution_clock::time_point
const& start_time) {
355 report_progress_from_thread(0, start_time);
358 bool add_pending_rule(Rule* rule);
361 virtual bool confluent_impl(std::atomic_uint64_t& seen) = 0;
363 virtual void report_checking_confluence(
364 std::atomic_uint64_t
const& seen,
365 std::chrono::high_resolution_clock::time_point
const& start_time)
369 virtual void report_reducing_rules(
370 std::atomic_uint64_t
const&,
371 std::chrono::high_resolution_clock::time_point
const&)
const {}
375 template <
typename StringLike>
376 void RewriteBase::add_rule(StringLike
const& lhs, StringLike
const& rhs) {
379 new_rule(lhs.cbegin(), lhs.cend(), rhs.cbegin(), rhs.cend()));
387 class RewriteFromLeft :
public RewriteBase {
388 std::set<RuleLookup> _set_rules;
391 using native_word_type = Rule::native_word_type;
393 using RewriteBase::add_rule;
395 RewriteFromLeft() =
default;
397 RewriteFromLeft(RewriteFromLeft
const& that) : RewriteFromLeft() {
400 RewriteFromLeft(RewriteFromLeft&&) =
default;
402 RewriteFromLeft& operator=(RewriteFromLeft
const&);
403 RewriteFromLeft& operator=(RewriteFromLeft&&) =
default;
407 RewriteFromLeft&
init();
409 bool process_pending_rules();
411 void rewrite(native_word_type& u);
413 void rewrite(native_word_type& u)
const {
414 const_cast<RewriteFromLeft*
>(
this)->rewrite(u);
418 void rewrite(Rule* rule)
const {
419 rewrite(rule->lhs());
420 rewrite(rule->rhs());
426 iterator make_active_rule_pending(iterator);
428 void report_checking_confluence(
429 std::atomic_uint64_t
const&,
430 std::chrono::high_resolution_clock::time_point
const&)
const override;
432 bool confluent_impl(std::atomic_uint64_t&)
override;
439 class RewriteTrie :
public RewriteBase {
441 using index_type = AhoCorasickImpl::index_type;
442 using iterator = native_word_type::iterator;
443 using rule_iterator = std::unordered_map<index_type, Rule*>::iterator;
444 using native_word_type = Rule::native_word_type;
447 std::unordered_map<index_type, Rule*> _new_rule_map;
448 AhoCorasickImpl _new_rule_trie;
449 std::vector<index_type> _rewrite_tmp_buf;
450 std::unordered_map<index_type, Rule*> _rule_map;
451 AhoCorasickImpl _rule_trie;
452 bool _ticker_running;
457 using RewriteBase::add_rule;
458 using RewriteBase::cached_confluent;
464 RewriteTrie(RewriteTrie
const& that) : RewriteTrie() {
467 RewriteTrie(RewriteTrie&& that) =
default;
468 RewriteTrie& operator=(RewriteTrie
const& that);
469 RewriteTrie& operator=(RewriteTrie&& that) =
default;
473 RewriteTrie& increase_alphabet_size_by(
size_t val) {
474 _rule_trie.increase_alphabet_size_by(val);
478 bool process_pending_rules();
481 void rewrite(native_word_type& u);
483 void rewrite(Rule* rule)
const {
484 rewrite(rule->lhs());
485 rewrite(rule->rhs());
489 void rewrite(native_word_type& u)
const {
490 const_cast<RewriteTrie*
>(
this)->rewrite(u);
495 Rules::add_rule(rule);
496 index_type node = _rule_trie.add_word_no_checks(rule->lhs().cbegin(),
499 set_cached_confluent(tril::unknown);
502 [[nodiscard]]
bool descendants_confluent(Rule
const* rule1,
503 index_type current_node,
504 size_t backtrack_depth)
const;
506 Rules::iterator make_active_rule_pending(Rules::iterator it);
508 bool confluent_impl(std::atomic_uint64_t&)
override;
510 void report_checking_confluence(
511 std::atomic_uint64_t
const&,
512 std::chrono::high_resolution_clock::time_point
const&)
const override;
514 void report_reducing_rules(
515 std::atomic_uint64_t
const&,
516 std::chrono::high_resolution_clock::time_point
const&)
const override;
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:273
@ none
No ordering.
Definition order.hpp:47
AhoCorasick::index_type index_type
Alias for the index of a node in the trie.
Definition aho-corasick.hpp:750
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:1636
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:841
Namespace for everything in the libsemigroups library.
Definition action.hpp:44