diff --git a/src/anthem/Simplification.cpp b/src/anthem/Simplification.cpp index abb2bc6..cd3b6d5 100644 --- a/src/anthem/Simplification.cpp +++ b/src/anthem/Simplification.cpp @@ -430,6 +430,42 @@ struct SimplificationRuleDeMorganForConjunctions //////////////////////////////////////////////////////////////////////////////////////////////////// +struct SimplificationRuleImplicationFromDisjunction +{ + static constexpr const auto Description = "(not F or G) === (F -> G)"; + + static SimplificationResult apply(ast::Formula &formula) + { + if (!formula.is()) + return SimplificationResult::Unchanged; + + auto &or_ = formula.get(); + + if (or_.arguments.size() != 2) + return SimplificationResult::Unchanged; + + const auto leftIsNot = or_.arguments[0].is(); + const auto rightIsNot = or_.arguments[1].is(); + + if (leftIsNot == rightIsNot) + return SimplificationResult::Unchanged; + + auto &negativeSide = leftIsNot ? or_.arguments[0] : or_.arguments[1]; + auto &positiveSide = leftIsNot ? or_.arguments[1] : or_.arguments[0]; + + assert(negativeSide.is()); + assert(!positiveSide.is()); + + auto &negativeSideArgument = negativeSide.get().argument; + + formula = ast::Formula::make(std::move(negativeSideArgument), std::move(positiveSide)); + + return SimplificationResult::Simplified; + } +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + const auto simplifyWithDefaultRules = simplify < @@ -442,7 +478,8 @@ const auto simplifyWithDefaultRules = SimplificationRuleExistsWithoutQuantifiedVariables, SimplificationRuleInWithPrimitiveArguments, SimplificationRuleSubsumptionInBiconditionals, - SimplificationRuleDeMorganForConjunctions + SimplificationRuleDeMorganForConjunctions, + SimplificationRuleImplicationFromDisjunction >; //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/tests/TestCompletion.cpp b/tests/TestCompletion.cpp index a5bad75..eebcb01 100644 --- a/tests/TestCompletion.cpp +++ b/tests/TestCompletion.cpp @@ -153,7 +153,7 @@ TEST_CASE("[completion] Rules are completed", "[completion]") CHECK(output.str() == "forall V1 (covered(V1) <-> exists U1 in(V1, U1))\n" "forall V2, V3 (in(V2, V3) -> (V2 in 1..n and V3 in 1..r))\n" - "forall U2 (not U2 in 1..n or covered(U2))\n" + "forall U2 (U2 in 1..n -> covered(U2))\n" "forall U3, U4, U5 (not in(U3, U4) or not in(U5, U4) or not exists X1 (X1 in (U3 + U5) and in(X1, U4)))\n"); } diff --git a/tests/TestHiddenPredicateElimination.cpp b/tests/TestHiddenPredicateElimination.cpp index 3b4fcf1..3e33c30 100644 --- a/tests/TestHiddenPredicateElimination.cpp +++ b/tests/TestHiddenPredicateElimination.cpp @@ -168,7 +168,7 @@ TEST_CASE("[hidden predicate elimination] Hidden predicates are correctly elimin CHECK(output.str() == "(s -> not #false)\n" "(t -> not #false)\n" - "(not s or t)\n" + "(s -> t)\n" "(#false or #false or not #false)\n"); } diff --git a/tests/TestPlaceholders.cpp b/tests/TestPlaceholders.cpp index 3ce361f..8375eaf 100644 --- a/tests/TestPlaceholders.cpp +++ b/tests/TestPlaceholders.cpp @@ -56,7 +56,7 @@ TEST_CASE("[placeholders] Programs with placeholders are correctly completed", " CHECK(output.str() == "forall V1, V2 (color(V1, V2) -> (vertex(V1) and color(V2)))\n" - "forall U1 (not vertex(U1) or exists U2 color(U1, U2))\n" + "forall U1 (vertex(U1) -> exists U2 color(U1, U2))\n" "forall U3, U4, U5 (not color(U3, U4) or not color(U5, U4) or not edge(U3, U5))\n"); } }