Fixed incorrect handling of implications with Booleans.
This commit is contained in:
parent
2ef3ef24a1
commit
37526bcc8e
@ -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);
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user