From 8d512979ca876a66674c14fd4dcf634cd0932fad Mon Sep 17 00:00:00 2001 From: jurajsic Date: Tue, 15 Apr 2025 14:31:25 +0200 Subject: [PATCH 1/2] add enum arguments for reduce() --- include/mata/nfa/algorithms.hh | 2 +- include/mata/nfa/nfa.hh | 6 ++- include/mata/nfa/plumbing.hh | 5 ++- src/nfa/operations.cc | 56 ++++++++------------------- tests/nfa/nfa.cc | 71 ++++++---------------------------- 5 files changed, 38 insertions(+), 102 deletions(-) diff --git a/include/mata/nfa/algorithms.hh b/include/mata/nfa/algorithms.hh index f3b993ba0..6c8381539 100644 --- a/include/mata/nfa/algorithms.hh +++ b/include/mata/nfa/algorithms.hh @@ -148,7 +148,7 @@ Nfa reduce_simulation(const Nfa& nfa, StateRenaming &state_renaming); * @param[in] direction Direction of the residual construction (values: "forward", "backward"). */ Nfa reduce_residual(const Nfa& nfa, StateRenaming &state_renaming, - const std::string& type, const std::string& direction); + const std::string& type, ReductionDirection direction); /** * @brief Reduce NFA using residual construction. diff --git a/include/mata/nfa/nfa.hh b/include/mata/nfa/nfa.hh index 70b272469..bef7aff85 100644 --- a/include/mata/nfa/nfa.hh +++ b/include/mata/nfa/nfa.hh @@ -788,6 +788,9 @@ Nfa determinize( const Nfa& aut, std::unordered_map *subset_map = nullptr, std::optional> macrostate_discover = std::nullopt); +enum class ReductionAlgorithm { SIMULATION, RESIDUAL_AFTER, RESIDUAL_WITH }; +enum class ReductionDirection { FORWARD, BACKWARD }; + /** * @brief Reduce the size of the automaton. * @@ -801,7 +804,8 @@ Nfa determinize( * @return Reduced automaton. */ Nfa reduce(const Nfa &aut, StateRenaming *state_renaming = nullptr, - const ParameterMap& params = {{ "algorithm", "simulation" }, { "type", "after" }, { "direction", "forward" } }); + ReductionAlgorithm reduction_algorithm = ReductionAlgorithm::SIMULATION, + ReductionDirection direction = ReductionDirection::FORWARD); /** * @brief Checks inclusion of languages of two NFAs: @p smaller and @p bigger (smaller <= bigger). diff --git a/include/mata/nfa/plumbing.hh b/include/mata/nfa/plumbing.hh index 94f39ee46..dc45884b9 100644 --- a/include/mata/nfa/plumbing.hh +++ b/include/mata/nfa/plumbing.hh @@ -44,8 +44,9 @@ inline void determinize(Nfa* result, const Nfa& aut, std::unordered_map reduced_state_map; - const std::string& algorithm = params.at("algorithm"); - if ("simulation" == algorithm) { - result = algorithms::reduce_simulation(aut, reduced_state_map); - } - else if ("residual" == algorithm) { - // reduce type either 'after' or 'with' creation of residual automaton - if (!haskey(params, "type")) { - throw std::runtime_error(std::to_string(__func__) + - " requires setting the \"type\" key in the \"params\" argument; " - "received: " + std::to_string(params)); - } - // forward or backward canonical residual automaton - if (!haskey(params, "direction")) { - throw std::runtime_error(std::to_string(__func__) + - " requires setting the \"direction\" key in the \"params\" argument; " - "received: " + std::to_string(params)); - } - const std::string& residual_type = params.at("type"); - const std::string& residual_direction = params.at("direction"); - - result = algorithms::reduce_residual(aut, reduced_state_map, residual_type, residual_direction); - } else { - throw std::runtime_error(std::to_string(__func__) + - " received an unknown value of the \"algorithm\" key: " + algorithm); + switch(reduction_algorithm) { + case ReductionAlgorithm::SIMULATION: + result = algorithms::reduce_simulation(aut, reduced_state_map); + break; + case ReductionAlgorithm::RESIDUAL_AFTER: + result = algorithms::reduce_residual(aut, reduced_state_map, "after", direction); + break; + case ReductionAlgorithm::RESIDUAL_WITH: + result = algorithms::reduce_residual(aut, reduced_state_map, "with", direction); + break; + default: + throw std::runtime_error(std::to_string(__func__) + + " received an unknown value of the \"reduction_algorithm\" key"); } if (state_renaming) { @@ -1617,20 +1600,15 @@ Nfa mata::nfa::algorithms::reduce_simulation(const Nfa& aut, StateRenaming &stat return result; } -Nfa mata::nfa::algorithms::reduce_residual(const Nfa& nfa, StateRenaming &state_renaming, const std::string& type, const std::string& direction) { +Nfa mata::nfa::algorithms::reduce_residual(const Nfa& nfa, StateRenaming &state_renaming, const std::string& type, ReductionDirection direction) { Nfa back_determinized = nfa; Nfa result; - if (direction != "forward" && direction != "backward"){ - throw std::runtime_error(std::to_string(__func__) + - " received an unknown value of the \"direction\" key: " + direction); - } - // forward canonical residual automaton is firstly backward determinized and // then the residual construction is done forward, for backward residual automaton // is it the opposite, so the automaton is reverted once more before and after // construction, however the first two reversion negate each other out - if (direction == "forward") + if (direction == ReductionDirection::FORWARD) back_determinized = revert(back_determinized); back_determinized = revert(determinize(back_determinized)); // backward deteminization @@ -1653,7 +1631,7 @@ Nfa mata::nfa::algorithms::reduce_residual(const Nfa& nfa, StateRenaming &state_ " received an unknown value of the \"type\" key: " + type); } - if (direction == "backward") + if (direction == ReductionDirection::BACKWARD) result = revert(result); return result.trim(); diff --git a/tests/nfa/nfa.cc b/tests/nfa/nfa.cc index cfbe7845f..b89d37c29 100644 --- a/tests/nfa/nfa.cc +++ b/tests/nfa/nfa.cc @@ -3288,19 +3288,11 @@ TEST_CASE("mata::nfa::algorithms::minimize_hopcroft()") { TEST_CASE("mata::nfa::reduce_size_by_residual()") { Nfa aut; StateRenaming state_renaming; - ParameterMap params_after, params_with; - params_after["algorithm"] = "residual"; - params_with["algorithm"] = "residual"; SECTION("empty automaton") { - params_after["type"] = "after"; - params_after["direction"] = "forward"; - params_with["type"] = "with"; - params_with["direction"] = "forward"; - - Nfa result_after = reduce(aut, &state_renaming, params_after); - Nfa result_with = reduce(aut, &state_renaming, params_with); + Nfa result_after = reduce(aut, &state_renaming, ReductionAlgorithm::RESIDUAL_AFTER); + Nfa result_with = reduce(aut, &state_renaming, ReductionAlgorithm::RESIDUAL_WITH); REQUIRE(result_after.delta.empty()); REQUIRE(result_after.initial.empty()); @@ -3311,16 +3303,12 @@ TEST_CASE("mata::nfa::reduce_size_by_residual()") { SECTION("simple automaton") { - params_after["type"] = "after"; - params_after["direction"] = "forward"; - params_with["type"] = "with"; - params_with["direction"] = "forward"; aut.add_state(2); aut.initial.insert(1); aut.final.insert(2); - Nfa result_after = reduce(aut, &state_renaming, params_after); - Nfa result_with = reduce(aut, &state_renaming, params_with); + Nfa result_after = reduce(aut, &state_renaming, ReductionAlgorithm::RESIDUAL_AFTER); + Nfa result_with = reduce(aut, &state_renaming, ReductionAlgorithm::RESIDUAL_WITH); REQUIRE(result_after.num_of_states() == 0); REQUIRE(result_after.initial.empty()); @@ -3330,8 +3318,8 @@ TEST_CASE("mata::nfa::reduce_size_by_residual()") { REQUIRE(are_equivalent(aut, result_after)); aut.delta.add(1, 'a', 2); - result_after = reduce(aut, &state_renaming, params_after); - result_with = reduce(aut, &state_renaming, params_with); + result_after = reduce(aut, &state_renaming, ReductionAlgorithm::RESIDUAL_AFTER); + result_with = reduce(aut, &state_renaming, ReductionAlgorithm::RESIDUAL_WITH); REQUIRE(result_after.num_of_states() == 2); REQUIRE(result_after.initial[0]); @@ -3343,10 +3331,6 @@ TEST_CASE("mata::nfa::reduce_size_by_residual()") { SECTION("medium automaton") { - params_after["type"] = "after"; - params_after["direction"] = "forward"; - params_with["type"] = "with"; - params_with["direction"] = "forward"; aut.add_state(4); aut.initial = { 1 }; @@ -3359,8 +3343,8 @@ TEST_CASE("mata::nfa::reduce_size_by_residual()") { aut.delta.add(3, 'a', 3); aut.delta.add(2, 'a', 1); - Nfa result_after = reduce(aut, &state_renaming, params_after); - Nfa result_with = reduce(aut, &state_renaming, params_with); + Nfa result_after = reduce(aut, &state_renaming, ReductionAlgorithm::RESIDUAL_AFTER); + Nfa result_with = reduce(aut, &state_renaming, ReductionAlgorithm::RESIDUAL_WITH); REQUIRE(result_after.num_of_states() == 4); REQUIRE(result_after.initial[0]); @@ -3380,10 +3364,6 @@ TEST_CASE("mata::nfa::reduce_size_by_residual()") { SECTION("big automaton") { - params_after["type"] = "after"; - params_after["direction"] = "forward"; - params_with["type"] = "with"; - params_with["direction"] = "forward"; aut.add_state(7); aut.initial = { 0 }; @@ -3423,8 +3403,8 @@ TEST_CASE("mata::nfa::reduce_size_by_residual()") { aut.delta.add(6, 'c', 1); aut.delta.add(6, 'd', 1); - Nfa result_after = reduce(aut, &state_renaming, params_after); - Nfa result_with = reduce(aut, &state_renaming, params_with); + Nfa result_after = reduce(aut, &state_renaming, ReductionAlgorithm::RESIDUAL_AFTER); + Nfa result_with = reduce(aut, &state_renaming, ReductionAlgorithm::RESIDUAL_WITH); REQUIRE(result_after.num_of_states() == 5); REQUIRE(result_after.initial[0]); @@ -3485,11 +3465,6 @@ TEST_CASE("mata::nfa::reduce_size_by_residual()") { SECTION("backward residual big automaton") { - params_after["type"] = "after"; - params_after["direction"] = "backward"; - params_with["type"] = "with"; - params_with["direction"] = "backward"; - aut.add_state(7); aut.initial = { 0 }; @@ -3529,8 +3504,8 @@ TEST_CASE("mata::nfa::reduce_size_by_residual()") { aut.delta.add(6, 'c', 1); aut.delta.add(6, 'd', 1); - Nfa result_after = reduce(aut, &state_renaming, params_after); - Nfa result_with = reduce(aut, &state_renaming, params_with); + Nfa result_after = reduce(aut, &state_renaming, ReductionAlgorithm::RESIDUAL_AFTER, ReductionDirection::BACKWARD); + Nfa result_with = reduce(aut, &state_renaming, ReductionAlgorithm::RESIDUAL_WITH, ReductionDirection::BACKWARD); REQUIRE(result_after.num_of_states() == 6); REQUIRE(result_after.initial[0]); @@ -3562,28 +3537,6 @@ TEST_CASE("mata::nfa::reduce_size_by_residual()") { REQUIRE(are_equivalent(aut, result_after)); } - - SECTION("error checking") - { - CHECK_THROWS_WITH(reduce(aut, &state_renaming, params_after), - Catch::Matchers::ContainsSubstring("requires setting the \"type\" key in the \"params\" argument;")); - - params_after["type"] = "bad_type"; - CHECK_THROWS_WITH(reduce(aut, &state_renaming, params_after), - Catch::Matchers::ContainsSubstring("requires setting the \"direction\" key in the \"params\" argument;")); - - params_after["direction"] = "unknown_direction"; - CHECK_THROWS_WITH(reduce(aut, &state_renaming, params_after), - Catch::Matchers::ContainsSubstring("received an unknown value of the \"direction\" key")); - - params_after["direction"] = "forward"; - CHECK_THROWS_WITH(reduce(aut, &state_renaming, params_after), - Catch::Matchers::ContainsSubstring("received an unknown value of the \"type\" key")); - - params_after["type"] = "after"; - CHECK_NOTHROW(reduce(aut, &state_renaming, params_after)); - - } } TEST_CASE("mata::nfa::union_norename()") { From 1b37f6574ca68e877a4001f86f38c92bf58ecefa Mon Sep 17 00:00:00 2001 From: jurajsic Date: Tue, 15 Apr 2025 14:38:45 +0200 Subject: [PATCH 2/2] add direction option to reduce_simulation() --- include/mata/nfa/algorithms.hh | 2 +- src/nfa/operations.cc | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/include/mata/nfa/algorithms.hh b/include/mata/nfa/algorithms.hh index 6c8381539..b39b70a9e 100644 --- a/include/mata/nfa/algorithms.hh +++ b/include/mata/nfa/algorithms.hh @@ -137,7 +137,7 @@ Nfa concatenate_eps(const Nfa& lhs, const Nfa& rhs, const Symbol& epsilon, bool * @param[in] nfa NFA to reduce * @param[out] state_renaming Map mapping original states to the reduced states. */ -Nfa reduce_simulation(const Nfa& nfa, StateRenaming &state_renaming); +Nfa reduce_simulation(const Nfa& nfa, StateRenaming &state_renaming, ReductionDirection direction = ReductionDirection::FORWARD); /** * @brief Reduce NFA using residual construction. diff --git a/src/nfa/operations.cc b/src/nfa/operations.cc index 0474c368e..2e34ede85 100644 --- a/src/nfa/operations.cc +++ b/src/nfa/operations.cc @@ -1079,7 +1079,7 @@ Nfa mata::nfa::reduce(const Nfa &aut, StateRenaming *state_renaming, ReductionAl switch(reduction_algorithm) { case ReductionAlgorithm::SIMULATION: - result = algorithms::reduce_simulation(aut, reduced_state_map); + result = algorithms::reduce_simulation(aut, reduced_state_map, direction); break; case ReductionAlgorithm::RESIDUAL_AFTER: result = algorithms::reduce_residual(aut, reduced_state_map, "after", direction); @@ -1528,10 +1528,13 @@ std::optional mata::nfa::get_word_from_lang_difference(const Nfa & n }).get_word(); } -Nfa mata::nfa::algorithms::reduce_simulation(const Nfa& aut, StateRenaming &state_renaming) { +Nfa mata::nfa::algorithms::reduce_simulation(const Nfa& aut, StateRenaming &state_renaming, ReductionDirection direction) { Nfa result; - const auto sim_relation = algorithms::compute_relation( - aut, ParameterMap{{ "relation", "simulation"}, { "direction", "forward"}}); + if (direction != ReductionDirection::FORWARD) { + throw std::runtime_error(std::to_string(__func__) + + " can only reduce simulation by forward direction (for now)"); + } + const auto sim_relation = algorithms::compute_relation(aut, ParameterMap{{ "relation", "simulation"}, { "direction", "forward"}}); auto sim_relation_symmetric = sim_relation; sim_relation_symmetric.restrict_to_symmetric();