Implemented advanced simplification (some formulas not covered yet).

This commit is contained in:
Patrick Lühne 2017-03-17 02:42:48 +01:00
parent fc538eb7fc
commit bf8cf75369
Signed by: patrick
GPG Key ID: 05F3611E97A70ABF

View File

@ -1,5 +1,7 @@
#include <anthem/Simplification.h> #include <anthem/Simplification.h>
#include <iostream>
namespace anthem namespace anthem
{ {
@ -11,75 +13,196 @@ namespace anthem
bool isPrimitiveTerm(const ast::Term &term) bool isPrimitiveTerm(const ast::Term &term)
{ {
const auto binaryOperationIsNotPrimitiveTerm = const auto handleBinaryOperation =
[](const ast::BinaryOperationPointer &) [](const ast::BinaryOperationPointer &)
{ {
return false; return false;
}; };
const auto intervalIsNotPrimitiveTerm = const auto handleInterval =
[](const ast::IntervalPointer &) [](const ast::IntervalPointer &)
{ {
return false; return false;
}; };
const auto defaultIsPrimitiveTerm = const auto handleDefault =
[](const auto &) [](const auto &)
{ {
return true; return true;
}; };
return term.match(binaryOperationIsNotPrimitiveTerm, intervalIsNotPrimitiveTerm, defaultIsPrimitiveTerm); return term.match(handleBinaryOperation, handleInterval, handleDefault);
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
ast::Formula simplifyFormula(ast::Formula &&formula) bool matchesVariable(const ast::Term &term, const ast::VariablePointer &variable)
{ {
const auto simplifyAnd = const auto handleVariable =
[&](const ast::VariablePointer &other)
{
return variable->name == other->name;
};
const auto handleDefault =
[](const auto &)
{
return false;
};
return term.match(handleVariable, handleDefault);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
std::experimental::optional<ast::Term> extractAssignedTerm(ast::Formula &formula, const ast::VariablePointer &variable)
{
const auto handleComparison =
[&](ast::ComparisonPointer &comparison) -> std::experimental::optional<ast::Term>
{
if (comparison->operator_ != ast::Comparison::Operator::Equal)
return std::experimental::nullopt;
if (matchesVariable(comparison->left, variable))
return std::move(comparison->right);
if (matchesVariable(comparison->right, variable))
return std::move(comparison->left);
return std::experimental::nullopt;
};
const auto handleDefault =
[](auto &) -> std::experimental::optional<ast::Term>
{
return std::experimental::nullopt;
};
return formula.match(handleComparison, handleDefault);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ast::Formula simplify(ast::ExistsPointer &exists)
{
if (!exists->argument.is<ast::AndPointer>())
return std::move(exists);
auto &conjunction = exists->argument.get_unchecked<ast::AndPointer>();
auto &arguments = conjunction->arguments;
// Check that formula is in normal form
if (!arguments.back().is<ast::PredicatePointer>())
return std::move(exists);
const auto replaceVariableInPredicateWithTerm =
[](ast::PredicatePointer &predicate, const ast::VariablePointer &variable, ast::Term &&term)
{
for (auto &argument : predicate->arguments)
{
if (!matchesVariable(argument, variable))
continue;
argument = std::move(term);
break;
}
};
// Simplify formulas of type “exists X (X = t and F(Y))” to “F(t)”
for (auto i = exists->variables.begin(); i != exists->variables.end();)
{
auto &variable = *i;
bool wasVariableReplaced = false;
for (auto j = arguments.begin(); j != arguments.end(); j++)
{
auto &argument = *j;
auto assignedTerm = extractAssignedTerm(argument, variable);
if (!assignedTerm)
continue;
auto &lastArgument = arguments.back().get_unchecked<ast::PredicatePointer>();
// If this argument is an assignment of the variable to some other term, remove the assignment and replace the variable with the other term
replaceVariableInPredicateWithTerm(lastArgument, variable, std::move(assignedTerm.value()));
arguments.erase(j);
wasVariableReplaced = true;
break;
}
if (wasVariableReplaced)
{
i = exists->variables.erase(i);
continue;
}
i++;
}
if (exists->variables.empty())
{
assert(!conjunction->arguments.empty());
if (conjunction->arguments.size() == 1)
return std::move(conjunction->arguments.front());
return std::move(exists->argument);
}
return std::move(exists);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ast::Formula simplify(ast::Formula &&formula)
{
const auto handleAnd =
[&](ast::AndPointer &and_) -> ast::Formula [&](ast::AndPointer &and_) -> ast::Formula
{ {
for (auto &argument : and_->arguments) for (auto &argument : and_->arguments)
argument = simplifyFormula(std::move(argument)); argument = simplify(std::move(argument));
return std::move(and_); return std::move(and_);
}; };
const auto simplifyBiconditional = const auto handleBiconditional =
[&](ast::BiconditionalPointer &biconditional) -> ast::Formula [&](ast::BiconditionalPointer &biconditional) -> ast::Formula
{ {
biconditional->left = simplifyFormula(std::move(biconditional->left)); biconditional->left = simplify(std::move(biconditional->left));
biconditional->right = simplifyFormula(std::move(biconditional->right)); biconditional->right = simplify(std::move(biconditional->right));
return std::move(biconditional); return std::move(biconditional);
}; };
const auto simplifyExists = const auto handleExists =
[&](ast::ExistsPointer &exists) -> ast::Formula [&](ast::ExistsPointer &exists) -> ast::Formula
{ {
exists->argument = simplifyFormula(std::move(exists->argument)); exists->argument = simplify(std::move(exists->argument));
return std::move(exists); return simplify(exists);
}; };
const auto simplifyForAll = const auto handleForAll =
[&](ast::ForAllPointer &forAll) -> ast::Formula [&](ast::ForAllPointer &forAll) -> ast::Formula
{ {
forAll->argument = simplifyFormula(std::move(forAll->argument)); forAll->argument = simplify(std::move(forAll->argument));
return std::move(forAll); return std::move(forAll);
}; };
const auto simplifyImplies = const auto handleImplies =
[&](ast::ImpliesPointer &implies) -> ast::Formula [&](ast::ImpliesPointer &implies) -> ast::Formula
{ {
implies->antecedent = simplifyFormula(std::move(implies->antecedent)); implies->antecedent = simplify(std::move(implies->antecedent));
implies->consequent = simplifyFormula(std::move(implies->consequent)); implies->consequent = simplify(std::move(implies->consequent));
return std::move(implies); return std::move(implies);
}; };
const auto simplifyIn = const auto handleIn =
[](ast::InPointer &in) -> ast::Formula [](ast::InPointer &in) -> ast::Formula
{ {
if (!isPrimitiveTerm(in->element) || !isPrimitiveTerm(in->set)) if (!isPrimitiveTerm(in->element) || !isPrimitiveTerm(in->set))
@ -89,37 +212,30 @@ ast::Formula simplifyFormula(ast::Formula &&formula)
return std::make_unique<ast::Comparison>(ast::Comparison::Operator::Equal, std::move(in->element), std::move(in->set)); return std::make_unique<ast::Comparison>(ast::Comparison::Operator::Equal, std::move(in->element), std::move(in->set));
}; };
const auto simplifyNot = const auto handleNot =
[&](ast::NotPointer &not_) -> ast::Formula [&](ast::NotPointer &not_) -> ast::Formula
{ {
not_->argument = simplifyFormula(std::move(not_->argument)); not_->argument = simplify(std::move(not_->argument));
return std::move(not_); return std::move(not_);
}; };
const auto simplifyOr = const auto handleOr =
[&](ast::OrPointer &or_) -> ast::Formula [&](ast::OrPointer &or_) -> ast::Formula
{ {
for (auto &argument : or_->arguments) for (auto &argument : or_->arguments)
argument = simplifyFormula(std::move(argument)); argument = simplify(std::move(argument));
return std::move(or_); return std::move(or_);
}; };
const auto defaultDoNothing = const auto handleDefault =
[&](auto &x) -> ast::Formula [&](auto &x) -> ast::Formula
{ {
return std::move(x); return std::move(x);
}; };
return formula.match(simplifyAnd, simplifyBiconditional, simplifyExists, simplifyForAll, simplifyImplies, simplifyIn, simplifyNot, simplifyOr, defaultDoNothing); return formula.match(handleAnd, handleBiconditional, handleExists, handleForAll, handleImplies, handleIn, handleNot, handleOr, handleDefault);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ast::Formula simplify(ast::Formula &&formula)
{
return simplifyFormula(std::move(formula));
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////