anthem/include/anthem/Head.h

252 lines
9.7 KiB
C
Raw Normal View History

2016-11-23 03:29:26 +01:00
#ifndef __ANTHEM__HEAD_H
#define __ANTHEM__HEAD_H
#include <algorithm>
#include <experimental/optional>
2016-11-23 03:29:26 +01:00
#include <anthem/AST.h>
#include <anthem/RuleContext.h>
2016-11-23 03:29:26 +01:00
#include <anthem/Utils.h>
#include <anthem/output/Formatting.h>
2016-11-23 03:29:26 +01:00
namespace anthem
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Head
//
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
// Collect Head Terms
////////////////////////////////////////////////////////////////////////////////////////////////////
2016-11-23 03:29:26 +01:00
struct TermCollectFunctionTermsVisitor
{
void visit(const Clingo::AST::Function &function, const Clingo::AST::Term &term, Context &context, RuleContext &ruleContext)
2016-11-23 03:29:26 +01:00
{
if (function.external)
throwErrorAtLocation(term.location, "external functions currently unsupported", context);
2016-11-23 03:29:26 +01:00
ruleContext.headTerms.reserve(ruleContext.headTerms.size() + function.arguments.size());
2016-11-23 03:29:26 +01:00
for (const auto &argument : function.arguments)
ruleContext.headTerms.emplace_back(&argument);
2016-11-23 03:29:26 +01:00
}
template<class T>
void visit(const T &, const Clingo::AST::Term &term, Context &context, RuleContext &)
2016-11-23 03:29:26 +01:00
{
throwErrorAtLocation(term.location, "term currently unsupported in this context, function expected", context);
2016-11-23 03:29:26 +01:00
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////
struct LiteralCollectFunctionTermsVisitor
{
void visit(const Clingo::AST::Boolean &, const Clingo::AST::Literal &, Context &, RuleContext &)
2016-11-23 03:29:26 +01:00
{
}
void visit(const Clingo::AST::Term &term, const Clingo::AST::Literal &, Context &context, RuleContext &ruleContext)
2016-11-23 03:29:26 +01:00
{
term.data.accept(TermCollectFunctionTermsVisitor(), term, context, ruleContext);
2016-11-23 03:29:26 +01:00
}
template<class T>
void visit(const T &, const Clingo::AST::Literal &literal, Context &context, RuleContext &)
2016-11-23 03:29:26 +01:00
{
throwErrorAtLocation(literal.location, "only disjunctions of literals allowed as head literals", context);
2016-11-23 03:29:26 +01:00
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////
2017-03-06 15:40:23 +01:00
// TODO: rename, because not only terms are collected anymore
2016-11-23 03:29:26 +01:00
struct HeadLiteralCollectFunctionTermsVisitor
{
void visit(const Clingo::AST::Literal &literal, const Clingo::AST::HeadLiteral &, Context &context, RuleContext &ruleContext)
2016-11-23 03:29:26 +01:00
{
ruleContext.numberOfHeadLiterals = 1;
2017-03-06 15:40:23 +01:00
literal.data.accept(LiteralCollectFunctionTermsVisitor(), literal, context, ruleContext);
2016-11-23 03:29:26 +01:00
}
void visit(const Clingo::AST::Disjunction &disjunction, const Clingo::AST::HeadLiteral &headLiteral, Context &context, RuleContext &ruleContext)
2016-11-23 03:29:26 +01:00
{
ruleContext.numberOfHeadLiterals = disjunction.elements.size();
2017-03-06 15:40:23 +01:00
2017-03-06 14:51:46 +01:00
for (const auto &conditionalLiteral : disjunction.elements)
2016-11-23 03:29:26 +01:00
{
2017-03-06 14:51:46 +01:00
if (!conditionalLiteral.condition.empty())
throwErrorAtLocation(headLiteral.location, "conditional head literals currently unsupported", context);
2016-11-23 03:29:26 +01:00
conditionalLiteral.literal.data.accept(LiteralCollectFunctionTermsVisitor(), conditionalLiteral.literal, context, ruleContext);
2016-11-23 03:29:26 +01:00
}
}
void visit(const Clingo::AST::Aggregate &aggregate, const Clingo::AST::HeadLiteral &headLiteral, Context &context, RuleContext &ruleContext)
2016-11-23 03:29:26 +01:00
{
ruleContext.isChoiceRule = true;
ruleContext.numberOfHeadLiterals = aggregate.elements.size();
2017-03-06 15:40:23 +01:00
if (aggregate.left_guard || aggregate.right_guard)
throwErrorAtLocation(headLiteral.location, "aggregates with left or right guards currently unsupported", context);
2017-03-06 15:40:23 +01:00
for (const auto &conditionalLiteral : aggregate.elements)
{
if (!conditionalLiteral.condition.empty())
throwErrorAtLocation(headLiteral.location, "conditional literals in aggregates currently unsupported", context);
conditionalLiteral.literal.data.accept(LiteralCollectFunctionTermsVisitor(), conditionalLiteral.literal, context, ruleContext);
2017-03-06 15:40:23 +01:00
}
2016-11-23 03:29:26 +01:00
}
template<class T>
void visit(const T &, const Clingo::AST::HeadLiteral &headLiteral, Context &context, RuleContext &)
2016-11-23 03:29:26 +01:00
{
throwErrorAtLocation(headLiteral.location, "head literal currently unsupported in this context, expected literal, disjunction, or aggregate", context);
2016-11-23 03:29:26 +01:00
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////
// Translate Head
2016-11-23 03:29:26 +01:00
////////////////////////////////////////////////////////////////////////////////////////////////////
struct FunctionTermTranslateVisitor
2016-11-23 03:29:26 +01:00
{
// TODO: check correctness
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Function &function, const Clingo::AST::Term &term, Context &context, RuleContext &ruleContext, size_t &headVariableIndex)
2016-11-23 03:29:26 +01:00
{
if (function.external)
throwErrorAtLocation(term.location, "external functions currently unsupported", context);
2016-11-23 03:29:26 +01:00
std::vector<ast::Term> arguments;
arguments.reserve(function.arguments.size());
2016-11-23 03:29:26 +01:00
for (size_t i = 0; i < function.arguments.size(); i++)
arguments.emplace_back(ast::Variable(ruleContext.freeVariables[headVariableIndex++].get()));
2016-11-23 03:29:26 +01:00
return ast::Formula::make<ast::Predicate>(function.name, std::move(arguments));
2016-11-23 03:29:26 +01:00
}
template<class T>
std::experimental::optional<ast::Formula> visit(const T &, const Clingo::AST::Term &term, Context &context, RuleContext &, size_t &)
2016-11-23 03:29:26 +01:00
{
throwErrorAtLocation(term.location, "term currently unsupported in this context, function expected", context);
return std::experimental::nullopt;
2016-11-23 03:29:26 +01:00
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////
struct LiteralTranslateVisitor
2016-11-23 03:29:26 +01:00
{
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Boolean &boolean, const Clingo::AST::Literal &, Context &, RuleContext &, size_t &)
2016-11-23 03:29:26 +01:00
{
return ast::Formula::make<ast::Boolean>(boolean.value);
2016-11-23 03:29:26 +01:00
}
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Term &term, const Clingo::AST::Literal &, Context &context, RuleContext &ruleContext, size_t &headVariableIndex)
2016-11-23 03:29:26 +01:00
{
return term.data.accept(FunctionTermTranslateVisitor(), term, context, ruleContext, headVariableIndex);
2016-11-23 03:29:26 +01:00
}
template<class T>
std::experimental::optional<ast::Formula> visit(const T &, const Clingo::AST::Literal &literal, Context &context, RuleContext &, size_t &)
2016-11-23 03:29:26 +01:00
{
throwErrorAtLocation(literal.location, "only disjunctions of literals allowed as head literals", context);
return std::experimental::nullopt;
2016-11-23 03:29:26 +01:00
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////
struct HeadLiteralTranslateToConsequentVisitor
2016-11-23 03:29:26 +01:00
{
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Literal &literal, const Clingo::AST::HeadLiteral &, Context &context, RuleContext &ruleContext, size_t &headVariableIndex)
2016-11-23 03:29:26 +01:00
{
2016-11-23 03:47:32 +01:00
if (literal.sign == Clingo::AST::Sign::DoubleNegation)
throwErrorAtLocation(literal.location, "double-negated head literals currently unsupported", context);
auto translatedLiteral = literal.data.accept(LiteralTranslateVisitor(), literal, context, ruleContext, headVariableIndex);
if (literal.sign == Clingo::AST::Sign::None)
return translatedLiteral;
if (!translatedLiteral)
return std::experimental::nullopt;
2016-11-23 03:47:32 +01:00
return ast::Formula::make<ast::Not>(std::move(translatedLiteral.value()));
2016-11-23 03:29:26 +01:00
}
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Disjunction &disjunction, const Clingo::AST::HeadLiteral &headLiteral, Context &context, RuleContext &ruleContext, size_t &headVariableIndex)
2016-11-23 03:29:26 +01:00
{
std::vector<ast::Formula> arguments;
arguments.reserve(disjunction.elements.size());
2016-11-23 03:29:26 +01:00
for (const auto &conditionalLiteral : disjunction.elements)
{
2017-03-06 14:51:46 +01:00
if (!conditionalLiteral.condition.empty())
throwErrorAtLocation(headLiteral.location, "conditional head literals currently unsupported", context);
2016-11-23 03:29:26 +01:00
auto argument = visit(conditionalLiteral.literal, headLiteral, context, ruleContext, headVariableIndex);
if (!argument)
throwErrorAtLocation(headLiteral.location, "could not parse argument", context);
2016-11-23 03:29:26 +01:00
arguments.emplace_back(std::move(argument.value()));
2016-11-23 03:29:26 +01:00
}
return ast::Formula::make<ast::Or>(std::move(arguments));
2016-11-23 03:29:26 +01:00
}
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Aggregate &aggregate, const Clingo::AST::HeadLiteral &headLiteral, Context &context, RuleContext &ruleContext, size_t &headVariableIndex)
2016-11-23 03:29:26 +01:00
{
2017-03-06 15:40:23 +01:00
if (aggregate.left_guard || aggregate.right_guard)
throwErrorAtLocation(headLiteral.location, "aggregates with left or right guards currently unsupported", context);
2017-03-06 15:40:23 +01:00
const auto translateConditionalLiteral =
[&](const auto &conditionalLiteral)
{
if (!conditionalLiteral.condition.empty())
throwErrorAtLocation(headLiteral.location, "conditional head literals currently unsupported", context);
2017-03-06 15:40:23 +01:00
return this->visit(conditionalLiteral.literal, headLiteral, context, ruleContext, headVariableIndex);
};
if (aggregate.elements.size() == 1)
return translateConditionalLiteral(aggregate.elements[0]);
std::vector<ast::Formula> arguments;
arguments.reserve(aggregate.elements.size());
2017-03-06 15:40:23 +01:00
for (const auto &conditionalLiteral : aggregate.elements)
{
auto argument = translateConditionalLiteral(conditionalLiteral);
2017-03-06 15:40:23 +01:00
if (!argument)
throwErrorAtLocation(headLiteral.location, "could not parse argument", context);
arguments.emplace_back(std::move(argument.value()));
2017-03-06 15:40:23 +01:00
}
return ast::Formula::make<ast::Or>(std::move(arguments));
2016-11-23 03:29:26 +01:00
}
template<class T>
std::experimental::optional<ast::Formula> visit(const T &, const Clingo::AST::HeadLiteral &headLiteral, Context &context, RuleContext &, size_t &)
2016-11-23 03:29:26 +01:00
{
throwErrorAtLocation(headLiteral.location, "head literal currently unsupported in this context, expected literal, disjunction, or aggregate", context);
return std::experimental::nullopt;
2016-11-23 03:29:26 +01:00
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////
}
#endif