From 968f233a11e1ebce4a765d700db01b6130b2b73d Mon Sep 17 00:00:00 2001 From: Alexander Delman Date: Sat, 15 Jun 2024 16:24:51 +0300 Subject: [PATCH] (#330) fixed decisions detection + refactoring --- .../Objects/include/Objects/FiniteAutomaton.h | 4 +- libs/Objects/include/Objects/MemoryCommon.h | 4 +- .../include/Objects/MemoryFiniteAutomaton.h | 12 ++-- libs/Objects/include/Objects/Tools.h | 2 +- libs/Objects/src/FiniteAutomaton.cpp | 26 +++---- libs/Objects/src/MemoryCommon.cpp | 16 +++-- libs/Objects/src/MemoryFiniteAutomaton.cpp | 67 +++++++++++-------- 7 files changed, 77 insertions(+), 54 deletions(-) diff --git a/libs/Objects/include/Objects/FiniteAutomaton.h b/libs/Objects/include/Objects/FiniteAutomaton.h index 52caff7d..90910d61 100644 --- a/libs/Objects/include/Objects/FiniteAutomaton.h +++ b/libs/Objects/include/Objects/FiniteAutomaton.h @@ -73,10 +73,10 @@ class FiniteAutomaton : public AbstractMachine { // eps-переходам (если флаг установлен в 0 - по всем переходам) std::set closure(const std::set&, bool) const; - std::vector get_bisimilar_classes() const; + std::vector get_bisimulation_classes() const; // объединение эквивалентных классов (принимает на вход вектор размера states.size()) // на i-й позиции номер класса i-го состояния - std::tuple> merge_equivalent_classes( + std::tuple> merge_classes( const std::vector&) const; static bool equality_checker(const FiniteAutomaton& fa1, const FiniteAutomaton& fa2); // дополнительно возвращает в векторах номера классов состояний каждого автомата diff --git a/libs/Objects/include/Objects/MemoryCommon.h b/libs/Objects/include/Objects/MemoryCommon.h index 1daa642c..a764bc16 100644 --- a/libs/Objects/include/Objects/MemoryCommon.h +++ b/libs/Objects/include/Objects/MemoryCommon.h @@ -91,12 +91,14 @@ class CaptureGroup { bool operator==(const CaptureGroup& other) const; bool get_is_reset() const; + bool get_cell_number() const; int get_opening_state_index() const; const std::unordered_set, VectorHasher>& get_paths() const; const std::unordered_set& get_states() const; - std::unordered_set get_states_diff(const CaptureGroup& other) const; + std::tuple, std::unordered_set> get_states_diff( + const CaptureGroup& other) const; friend std::ostream& operator<<(std::ostream& os, const CaptureGroup& cg); }; diff --git a/libs/Objects/include/Objects/MemoryFiniteAutomaton.h b/libs/Objects/include/Objects/MemoryFiniteAutomaton.h index 9cc2ceec..68650853 100644 --- a/libs/Objects/include/Objects/MemoryFiniteAutomaton.h +++ b/libs/Objects/include/Objects/MemoryFiniteAutomaton.h @@ -176,17 +176,21 @@ class MemoryFiniteAutomaton : public AbstractMachine { bool find_decisions(int state_index, std::vector& visited, // NOLINT(runtime/references) - const std::unordered_set& states_to_check) const; - bool states_have_decisions(const std::unordered_set& states_to_check) const; + const std::unordered_set& states_to_check, + const std::unordered_set& following_states, + const CaptureGroup& cg) const; + bool states_have_decisions(const std::unordered_set& states_to_check, + const std::unordered_set& following_states, + const CaptureGroup& cg) const; - FiniteAutomaton get_cg_fa(const CaptureGroup&) const; + FiniteAutomaton get_cg_fa(const CaptureGroup& cg) const; static std::optional bisimilarity_checker(const MemoryFiniteAutomaton&, const MemoryFiniteAutomaton&); // объединение эквивалентных классов (принимает на вход вектор размера states.size()) // на i-й позиции номер класса i-го состояния - std::tuple> merge_equivalent_classes( + std::tuple> merge_classes( const std::vector&) const; public: diff --git a/libs/Objects/include/Objects/Tools.h b/libs/Objects/include/Objects/Tools.h index 6ed57f39..73c6bd96 100644 --- a/libs/Objects/include/Objects/Tools.h +++ b/libs/Objects/include/Objects/Tools.h @@ -33,7 +33,7 @@ struct TupleHasher { size_t operator()(const std::tuple& p) const; }; -using IntPairSet = std::unordered_set, IntPairHasher>; +using IntPairsSet = std::unordered_set, IntPairHasher>; std::ostream& operator<<(std::ostream& os, const std::vector& vec); diff --git a/libs/Objects/src/FiniteAutomaton.cpp b/libs/Objects/src/FiniteAutomaton.cpp index 589b9574..7f7bb1a0 100644 --- a/libs/Objects/src/FiniteAutomaton.cpp +++ b/libs/Objects/src/FiniteAutomaton.cpp @@ -383,7 +383,7 @@ FiniteAutomaton FiniteAutomaton::minimize(bool is_trim, iLogTemplate* log) const classes[groups[i][j]] = i; } } - auto [minimized_dfa, class_to_index] = dfa.merge_equivalent_classes(classes); + auto [minimized_dfa, class_to_index] = dfa.merge_classes(classes); // кэширование language->set_min_dfa(minimized_dfa); @@ -1361,7 +1361,7 @@ bool FiniteAutomaton::is_one_unambiguous(iLogTemplate* log) const { return true; } -tuple> FiniteAutomaton::merge_equivalent_classes( +tuple> FiniteAutomaton::merge_classes( const vector& classes) const { map> class_to_indexes; for (int i = 0; i < classes.size(); i++) @@ -1398,7 +1398,7 @@ tuple> FiniteAutomaton::merge_equivalen return {{class_to_index.at(classes[initial_state]), new_states, language}, class_to_index}; } -vector FiniteAutomaton::get_bisimilar_classes() const { +vector FiniteAutomaton::get_bisimulation_classes() const { vector fa_items; vector nonterminals; vector terminals; @@ -1418,8 +1418,8 @@ vector FiniteAutomaton::get_bisimilar_classes() const { FiniteAutomaton FiniteAutomaton::merge_bisimilar(iLogTemplate* log) const { MetaInfo old_meta, new_meta; - vector classes = get_bisimilar_classes(); - auto [result, class_to_index] = merge_equivalent_classes(classes); + vector classes = get_bisimulation_classes(); + auto [result, class_to_index] = merge_classes(classes); for (int i = 0; i < classes.size(); i++) { for (int j = 0; j < classes.size(); j++) @@ -1602,9 +1602,9 @@ bool FiniteAutomaton::equality_checker(const FiniteAutomaton& fa1, const FiniteA if (t != 0) return false; - vector bisimilar_classes(nonterminals.size()); + vector bisimulation_classes(nonterminals.size()); for (int i = 0; i < nonterminals.size(); i++) - bisimilar_classes[i] = nonterminals[i]->class_number; + bisimulation_classes[i] = nonterminals[i]->class_number; // биективная бисимуляция обратных грамматик vector>> fa1_reverse_rules = RLGrammar::get_reverse_grammar( @@ -1623,22 +1623,22 @@ bool FiniteAutomaton::equality_checker(const FiniteAutomaton& fa1, const FiniteA RLGrammar::get_bisimilar_grammar( reverse_rules, nonterminals, reverse_bisimilar_nonterminals, class_to_nonterminals); // сопоставление состояний 1 к 1 - vector reverse_bisimilar_classes; + vector reverse_bisimulation_classes; for (RLGrammar::Item* nont : nonterminals) { - reverse_bisimilar_classes.push_back(nont->class_number); + reverse_bisimulation_classes.push_back(nont->class_number); nont->class_number = -1; } // устанавливаем классы нетерминалов-состояний (1 к 1), чтобы после сопоставить переходы int new_class = 0; - for (int i = 0; i < bisimilar_classes.size(); i++) { + for (int i = 0; i < bisimulation_classes.size(); i++) { if (nonterminals[i]->class_number != -1) continue; nonterminals[i]->class_number = new_class; // поиск нетерминалов с классом, как у i-го - for (int j = i + 1; j < bisimilar_classes.size(); j++) { - if (bisimilar_classes[j] == bisimilar_classes[i]) - if (reverse_bisimilar_classes[j] == reverse_bisimilar_classes[i]) + for (int j = i + 1; j < bisimulation_classes.size(); j++) { + if (bisimulation_classes[j] == bisimulation_classes[i]) + if (reverse_bisimulation_classes[j] == reverse_bisimulation_classes[i]) nonterminals[j]->class_number = new_class; } new_class++; diff --git a/libs/Objects/src/MemoryCommon.cpp b/libs/Objects/src/MemoryCommon.cpp index f8bce317..f80e29b5 100644 --- a/libs/Objects/src/MemoryCommon.cpp +++ b/libs/Objects/src/MemoryCommon.cpp @@ -1,5 +1,6 @@ #include "Objects/MemoryCommon.h" +using std::tuple; using std::unordered_set; using std::vector; @@ -60,6 +61,10 @@ bool CaptureGroup::get_is_reset() const { return is_reset; } +bool CaptureGroup::get_cell_number() const { + return cell; +} + int CaptureGroup::get_opening_state_index() const { return (*paths.begin())[0]; } @@ -73,18 +78,19 @@ const unordered_set& CaptureGr return states; } -unordered_set CaptureGroup::get_states_diff(const CaptureGroup& other) const { +tuple, unordered_set> CaptureGroup::get_states_diff( + const CaptureGroup& other) const { unordered_set diff; for (auto st : states) if (st.class_num != State::reset_class && !other.state_classes.count(st.class_num)) diff.insert(st.index); - unordered_set res(diff); + unordered_set following(diff); for (const auto& path : paths) for (size_t i = path.size() - 1; i > 0; i--) if (diff.count(path[i - 1])) - res.insert(path[i]); - return res; + following.insert(path[i]); + return {diff, following}; } std::ostream& operator<<(std::ostream& os, const CaptureGroup& cg) { @@ -95,4 +101,4 @@ std::ostream& operator<<(std::ostream& os, const CaptureGroup& cg) { for (const auto& i : cg.states) os << "{" << i.index << ": " << i.class_num << "} "; return os << "]\n"; -} +} \ No newline at end of file diff --git a/libs/Objects/src/MemoryFiniteAutomaton.cpp b/libs/Objects/src/MemoryFiniteAutomaton.cpp index 63d3efca..d8bbc7ec 100644 --- a/libs/Objects/src/MemoryFiniteAutomaton.cpp +++ b/libs/Objects/src/MemoryFiniteAutomaton.cpp @@ -1062,7 +1062,7 @@ size_t TraversalState::Hasher::operator()(const TraversalState& s) const { pair, unordered_set> MemoryFiniteAutomaton::generate_test_set( int max_len) const { unordered_set words_in_language; - unordered_map words_to_mutate; + unordered_map words_to_mutate; unordered_set current_states; current_states.insert(TraversalState(&states[initial_state])); @@ -1383,6 +1383,11 @@ void find_opening_states_dfs(int state_index, } } +bool is_valid_transition(bool is_opening_state, optional action) { + bool is_open_action = action && action == MFATransition::open; + return is_opening_state == is_open_action; +} + pair>, vector>> MemoryFiniteAutomaton::find_cg_paths( int state_index, std::unordered_set visited, int cell, int opening_state) const { vector> paths; @@ -1392,22 +1397,19 @@ pair>, vector>> MemoryFiniteAutomaton::find_cg_pa for (const auto& [symbol, symbol_transitions] : states[state_index].transitions) for (const auto& tr : symbol_transitions) { optional action; - if (tr.memory_actions.count(cell)) - action = tr.memory_actions.at(cell); + if (auto it = tr.memory_actions.find(cell); it != tr.memory_actions.end()) + action = it->second; if (action && action == MFATransition::close) { paths.push_back({state_index}); } else if (action && action == MFATransition::reset) { reset_paths.push_back({state_index}); } else { - bool is_open_action = action && action == MFATransition::open; bool is_opening_state = state_index == opening_state; bool should_process = !visited.count(tr.to) || // чтобы обработать случай, когда открывающее совпадает с // закрывающим, e.g. [a*a]:1*&1 (!is_opening_state && tr.to == opening_state); - bool is_valid_transition = - is_opening_state ? action && is_open_action : !is_open_action; - if (should_process && is_valid_transition) { + if (should_process && is_valid_transition(is_opening_state, action)) { auto [t, _] = find_cg_paths(tr.to, visited, cell, opening_state); for (auto& i : t) { i.insert(i.begin(), state_index); @@ -1440,15 +1442,24 @@ vector MemoryFiniteAutomaton::find_capture_groups_backward( return res; } -bool MemoryFiniteAutomaton::find_decisions(int state_index, std::vector& visited, - const std::unordered_set& states_to_check) const { +bool MemoryFiniteAutomaton::find_decisions(int state_index, vector& visited, + const unordered_set& states_to_check, + const unordered_set& following_states, + const CaptureGroup& cg) const { visited[state_index] = 1; optional single_tr; int count = 0; for (const auto& [symbol, symbol_transitions] : states[state_index].transitions) - for (const auto& tr : symbol_transitions) - if (states_to_check.count(tr.to)) { + for (const auto& tr : symbol_transitions) { + optional action; + if (auto it = tr.memory_actions.find(cg.get_cell_number()); + it != tr.memory_actions.end()) + action = it->second; + + if (is_valid_transition(state_index == cg.get_opening_state_index(), action) && + (states_to_check.count(tr.to) || following_states.count(tr.to)) && + !(following_states.count(state_index) && !states_to_check.count(tr.to))) { if (visited[tr.to] == 0) { if (++count > 1) return true; @@ -1457,22 +1468,24 @@ bool MemoryFiniteAutomaton::find_decisions(int state_index, std::vector& vi return true; } } + } bool found = false; if (single_tr) - found = find_decisions(single_tr->to, visited, states_to_check); + found = find_decisions(single_tr->to, visited, states_to_check, following_states, cg); visited[state_index] = 2; return found; } -bool MemoryFiniteAutomaton::states_have_decisions( - const std::unordered_set& states_to_check) const { +bool MemoryFiniteAutomaton::states_have_decisions(const unordered_set& states_to_check, + const unordered_set& following_states, + const CaptureGroup& cg) const { vector visited(size(), 0); for (auto start : states_to_check) { if (visited[start] != 0) continue; - if (find_decisions(start, visited, states_to_check)) + if (find_decisions(start, visited, states_to_check, following_states, cg)) return true; } return false; @@ -1612,9 +1625,7 @@ optional MemoryFiniteAutomaton::bisimilarity_checker(const MemoryFiniteAut for (auto color : mfa_colors[i][j]) if (!colors_to_ignore.count(color)) j_colors.insert(color); - if (!j_colors.empty()) - colored_SCC.insert( - {ab_classes[i][j], set(j_colors.begin(), j_colors.end())}); + colored_SCC.insert({ab_classes[i][j], set(j_colors.begin(), j_colors.end())}); } if (!colored_SCC.empty()) colored_SCCs[i].insert(colored_SCC); @@ -1647,8 +1658,8 @@ optional MemoryFiniteAutomaton::bisimilarity_checker(const MemoryFiniteAut in_SCCs[i].insert(j); vector symbolic_fas({mfas[0]->to_symbolic_fa(), mfas[1]->to_symbolic_fa()}); - vector> symbolic_classes = {symbolic_fas[0].get_bisimilar_classes(), - symbolic_fas[1].get_bisimilar_classes()}; + vector> symbolic_classes = {symbolic_fas[0].get_bisimulation_classes(), + symbolic_fas[1].get_bisimulation_classes()}; #ifdef DEBUG cout << ab_classes[0] << ab_classes[1]; cout << FiniteAutomaton::bisimilar(symbolic_fas[0], symbolic_fas[1]) << "\n"; @@ -1744,11 +1755,11 @@ optional MemoryFiniteAutomaton::bisimilarity_checker(const MemoryFiniteAut for (int i = 0; i < CGs_0.size(); i++) for (int j = 0; j < CGs_1.size(); j++) { const auto &cg0 = CGs_0[i], cg1 = CGs_1[j]; - unordered_set states_to_check_0 = cg0.get_states_diff(cg1), - states_to_check_1 = cg1.get_states_diff(cg0); + auto [diff0, following0] = cg0.get_states_diff(cg1); + auto [diff1, following1] = cg1.get_states_diff(cg0); - if (!mfa1.states_have_decisions(states_to_check_0) && - !mfa2.states_have_decisions(states_to_check_1)) { + if (!mfa1.states_have_decisions(diff0, following0, cg0) && + !mfa2.states_have_decisions(diff1, following1, cg1)) { check_set_0.insert(i); check_set_1.insert(j); } @@ -1793,8 +1804,8 @@ optional MemoryFiniteAutomaton::bisimilar(const MemoryFiniteAutomaton& mfa return result; } -tuple> MemoryFiniteAutomaton:: - merge_equivalent_classes(const vector& classes) const { +tuple> MemoryFiniteAutomaton::merge_classes( + const vector& classes) const { map> class_to_indexes; for (int i = 0; i < classes.size(); i++) class_to_indexes[classes[i]].push_back(i); @@ -1832,9 +1843,9 @@ tuple> MemoryFiniteAutomaton:: MemoryFiniteAutomaton MemoryFiniteAutomaton::merge_bisimilar(iLogTemplate* log) const { MetaInfo old_meta, new_meta; - vector classes = to_symbolic_fa().get_bisimilar_classes(); + vector classes = to_symbolic_fa().get_bisimulation_classes(); classes.resize(size()); // в symbolic_fa первые size() состояний - состояния исходного mfa - auto [result, class_to_index] = merge_equivalent_classes(classes); + auto [result, class_to_index] = merge_classes(classes); for (int i = 0; i < classes.size(); i++) { for (int j = 0; j < classes.size(); j++)