From 341f0d6e98cc506eeca21511bfdab225fd3170af Mon Sep 17 00:00:00 2001 From: koniksedy Date: Mon, 2 Dec 2024 15:26:02 +0100 Subject: [PATCH 1/6] dispatch --- include/mata/nfa/nfa.hh | 44 +++++++++++++++++++++++++++- include/mata/nfa/types.hh | 17 +++++++++++ src/nfa/operations.cc | 61 +++++++++++++++++++++++++++++++++------ 3 files changed, 112 insertions(+), 10 deletions(-) diff --git a/include/mata/nfa/nfa.hh b/include/mata/nfa/nfa.hh index 4ce4505a7..3e8d231bf 100644 --- a/include/mata/nfa/nfa.hh +++ b/include/mata/nfa/nfa.hh @@ -646,8 +646,50 @@ Nfa complement(const Nfa& aut, const utils::OrdVector& symbols, * @brief Compute minimal deterministic automaton. * * @param[in] aut Automaton whose minimal version to compute. + * @param[in] property Property of the automaton to minimize. + * - AutomatonProperty::Trimmed - Trim will not be performed. * @param[in] params Optional parameters to control the minimization algorithm: - * - "algorithm": "brzozowski" + * - "algorithm": "brzozowski" (Default: "brzozowski") + * @return Minimal deterministic automaton. + */ +Nfa minimize_nfa(const Nfa& aut, const ParameterMap& params = { { "algorithm", "brzozowski" } }); + +/** + * @brief Compute minimal deterministic automaton. + * + * @param[in] aut Deterministic automaton whose minimal version to compute. + * @param[in] property Property of the automaton to minimize. + * - AutomatonProperty::Trimmed - Trim will not be performed. + * @param[in] params Optional parameters to control the minimization algorithm: + * - "algorithm": "hopcroft", "brzozowski" (Default: "hopcroft") + * @return Minimal deterministic automaton. + */ +Nfa minimize_dfa(const Nfa &aut, + const std::optional property, + const ParameterMap& params = { { "algorithm", "hopcroft" } }); + +/** + * @brief Compute minimal deterministic automaton. + * + * @param[in] aut Automaton whose minimal version to compute. + * @param[in] type Type of the automaton to minimize (NFA or DFA). + * @param[in] property Property of the automaton to minimize. + * - AutomatonProperty::Trimmed - Trim will not be performed. + * @param[in] params Optional parameters to control the minimization algorithm: + * - "algorithm": "hopcroft", "brzozowski" (Default: "brzozowski") + * @return Minimal deterministic automaton. + */ +Nfa minimize(const Nfa &aut, + const AutomatonType type, + const std::optional property = std::nullopt, + const ParameterMap& params = { { "algorithm", "brzozowski" } }); + +/** + * @brief Compute minimal deterministic automaton. + * + * @param[in] aut Automaton whose minimal version to compute. + * @param[in] params Optional parameters to control the minimization algorithm: + * - "algorithm": "hopcroft", "brzozowski" (Default: "brzozowski") * @return Minimal deterministic automaton. */ Nfa minimize(const Nfa &aut, const ParameterMap& params = { { "algorithm", "brzozowski" } }); diff --git a/include/mata/nfa/types.hh b/include/mata/nfa/types.hh index 40a016d7f..5733ada5e 100644 --- a/include/mata/nfa/types.hh +++ b/include/mata/nfa/types.hh @@ -43,6 +43,23 @@ public: static const Symbol max_symbol = std::numeric_limits::max(); }; +/** + * @brief Properties of an automaton. + */ +enum class AutomatonProperty { + Trimmed, ///< Automaton has only useful states (i.e., reachable from initial states and leading to final states). + Complete, ///< Automaton is complete (i.e., every state has an outgoing transition for every symbol). + Minimal ///< Automaton is minimal. +}; + +/** + * @brief Type of an automaton (NFA or DFA). + */ +enum class AutomatonType { + Nfa, ///< Non-deterministic finite automaton. + Dfa ///< Deterministic finite automaton. +}; + struct Nfa; ///< A non-deterministic finite automaton. /// An epsilon symbol which is now defined as the maximal value of data type used for symbols. diff --git a/src/nfa/operations.cc b/src/nfa/operations.cc index 347d0b08d..c5759ab30 100644 --- a/src/nfa/operations.cc +++ b/src/nfa/operations.cc @@ -927,29 +927,72 @@ Nfa mata::nfa::algorithms::minimize_brzozowski(const Nfa& aut) { return determinize(revert(determinize(revert(aut)))); } -Nfa mata::nfa::minimize( - const Nfa& aut, - const ParameterMap& params) -{ - Nfa result; - // setting the default algorithm - decltype(algorithms::minimize_brzozowski)* algo = algorithms::minimize_brzozowski; +Nfa mata::nfa::minimize_nfa(const Nfa& aut, const ParameterMap& params) { if (!haskey(params, "algorithm")) { throw std::runtime_error(std::to_string(__func__) + " requires setting the \"algorithm\" key in the \"params\" argument; " "received: " + std::to_string(params)); } + // Setting the algorithm. Default is Hopcroft. const std::string& str_algo = params.at("algorithm"); - if ("brzozowski" == str_algo) { /* default */ } + decltype(algorithms::minimize_brzozowski)* algo = algorithms::minimize_brzozowski; + if (str_algo == "brzozowski") { /* default */ } else { + throw std::runtime_error(std::string(__func__) + + " received an unknown value for the \"algorithm\" key: " + str_algo); + } + + return algo(aut); +} + +Nfa mata::nfa::minimize_dfa(const Nfa &aut, + const std::optional property, + const ParameterMap& params) +{ + if (!haskey(params, "algorithm")) { throw std::runtime_error(std::to_string(__func__) + - " received an unknown value of the \"algorithm\" key: " + str_algo); + " requires setting the \"algorithm\" key in the \"params\" argument; " + "received: " + std::to_string(params)); } + // Setting the algorithm. Default is Hopcroft. + const std::string& str_algo = params.at("algorithm"); + decltype(algorithms::minimize_hopcroft)* algo = algorithms::minimize_hopcroft; + if (str_algo == "hopcroft") { + /* default */; + } else if (str_algo == "brzozowski") { + algo = algorithms::minimize_brzozowski; + } else { + throw std::runtime_error(std::string(__func__) + + " received an unknown value for the \"algorithm\" key: " + str_algo); + } + + // Hopcroft algorithm does not work with non-trimmed automata. + if (str_algo == "hopcroft" && property != AutomatonProperty::Trimmed) { + return algo(Nfa(aut).trim()); + } return algo(aut); } +Nfa mata::nfa::minimize(const Nfa &aut, + const AutomatonType type, + const std::optional property, + const ParameterMap& params) +{ + if (type == AutomatonType::Dfa) { + return minimize_dfa(aut, property, params); + } + return minimize_nfa(aut, params); +} + +Nfa mata::nfa::minimize( + const Nfa& aut, + const ParameterMap& params) +{ + return minimize(aut, AutomatonType::Nfa, std::nullopt, params); +} + // Anonymous namespace for the Hopcroft minimization algorithm. namespace { template From 52222c33ad0f30cefb55498c3354f75cb262ee7d Mon Sep 17 00:00:00 2001 From: koniksedy Date: Tue, 3 Dec 2024 10:54:40 +0100 Subject: [PATCH 2/6] new minimize dispatch --- include/mata/nfa/nfa.hh | 43 ++++------------------- include/mata/nfa/plumbing.hh | 4 ++- src/nfa/operations.cc | 36 +++++-------------- tests-integration/src/test-unary-op.cc | 2 +- tests-integration/src/unary-operations.cc | 6 ++-- tests/nfa/nfa-plumbing.cc | 2 +- tests/nfa/nfa.cc | 2 +- 7 files changed, 24 insertions(+), 71 deletions(-) diff --git a/include/mata/nfa/nfa.hh b/include/mata/nfa/nfa.hh index dcc205c92..78eb7fef6 100644 --- a/include/mata/nfa/nfa.hh +++ b/include/mata/nfa/nfa.hh @@ -669,54 +669,23 @@ Nfa complement(const Nfa& aut, const utils::OrdVector& symbols, /** * @brief Compute minimal deterministic automaton. * - * @param[in] aut Automaton whose minimal version to compute. - * @param[in] property Property of the automaton to minimize. - * - AutomatonProperty::Trimmed - Trim will not be performed. - * @param[in] params Optional parameters to control the minimization algorithm: - * - "algorithm": "brzozowski" (Default: "brzozowski") - * @return Minimal deterministic automaton. - */ -Nfa minimize_nfa(const Nfa& aut, const ParameterMap& params = { { "algorithm", "brzozowski" } }); - -/** - * @brief Compute minimal deterministic automaton. - * - * @param[in] aut Deterministic automaton whose minimal version to compute. - * @param[in] property Property of the automaton to minimize. - * - AutomatonProperty::Trimmed - Trim will not be performed. - * @param[in] params Optional parameters to control the minimization algorithm: - * - "algorithm": "hopcroft", "brzozowski" (Default: "hopcroft") - * @return Minimal deterministic automaton. - */ -Nfa minimize_dfa(const Nfa &aut, - const std::optional property, - const ParameterMap& params = { { "algorithm", "hopcroft" } }); - -/** - * @brief Compute minimal deterministic automaton. - * - * @param[in] aut Automaton whose minimal version to compute. - * @param[in] type Type of the automaton to minimize (NFA or DFA). - * @param[in] property Property of the automaton to minimize. - * - AutomatonProperty::Trimmed - Trim will not be performed. + * @param[in] aut NFA whose minimal version to compute. * @param[in] params Optional parameters to control the minimization algorithm: * - "algorithm": "hopcroft", "brzozowski" (Default: "brzozowski") * @return Minimal deterministic automaton. */ -Nfa minimize(const Nfa &aut, - const AutomatonType type, - const std::optional property = std::nullopt, - const ParameterMap& params = { { "algorithm", "brzozowski" } }); +Nfa make_minimal_dfa(const Nfa &nfa, const ParameterMap& params = { { "algorithm", "brzozowski" } }); /** * @brief Compute minimal deterministic automaton. * - * @param[in] aut Automaton whose minimal version to compute. + * @param[in] aut DFA whose minimal version to compute. Trimming on the copy of the automaton + * will be performed if the automaton is not already trimmed. * @param[in] params Optional parameters to control the minimization algorithm: - * - "algorithm": "hopcroft", "brzozowski" (Default: "brzozowski") + * - "algorithm": "hopcroft", "brzozowski" (Default: "hopcroft") * @return Minimal deterministic automaton. */ -Nfa minimize(const Nfa &aut, const ParameterMap& params = { { "algorithm", "brzozowski" } }); +Nfa minimize(const Nfa &dfa, const ParameterMap& params = { { "algorithm", "hopcroft" } }); /** * @brief Determinize automaton. diff --git a/include/mata/nfa/plumbing.hh b/include/mata/nfa/plumbing.hh index 9d1c08f0f..775affd6b 100644 --- a/include/mata/nfa/plumbing.hh +++ b/include/mata/nfa/plumbing.hh @@ -35,7 +35,9 @@ inline void complement( { "minimize", "false"}}) { *result = complement(aut, alphabet, params); } -inline void minimize(Nfa* res, const Nfa &aut) { *res = minimize(aut); } +inline void minimize(Nfa* res, const Nfa &dfa, const ParameterMap& params = {{ "algorithm", "hopcroft" }}) { *res = minimize(dfa, params); } + +inline void make_minimal_dfa(Nfa* res, const Nfa &nfa, const ParameterMap& params = {{ "algorithm", "brzozowski" }}) { *res = make_minimal_dfa(nfa, params); } inline void determinize(Nfa* result, const Nfa& aut, std::unordered_map *subset_map = nullptr) { *result = determinize(aut, subset_map); diff --git a/src/nfa/operations.cc b/src/nfa/operations.cc index c377f944d..454670f74 100644 --- a/src/nfa/operations.cc +++ b/src/nfa/operations.cc @@ -927,7 +927,7 @@ Nfa mata::nfa::algorithms::minimize_brzozowski(const Nfa& aut) { return determinize(revert(determinize(revert(aut)))); } -Nfa mata::nfa::minimize_nfa(const Nfa& aut, const ParameterMap& params) { +Nfa mata::nfa::make_minimal_dfa(const Nfa& nfa, const ParameterMap& params) { if (!haskey(params, "algorithm")) { throw std::runtime_error(std::to_string(__func__) + " requires setting the \"algorithm\" key in the \"params\" argument; " @@ -943,12 +943,10 @@ Nfa mata::nfa::minimize_nfa(const Nfa& aut, const ParameterMap& params) { " received an unknown value for the \"algorithm\" key: " + str_algo); } - return algo(aut); + return algo(nfa); } -Nfa mata::nfa::minimize_dfa(const Nfa &aut, - const std::optional property, - const ParameterMap& params) +Nfa mata::nfa::minimize(const Nfa &dfa, const ParameterMap& params) { if (!haskey(params, "algorithm")) { throw std::runtime_error(std::to_string(__func__) + @@ -969,28 +967,12 @@ Nfa mata::nfa::minimize_dfa(const Nfa &aut, } // Hopcroft algorithm does not work with non-trimmed automata. - if (str_algo == "hopcroft" && property != AutomatonProperty::Trimmed) { - return algo(Nfa(aut).trim()); + const BoolVector is_used = dfa.get_useful_states(); + bool is_trimmed = std::all_of(is_used.begin(), is_used.end(), [](bool b) { return b; }); + if (str_algo == "hopcroft" && !is_trimmed) { + return algo(Nfa(dfa).trim()); } - return algo(aut); -} - -Nfa mata::nfa::minimize(const Nfa &aut, - const AutomatonType type, - const std::optional property, - const ParameterMap& params) -{ - if (type == AutomatonType::Dfa) { - return minimize_dfa(aut, property, params); - } - return minimize_nfa(aut, params); -} - -Nfa mata::nfa::minimize( - const Nfa& aut, - const ParameterMap& params) -{ - return minimize(aut, AutomatonType::Nfa, std::nullopt, params); + return algo(dfa); } // Anonymous namespace for the Hopcroft minimization algorithm. @@ -1338,7 +1320,7 @@ Nfa mata::nfa::algorithms::minimize_hopcroft(const Nfa& dfa_trimmed) { for (const SymbolPost &symbol_post : dfa_trimmed.delta[q]) { assert(symbol_post.targets.size() == 1); const State target = brp.set_idx[*symbol_post.targets.begin()]; - mut_state_post.push_back(SymbolPost{ symbol_post.symbol, StateSet{ target } }); + mut_state_post.emplace_back(SymbolPost{ symbol_post.symbol, StateSet{ target } }); } } diff --git a/tests-integration/src/test-unary-op.cc b/tests-integration/src/test-unary-op.cc index 770610d86..ece07a789 100644 --- a/tests-integration/src/test-unary-op.cc +++ b/tests-integration/src/test-unary-op.cc @@ -36,7 +36,7 @@ int main(int argc, char *argv[]) { // minimization test Nfa aut_min(aut); - aut_min = mata::nfa::minimize(aut_min); + aut_min = mata::nfa::make_minimal_dfa(aut_min); std::cout << "minimize:" << (mata::nfa::are_equivalent(aut, aut_min) ? "ok" : "fail") << std::endl; return EXIT_SUCCESS; diff --git a/tests-integration/src/unary-operations.cc b/tests-integration/src/unary-operations.cc index 9b2cb175f..f1c6a91e1 100644 --- a/tests-integration/src/unary-operations.cc +++ b/tests-integration/src/unary-operations.cc @@ -64,12 +64,12 @@ int main(int argc, char *argv[]) { TIME_END(reduce); Nfa minimized_aut; - TIME_BEGIN(minimize); + TIME_BEGIN(make_minimal_dfa); // > START OF PROFILED CODE // Only minimize and its callees will be measured - mata::nfa::plumbing::minimize(&minimized_aut, aut); + mata::nfa::plumbing::make_minimal_dfa(&minimized_aut, aut); // > END OF PROFILED CODE - TIME_END(minimize); + TIME_END(make_minimal_dfa); Nfa det_aut; TIME_BEGIN(determinize); diff --git a/tests/nfa/nfa-plumbing.cc b/tests/nfa/nfa-plumbing.cc index c85dc81cc..5d9c13a99 100644 --- a/tests/nfa/nfa-plumbing.cc +++ b/tests/nfa/nfa-plumbing.cc @@ -109,7 +109,7 @@ TEST_CASE("Mata::nfa::Plumbing") { SECTION("Mata::nfa::Plumbing::minimize") { FILL_WITH_AUT_A(lhs); - mata::nfa::plumbing::minimize(&result, lhs); + mata::nfa::plumbing::make_minimal_dfa(&result, lhs); CHECK(!result.is_lang_empty()); } diff --git a/tests/nfa/nfa.cc b/tests/nfa/nfa.cc index 2213f4edb..0b13d8114 100644 --- a/tests/nfa/nfa.cc +++ b/tests/nfa/nfa.cc @@ -1017,7 +1017,7 @@ TEST_CASE("mata::nfa::minimize() for profiling", "[.profiling],[minimize]") { aut.delta.add(3, 110, 3); aut.delta.add(3, 111, 3); aut.delta.add(3, 114, 3); - minimize(&result, aut); + make_minimal_dfa(&result, aut); } TEST_CASE("mata::nfa::construct() correct calls") From fa8f618001dc340feaaf326856629ae0c392eed5 Mon Sep 17 00:00:00 2001 From: koniksedy Date: Tue, 3 Dec 2024 10:56:30 +0100 Subject: [PATCH 3/6] comment update --- include/mata/nfa/nfa.hh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mata/nfa/nfa.hh b/include/mata/nfa/nfa.hh index 78eb7fef6..59402ec69 100644 --- a/include/mata/nfa/nfa.hh +++ b/include/mata/nfa/nfa.hh @@ -671,7 +671,7 @@ Nfa complement(const Nfa& aut, const utils::OrdVector& symbols, * * @param[in] aut NFA whose minimal version to compute. * @param[in] params Optional parameters to control the minimization algorithm: - * - "algorithm": "hopcroft", "brzozowski" (Default: "brzozowski") + * - "algorithm": "brzozowski" (Default: "brzozowski") * @return Minimal deterministic automaton. */ Nfa make_minimal_dfa(const Nfa &nfa, const ParameterMap& params = { { "algorithm", "brzozowski" } }); From 8f8b3cf4d95d156b5e9adfb9cc9162e9c8e4e301 Mon Sep 17 00:00:00 2001 From: koniksedy Date: Tue, 3 Dec 2024 10:58:19 +0100 Subject: [PATCH 4/6] remove enum class --- include/mata/nfa/types.hh | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/include/mata/nfa/types.hh b/include/mata/nfa/types.hh index e682cac0e..9d19143f2 100644 --- a/include/mata/nfa/types.hh +++ b/include/mata/nfa/types.hh @@ -43,23 +43,6 @@ public: static const Symbol max_symbol = std::numeric_limits::max(); }; -/** - * @brief Properties of an automaton. - */ -enum class AutomatonProperty { - Trimmed, ///< Automaton has only useful states (i.e., reachable from initial states and leading to final states). - Complete, ///< Automaton is complete (i.e., every state has an outgoing transition for every symbol). - Minimal ///< Automaton is minimal. -}; - -/** - * @brief Type of an automaton (NFA or DFA). - */ -enum class AutomatonType { - Nfa, ///< Non-deterministic finite automaton. - Dfa ///< Deterministic finite automaton. -}; - class Nfa; ///< A non-deterministic finite automaton. /// An epsilon symbol which is now defined as the maximal value of data type used for symbols. From f84c984be5ba44a355b6da58b8b6d7547afe2d20 Mon Sep 17 00:00:00 2001 From: koniksedy Date: Tue, 3 Dec 2024 15:30:28 +0100 Subject: [PATCH 5/6] nested if --- src/nfa/operations.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/nfa/operations.cc b/src/nfa/operations.cc index 454670f74..cdbac9459 100644 --- a/src/nfa/operations.cc +++ b/src/nfa/operations.cc @@ -967,10 +967,12 @@ Nfa mata::nfa::minimize(const Nfa &dfa, const ParameterMap& params) } // Hopcroft algorithm does not work with non-trimmed automata. - const BoolVector is_used = dfa.get_useful_states(); - bool is_trimmed = std::all_of(is_used.begin(), is_used.end(), [](bool b) { return b; }); - if (str_algo == "hopcroft" && !is_trimmed) { - return algo(Nfa(dfa).trim()); + if (str_algo == "hopcroft") { + const BoolVector is_used = dfa.get_useful_states(); + bool is_trimmed = std::all_of(is_used.begin(), is_used.end(), [](bool b) { return b; }); + if (!is_trimmed) { + return algo(Nfa(dfa).trim()); + } } return algo(dfa); } From 714ab67e4a77c48f187e15741b60520a6f02ee46 Mon Sep 17 00:00:00 2001 From: koniksedy Date: Wed, 4 Dec 2024 12:55:59 +0100 Subject: [PATCH 6/6] chenge comment --- src/nfa/operations.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nfa/operations.cc b/src/nfa/operations.cc index cdbac9459..ac6996a38 100644 --- a/src/nfa/operations.cc +++ b/src/nfa/operations.cc @@ -934,7 +934,7 @@ Nfa mata::nfa::make_minimal_dfa(const Nfa& nfa, const ParameterMap& params) { "received: " + std::to_string(params)); } - // Setting the algorithm. Default is Hopcroft. + // Setting the algorithm. Default is Brzozowski. const std::string& str_algo = params.at("algorithm"); decltype(algorithms::minimize_brzozowski)* algo = algorithms::minimize_brzozowski; if (str_algo == "brzozowski") { /* default */ }