Fixed incorrect handling of implications with Booleans.

This commit is contained in:
Patrick Lühne 2017-04-08 20:17:01 +02:00
parent 2ef3ef24a1
commit 37526bcc8e
Signed by: patrick
GPG Key ID: 05F3611E97A70ABF
3 changed files with 60 additions and 15 deletions

View File

@ -102,6 +102,11 @@ struct BodyTermTranslateVisitor
struct BodyLiteralTranslateVisitor struct BodyLiteralTranslateVisitor
{ {
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Boolean &boolean, const Clingo::AST::Literal &, Context &)
{
return ast::Formula::make<ast::Boolean>(boolean.value);
}
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Term &term, const Clingo::AST::Literal &literal, Context &context) std::experimental::optional<ast::Formula> visit(const Clingo::AST::Term &term, const Clingo::AST::Literal &literal, Context &context)
{ {
return term.data.accept(BodyTermTranslateVisitor(), literal, term, context); return term.data.accept(BodyTermTranslateVisitor(), literal, term, context);

View File

@ -24,10 +24,10 @@ void checkMatchingPredicates(const ast::Term &lhs, const ast::Term &rhs)
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
void completePredicate(const ast::Predicate &predicate, std::vector<ast::Formula> &formulas, std::size_t formulasBegin) void completePredicate(const ast::Predicate &predicate, std::vector<ast::Formula> &formulas, std::size_t &formulaIndex)
{ {
// Check that predicate is in normal form // Check that predicate is in normal form
for (auto i = formulasBegin; i < formulas.size(); i++) for (auto i = formulaIndex; i < formulas.size(); i++)
{ {
auto &formula = formulas[i]; auto &formula = formulas[i];
assert(formula.is<ast::Implies>()); assert(formula.is<ast::Implies>());
@ -58,7 +58,7 @@ void completePredicate(const ast::Predicate &predicate, std::vector<ast::Formula
auto or_ = ast::Formula::make<ast::Or>(); auto or_ = ast::Formula::make<ast::Or>();
// Build the conjunction of all formulas with the predicate as consequent // Build the conjunction of all formulas with the predicate as consequent
for (auto i = formulasBegin; i < formulas.size();) for (auto i = formulaIndex; i < formulas.size();)
{ {
auto &formula = formulas[i]; auto &formula = formulas[i];
assert(formula.is<ast::Implies>()); assert(formula.is<ast::Implies>());
@ -91,33 +91,53 @@ void completePredicate(const ast::Predicate &predicate, std::vector<ast::Formula
or_.get<ast::Or>().arguments.emplace_back(std::move(exists)); or_.get<ast::Or>().arguments.emplace_back(std::move(exists));
} }
if (i > formulasBegin) if (i > formulaIndex)
formulas.erase(formulas.begin() + i); formulas.erase(formulas.begin() + i);
else else
i++; i++;
} }
if (or_.get<ast::Or>().arguments.size() == 1) auto biconditionalRight = std::move(or_);
or_ = or_.get<ast::Or>().arguments.front();
// If the disjunction contains only one element, drop the enclosing disjunction
if (biconditionalRight.get<ast::Or>().arguments.size() == 1)
biconditionalRight = biconditionalRight.get<ast::Or>().arguments.front();
// If the biconditional would be of the form “F <-> true” or “F <-> false,” simplify the output
if (biconditionalRight.is<ast::Boolean>())
{
const auto &boolean = biconditionalRight.get<ast::Boolean>();
if (boolean.value == true)
formulas[formulaIndex] = ast::deepCopy(predicate);
else
formulas[formulaIndex] = ast::Formula::make<ast::Not>(ast::deepCopy(predicate));
formulaIndex++;
return;
}
// Build the biconditional within the completed formula // Build the biconditional within the completed formula
auto biconditional = ast::Formula::make<ast::Biconditional>(ast::deepCopy(predicate), std::move(or_)); auto biconditional = ast::Formula::make<ast::Biconditional>(ast::deepCopy(predicate), std::move(biconditionalRight));
if (predicate.arguments.empty()) if (predicate.arguments.empty())
{ {
formulas[formulasBegin] = std::move(biconditional); formulas[formulaIndex] = std::move(biconditional);
formulaIndex++;
return; return;
} }
auto completedFormula = ast::Formula::make<ast::ForAll>(std::move(variables), std::move(biconditional)); auto completedFormula = ast::Formula::make<ast::ForAll>(std::move(variables), std::move(biconditional));
formulas[formulasBegin] = std::move(completedFormula); formulas[formulaIndex] = std::move(completedFormula);
formulaIndex++;
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
void completeBoolean(ast::Formula &formula) void completeBoolean(std::vector<ast::Formula> &formulas, std::size_t &formulaIndex)
{ {
auto &formula = formulas[formulaIndex];
assert(formula.is<ast::Implies>()); assert(formula.is<ast::Implies>());
auto &implies = formula.get<ast::Implies>(); auto &implies = formula.get<ast::Implies>();
assert(implies.consequent.is<ast::Boolean>()); assert(implies.consequent.is<ast::Boolean>());
@ -125,17 +145,24 @@ void completeBoolean(ast::Formula &formula)
auto variables = ast::collectFreeVariables(implies.antecedent); auto variables = ast::collectFreeVariables(implies.antecedent);
auto argument = (boolean.value == true) // Implications of the form “T -> true” are useless
? std::move(implies.antecedent) if (boolean.value == true)
: ast::Formula::make<ast::Not>(std::move(implies.antecedent)); {
formulas.erase(formulas.begin() + formulaIndex);
return;
}
auto argument = ast::Formula::make<ast::Not>(std::move(implies.antecedent));
if (variables.empty()) if (variables.empty())
{ {
formula = std::move(argument); formula = std::move(argument);
formulaIndex++;
return; return;
} }
formula = ast::Formula::make<ast::ForAll>(std::move(variables), std::move(argument)); formula = ast::Formula::make<ast::ForAll>(std::move(variables), std::move(argument));
formulaIndex++;
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
@ -153,7 +180,7 @@ void complete(std::vector<ast::Formula> &formulas)
throw std::runtime_error("cannot perform completion, only single predicates and Booleans supported as formula consequent currently"); throw std::runtime_error("cannot perform completion, only single predicates and Booleans supported as formula consequent currently");
} }
for (std::size_t i = 0; i < formulas.size(); i++) for (std::size_t i = 0; i < formulas.size();)
{ {
auto &formula = formulas[i]; auto &formula = formulas[i];
auto &implies = formula.get<ast::Implies>(); auto &implies = formula.get<ast::Implies>();
@ -164,7 +191,7 @@ void complete(std::vector<ast::Formula> &formulas)
completePredicate(predicate, formulas, i); completePredicate(predicate, formulas, i);
} }
else if (implies.consequent.is<ast::Boolean>()) else if (implies.consequent.is<ast::Boolean>())
completeBoolean(formula); completeBoolean(formulas, i);
} }
} }

View File

@ -69,4 +69,17 @@ TEST_CASE("[completion] Rules are completed", "[completion]")
CHECK(output.str() == "q\nr\nt\ns\n"); CHECK(output.str() == "q\nr\nt\ns\n");
} }
SECTION("useless implications")
{
input << "#true :- p, q(N), t(1, 2).\n"
"#true.\n"
"h :- #false.";
REQUIRE_NOTHROW(anthem::translate("input", input, context));
// TODO: implement completion for unused predicates
CHECK(output.str() == "not h\n");
}
// TODO: test collecting free variables
} }