Refactor predicate representation

This refactoring separates predicates from their declarations. The
purpose of this is to avoid duplicating properties specific to the
predicate declaration and not its occurrences in the program.
This commit is contained in:
2018-04-13 20:40:40 +02:00
parent 87dcd6ee93
commit 2372eb24c4
15 changed files with 187 additions and 242 deletions

View File

@@ -204,13 +204,13 @@ struct Interval
struct Predicate
{
explicit Predicate(std::string &&name)
: name{std::move(name)}
explicit Predicate(PredicateDeclaration *declaration)
: declaration{declaration}
{
}
explicit Predicate(std::string &&name, std::vector<Term> &&arguments)
: name{std::move(name)},
explicit Predicate(PredicateDeclaration *declaration, std::vector<Term> &&arguments)
: declaration{declaration},
arguments{std::move(arguments)}
{
}
@@ -220,35 +220,37 @@ struct Predicate
Predicate(Predicate &&other) noexcept = default;
Predicate &operator=(Predicate &&other) noexcept = default;
std::size_t arity() const
{
return arguments.size();
}
std::string name;
PredicateDeclaration *declaration{nullptr};
std::vector<Term> arguments;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
// TODO: make more use of this class
struct PredicateSignature
struct PredicateDeclaration
{
explicit PredicateSignature(std::string &&name, size_t arity)
enum class Visibility
{
Default,
Visible,
Hidden
};
explicit PredicateDeclaration(std::string &&name, size_t arity)
: name{std::move(name)},
arity{arity}
{
}
PredicateSignature(const PredicateSignature &other) = delete;
PredicateSignature &operator=(const PredicateSignature &other) = delete;
// TODO: make noexcept again
// GCC versions before 7 dont declare moving std::string noexcept and would complain here
PredicateSignature(PredicateSignature &&other) = default;
PredicateSignature &operator=(PredicateSignature &&other) = default;
PredicateDeclaration(const PredicateDeclaration &other) = delete;
PredicateDeclaration &operator=(const PredicateDeclaration &other) = delete;
PredicateDeclaration(PredicateDeclaration &&other) noexcept = default;
PredicateDeclaration &operator=(PredicateDeclaration &&other) noexcept = default;
std::string name;
size_t arity;
bool isUsed{false};
bool isExternal{false};
Visibility visibility{Visibility::Default};
};
////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@@ -35,6 +35,7 @@ struct Interval;
struct Not;
struct Or;
struct Predicate;
struct PredicateDeclaration;
struct SpecialInteger;
struct String;
struct UnaryOperation;

View File

@@ -36,12 +36,6 @@ class VariableStack
std::vector<Layer> m_layers;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
bool matches(const Predicate &lhs, const Predicate &rhs);
bool matches(const Predicate &predicate, const PredicateSignature &signature);
bool matches(const PredicateSignature &lhs, const PredicateSignature &rhs);
void collectPredicateSignatures(const Formula &formula, std::vector<PredicateSignature> &predicateSignatures, Context &context);
////////////////////////////////////////////////////////////////////////////////////////////////////
// Replacing Variables

View File

@@ -43,19 +43,22 @@ ast::Comparison::Operator translate(Clingo::AST::ComparisonOperator comparisonOp
struct BodyTermTranslateVisitor
{
// TODO: refactor
std::optional<ast::Formula> visit(const Clingo::AST::Function &function, const Clingo::AST::Literal &literal, const Clingo::AST::Term &, RuleContext &ruleContext, ast::VariableStack &variableStack)
std::optional<ast::Formula> visit(const Clingo::AST::Function &function,
const Clingo::AST::Literal &literal, const Clingo::AST::Term &, RuleContext &ruleContext,
Context &context, ast::VariableStack &variableStack)
{
if (literal.sign == Clingo::AST::Sign::DoubleNegation)
throw TranslationException(literal.location, "double-negated literals currently unsupported");
auto predicateDeclaration = context.findOrCreatePredicateDeclaration(function.name, function.arguments.size());
predicateDeclaration->isUsed = true;
if (function.arguments.empty())
{
auto predicate = ast::Formula::make<ast::Predicate>(std::string(function.name));
if (literal.sign == Clingo::AST::Sign::None)
return std::move(predicate);
return ast::Predicate(predicateDeclaration);
else if (literal.sign == Clingo::AST::Sign::Negation)
return ast::Formula::make<ast::Not>(std::move(predicate));
return ast::Formula::make<ast::Not>(ast::Predicate(predicateDeclaration));
}
// Create new body variable declarations
@@ -78,7 +81,7 @@ struct BodyTermTranslateVisitor
variableStack.pop();
ast::Predicate predicate(std::string(function.name));
ast::Predicate predicate(predicateDeclaration);
predicate.arguments.reserve(function.arguments.size());
for (size_t i = 0; i < function.arguments.size(); i++)
@@ -93,7 +96,8 @@ struct BodyTermTranslateVisitor
}
template<class T>
std::optional<ast::Formula> visit(const T &, const Clingo::AST::Literal &, const Clingo::AST::Term &term, RuleContext &, ast::VariableStack &)
std::optional<ast::Formula> visit(const T &, const Clingo::AST::Literal &,
const Clingo::AST::Term &term, RuleContext &, Context &, ast::VariableStack &)
{
assert(!term.data.is<Clingo::AST::Function>());
@@ -106,18 +110,18 @@ struct BodyTermTranslateVisitor
struct BodyLiteralTranslateVisitor
{
std::optional<ast::Formula> visit(const Clingo::AST::Boolean &boolean, const Clingo::AST::Literal &, RuleContext &, ast::VariableStack &)
std::optional<ast::Formula> visit(const Clingo::AST::Boolean &boolean, const Clingo::AST::Literal &, RuleContext &, Context &, ast::VariableStack &)
{
return ast::Formula::make<ast::Boolean>(boolean.value);
}
std::optional<ast::Formula> visit(const Clingo::AST::Term &term, const Clingo::AST::Literal &literal, RuleContext &ruleContext, ast::VariableStack &variableStack)
std::optional<ast::Formula> visit(const Clingo::AST::Term &term, const Clingo::AST::Literal &literal, RuleContext &ruleContext, Context &context, ast::VariableStack &variableStack)
{
return term.data.accept(BodyTermTranslateVisitor(), literal, term, ruleContext, variableStack);
return term.data.accept(BodyTermTranslateVisitor(), literal, term, ruleContext, context, variableStack);
}
// TODO: refactor
std::optional<ast::Formula> visit(const Clingo::AST::Comparison &comparison, const Clingo::AST::Literal &literal, RuleContext &ruleContext, ast::VariableStack &variableStack)
std::optional<ast::Formula> visit(const Clingo::AST::Comparison &comparison, const Clingo::AST::Literal &literal, RuleContext &ruleContext, Context &, ast::VariableStack &variableStack)
{
// Comparisons should never have a sign, because these are converted to positive comparisons by clingo
if (literal.sign != Clingo::AST::Sign::None)
@@ -140,7 +144,7 @@ struct BodyLiteralTranslateVisitor
}
template<class T>
std::optional<ast::Formula> visit(const T &, const Clingo::AST::Literal &literal, RuleContext &, ast::VariableStack &)
std::optional<ast::Formula> visit(const T &, const Clingo::AST::Literal &literal, RuleContext &, Context &, ast::VariableStack &)
{
throw TranslationException(literal.location, "literal currently unsupported in this context, expected function or term");
return std::nullopt;
@@ -151,16 +155,16 @@ struct BodyLiteralTranslateVisitor
struct BodyBodyLiteralTranslateVisitor
{
std::optional<ast::Formula> visit(const Clingo::AST::Literal &literal, const Clingo::AST::BodyLiteral &bodyLiteral, RuleContext &ruleContext, ast::VariableStack &variableStack)
std::optional<ast::Formula> visit(const Clingo::AST::Literal &literal, const Clingo::AST::BodyLiteral &bodyLiteral, RuleContext &ruleContext, Context &context, ast::VariableStack &variableStack)
{
if (bodyLiteral.sign != Clingo::AST::Sign::None)
throw TranslationException(bodyLiteral.location, "only positive body literals supported currently");
return literal.data.accept(BodyLiteralTranslateVisitor(), literal, ruleContext, variableStack);
return literal.data.accept(BodyLiteralTranslateVisitor(), literal, ruleContext, context, variableStack);
}
template<class T>
std::optional<ast::Formula> visit(const T &, const Clingo::AST::BodyLiteral &bodyLiteral, RuleContext &, ast::VariableStack &)
std::optional<ast::Formula> visit(const T &, const Clingo::AST::BodyLiteral &bodyLiteral, RuleContext &, Context &, ast::VariableStack &)
{
throw TranslationException(bodyLiteral.location, "body literal currently unsupported in this context, expected literal");
return std::nullopt;

View File

@@ -16,9 +16,9 @@ namespace anthem
//
////////////////////////////////////////////////////////////////////////////////////////////////////
struct PredicateSignatureMeta
struct PredicateDeclarationMeta
{
ast::PredicateSignature predicateSignature;
ast::PredicateDeclaration *declaration;
bool used{false};
};
@@ -33,13 +33,36 @@ struct Context
{
}
ast::PredicateDeclaration *findOrCreatePredicateDeclaration(const char *name, size_t arity)
{
const auto matchesExistingPredicateDeclaration =
[&](const auto &predicateDeclaration)
{
return (predicateDeclaration->arity == arity
&& strcmp(predicateDeclaration->name.c_str(), name) == 0);
};
auto matchingPredicateDeclaration = std::find_if(predicateDeclarations.begin(),
predicateDeclarations.end(), matchesExistingPredicateDeclaration);
if (matchingPredicateDeclaration != predicateDeclarations.end())
return matchingPredicateDeclaration->get();
predicateDeclarations.emplace_back(std::make_unique<ast::PredicateDeclaration>(name, arity));
return predicateDeclarations.back().get();
}
output::Logger logger;
bool performSimplification = false;
bool performCompletion = false;
std::optional<std::vector<PredicateSignatureMeta>> visiblePredicateSignatures;
std::optional<std::vector<PredicateSignatureMeta>> externalPredicateSignatures;
std::vector<std::unique_ptr<ast::PredicateDeclaration>> predicateDeclarations;
ast::PredicateDeclaration::Visibility defaultPredicateVisibility{ast::PredicateDeclaration::Visibility::Visible};
bool externalStatementsUsed{false};
bool showStatementsUsed{false};
ast::ParenthesisStyle parenthesisStyle = ast::ParenthesisStyle::Normal;
};

View File

@@ -237,7 +237,7 @@ struct FormulaEqualityVisitor
const auto &otherPredicate = otherFormula.get<Predicate>();
if (!matches(predicate, otherPredicate))
if (predicate.declaration != otherPredicate.declaration)
return Tristate::False;
assert(predicate.arguments.size() == otherPredicate.arguments.size());

View File

@@ -118,8 +118,7 @@ struct HeadLiteralCollectFunctionTermsVisitor
struct FunctionTermTranslateVisitor
{
// TODO: check correctness
std::optional<ast::Formula> visit(const Clingo::AST::Function &function, const Clingo::AST::Term &term, RuleContext &ruleContext, size_t &headVariableIndex)
std::optional<ast::Formula> visit(const Clingo::AST::Function &function, const Clingo::AST::Term &term, RuleContext &ruleContext, Context &context, size_t &headVariableIndex)
{
if (function.external)
throw TranslationException(term.location, "external functions currently unsupported");
@@ -130,11 +129,14 @@ struct FunctionTermTranslateVisitor
for (size_t i = 0; i < function.arguments.size(); i++)
arguments.emplace_back(ast::Variable(ruleContext.freeVariables[headVariableIndex++].get()));
return ast::Formula::make<ast::Predicate>(function.name, std::move(arguments));
auto predicateDeclaration = context.findOrCreatePredicateDeclaration(function.name, function.arguments.size());
predicateDeclaration->isUsed = true;
return ast::Predicate(predicateDeclaration, std::move(arguments));
}
template<class T>
std::optional<ast::Formula> visit(const T &, const Clingo::AST::Term &term, RuleContext &, size_t &)
std::optional<ast::Formula> visit(const T &, const Clingo::AST::Term &term, RuleContext &, Context &, size_t &)
{
throw TranslationException(term.location, "term currently unsupported in this context, function expected");
return std::nullopt;
@@ -145,18 +147,18 @@ struct FunctionTermTranslateVisitor
struct LiteralTranslateVisitor
{
std::optional<ast::Formula> visit(const Clingo::AST::Boolean &boolean, const Clingo::AST::Literal &, RuleContext &, size_t &)
std::optional<ast::Formula> visit(const Clingo::AST::Boolean &boolean, const Clingo::AST::Literal &, RuleContext &, Context &, size_t &)
{
return ast::Formula::make<ast::Boolean>(boolean.value);
}
std::optional<ast::Formula> visit(const Clingo::AST::Term &term, const Clingo::AST::Literal &, RuleContext &ruleContext, size_t &headVariableIndex)
std::optional<ast::Formula> visit(const Clingo::AST::Term &term, const Clingo::AST::Literal &, RuleContext &ruleContext, Context &context, size_t &headVariableIndex)
{
return term.data.accept(FunctionTermTranslateVisitor(), term, ruleContext, headVariableIndex);
return term.data.accept(FunctionTermTranslateVisitor(), term, ruleContext, context, headVariableIndex);
}
template<class T>
std::optional<ast::Formula> visit(const T &, const Clingo::AST::Literal &literal, RuleContext &, size_t &)
std::optional<ast::Formula> visit(const T &, const Clingo::AST::Literal &literal, RuleContext &, Context &, size_t &)
{
throw TranslationException(literal.location, "only disjunctions of literals allowed as head literals");
return std::nullopt;
@@ -167,12 +169,12 @@ struct LiteralTranslateVisitor
struct HeadLiteralTranslateToConsequentVisitor
{
std::optional<ast::Formula> visit(const Clingo::AST::Literal &literal, const Clingo::AST::HeadLiteral &, RuleContext &ruleContext, size_t &headVariableIndex)
std::optional<ast::Formula> visit(const Clingo::AST::Literal &literal, const Clingo::AST::HeadLiteral &, RuleContext &ruleContext, Context &context, size_t &headVariableIndex)
{
if (literal.sign == Clingo::AST::Sign::DoubleNegation)
throw TranslationException(literal.location, "double-negated head literals currently unsupported");
auto translatedLiteral = literal.data.accept(LiteralTranslateVisitor(), literal, ruleContext, headVariableIndex);
auto translatedLiteral = literal.data.accept(LiteralTranslateVisitor(), literal, ruleContext, context, headVariableIndex);
if (literal.sign == Clingo::AST::Sign::None)
return translatedLiteral;
@@ -183,7 +185,7 @@ struct HeadLiteralTranslateToConsequentVisitor
return ast::Formula::make<ast::Not>(std::move(translatedLiteral.value()));
}
std::optional<ast::Formula> visit(const Clingo::AST::Disjunction &disjunction, const Clingo::AST::HeadLiteral &headLiteral, RuleContext &ruleContext, size_t &headVariableIndex)
std::optional<ast::Formula> visit(const Clingo::AST::Disjunction &disjunction, const Clingo::AST::HeadLiteral &headLiteral, RuleContext &ruleContext, Context &context, size_t &headVariableIndex)
{
std::vector<ast::Formula> arguments;
arguments.reserve(disjunction.elements.size());
@@ -193,7 +195,7 @@ struct HeadLiteralTranslateToConsequentVisitor
if (!conditionalLiteral.condition.empty())
throw TranslationException(headLiteral.location, "conditional head literals currently unsupported");
auto argument = visit(conditionalLiteral.literal, headLiteral, ruleContext, headVariableIndex);
auto argument = visit(conditionalLiteral.literal, headLiteral, ruleContext, context, headVariableIndex);
if (!argument)
throw TranslationException(headLiteral.location, "could not parse argument");
@@ -204,7 +206,7 @@ struct HeadLiteralTranslateToConsequentVisitor
return ast::Formula::make<ast::Or>(std::move(arguments));
}
std::optional<ast::Formula> visit(const Clingo::AST::Aggregate &aggregate, const Clingo::AST::HeadLiteral &headLiteral, RuleContext &ruleContext, size_t &headVariableIndex)
std::optional<ast::Formula> visit(const Clingo::AST::Aggregate &aggregate, const Clingo::AST::HeadLiteral &headLiteral, RuleContext &ruleContext, Context &context, size_t &headVariableIndex)
{
if (aggregate.left_guard || aggregate.right_guard)
throw TranslationException(headLiteral.location, "aggregates with left or right guards currently unsupported");
@@ -215,7 +217,7 @@ struct HeadLiteralTranslateToConsequentVisitor
if (!conditionalLiteral.condition.empty())
throw TranslationException(headLiteral.location, "conditional head literals currently unsupported");
return this->visit(conditionalLiteral.literal, headLiteral, ruleContext, headVariableIndex);
return this->visit(conditionalLiteral.literal, headLiteral, ruleContext, context, headVariableIndex);
};
if (aggregate.elements.size() == 1)
@@ -238,7 +240,7 @@ struct HeadLiteralTranslateToConsequentVisitor
}
template<class T>
std::optional<ast::Formula> visit(const T &, const Clingo::AST::HeadLiteral &headLiteral, RuleContext &, size_t &)
std::optional<ast::Formula> visit(const T &, const Clingo::AST::HeadLiteral &headLiteral, RuleContext &, Context &, size_t &)
{
throw TranslationException(headLiteral.location, "head literal currently unsupported in this context, expected literal, disjunction, or aggregate");
return std::nullopt;

View File

@@ -13,7 +13,7 @@ namespace anthem
//
////////////////////////////////////////////////////////////////////////////////////////////////////
void eliminateHiddenPredicates(const std::vector<ast::PredicateSignature> &predicateSignatures, std::vector<ast::Formula> &completedFormulas, Context &context);
void eliminateHiddenPredicates(std::vector<ast::Formula> &completedFormulas, Context &context);
////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@@ -73,7 +73,7 @@ struct StatementVisitor
// Compute consequent
auto headVariableIndex = ruleContext.headVariablesStartIndex;
auto consequent = rule.head.data.accept(HeadLiteralTranslateToConsequentVisitor(), rule.head, ruleContext, headVariableIndex);
auto consequent = rule.head.data.accept(HeadLiteralTranslateToConsequentVisitor(), rule.head, ruleContext, context, headVariableIndex);
assert(ruleContext.headTerms.size() == headVariableIndex - ruleContext.headVariablesStartIndex);
@@ -98,7 +98,7 @@ struct StatementVisitor
{
const auto &bodyLiteral = *i;
auto argument = bodyLiteral.data.accept(BodyBodyLiteralTranslateVisitor(), bodyLiteral, ruleContext, variableStack);
auto argument = bodyLiteral.data.accept(BodyBodyLiteralTranslateVisitor(), bodyLiteral, ruleContext, context, variableStack);
if (!argument)
throw TranslationException(bodyLiteral.location, "could not translate body literal");
@@ -165,8 +165,8 @@ struct StatementVisitor
if (signature.negative())
throw LogicException(statement.location, "negative #show atom signatures are currently unsupported");
if (!context.visiblePredicateSignatures)
context.visiblePredicateSignatures.emplace();
context.showStatementsUsed = true;
context.defaultPredicateVisibility = ast::PredicateDeclaration::Visibility::Hidden;
if (std::strlen(signature.name()) == 0)
{
@@ -176,8 +176,8 @@ struct StatementVisitor
context.logger.log(output::Priority::Debug, statement.location) << "showing “" << signature.name() << "/" << signature.arity() << "";
auto predicateSignature = ast::PredicateSignature{std::string(signature.name()), signature.arity()};
context.visiblePredicateSignatures.value().emplace_back(PredicateSignatureMeta{std::move(predicateSignature)});
auto predicateDeclaration = context.findOrCreatePredicateDeclaration(signature.name(), signature.arity());
predicateDeclaration->visibility = ast::PredicateDeclaration::Visibility::Visible;
}
void visit(const Clingo::AST::ShowTerm &, const Clingo::AST::Statement &statement, std::vector<ast::ScopedFormula> &, Context &)
@@ -214,13 +214,12 @@ struct StatementVisitor
if (aritySymbol.type() != Clingo::SymbolType::Number)
fail();
context.externalStatementsUsed = true;
const size_t arity = arityArgument.data.get<Clingo::Symbol>().number();
if (!context.externalPredicateSignatures)
context.externalPredicateSignatures.emplace();
auto predicateSignature = ast::PredicateSignature{std::string(predicate.name), arity};
context.externalPredicateSignatures->emplace_back(PredicateSignatureMeta{std::move(predicateSignature)});
auto predicateDeclaration = context.findOrCreatePredicateDeclaration(predicate.name, arity);
predicateDeclaration->isExternal = true;
}
template<class T>

View File

@@ -52,6 +52,7 @@ output::ColorStream &print(output::ColorStream &stream, const In &in, PrintConte
output::ColorStream &print(output::ColorStream &stream, const Integer &integer, PrintContext &printContext, bool omitParentheses = false);
output::ColorStream &print(output::ColorStream &stream, const Interval &interval, PrintContext &printContext, bool omitParentheses = false);
output::ColorStream &print(output::ColorStream &stream, const Predicate &predicate, PrintContext &printContext, bool omitParentheses = false);
output::ColorStream &print(output::ColorStream &stream, const PredicateDeclaration &predicateDeclaration, PrintContext &printContext, bool omitParentheses = false);
output::ColorStream &print(output::ColorStream &stream, const SpecialInteger &specialInteger, PrintContext &printContext, bool omitParentheses = false);
output::ColorStream &print(output::ColorStream &stream, const String &string, PrintContext &printContext, bool omitParentheses = false);
output::ColorStream &print(output::ColorStream &stream, const UnaryOperation &unaryOperation, PrintContext &printContext, bool omitParentheses = false);
@@ -244,7 +245,7 @@ inline output::ColorStream &print(output::ColorStream &stream, const Interval &i
inline output::ColorStream &print(output::ColorStream &stream, const Predicate &predicate, PrintContext &printContext, bool)
{
stream << predicate.name;
stream << predicate.declaration->name;
if (predicate.arguments.empty())
return stream;
@@ -266,6 +267,13 @@ inline output::ColorStream &print(output::ColorStream &stream, const Predicate &
////////////////////////////////////////////////////////////////////////////////////////////////////
inline output::ColorStream &print(output::ColorStream &stream, const PredicateDeclaration &predicateDeclaration, PrintContext &, bool)
{
return (stream << predicateDeclaration.name << "/" << predicateDeclaration.arity);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
inline output::ColorStream &print(output::ColorStream &stream, const SpecialInteger &specialInteger, PrintContext &, bool)
{
switch (specialInteger.type)