2016-11-23 03:29:26 +01:00
|
|
|
#ifndef __ANTHEM__HEAD_H
|
|
|
|
#define __ANTHEM__HEAD_H
|
|
|
|
|
|
|
|
#include <algorithm>
|
2018-03-22 17:20:54 +01:00
|
|
|
#include <optional>
|
2016-11-23 03:29:26 +01:00
|
|
|
|
2017-03-15 16:00:00 +01:00
|
|
|
#include <anthem/AST.h>
|
2017-05-31 18:03:19 +02:00
|
|
|
#include <anthem/Exception.h>
|
2017-05-30 03:53:51 +02:00
|
|
|
#include <anthem/RuleContext.h>
|
2016-11-23 03:29:26 +01:00
|
|
|
#include <anthem/Utils.h>
|
2016-11-24 02:42:32 +01:00
|
|
|
#include <anthem/output/Formatting.h>
|
2016-11-23 03:29:26 +01:00
|
|
|
|
|
|
|
namespace anthem
|
|
|
|
{
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// Head
|
|
|
|
//
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2017-05-30 03:53:51 +02:00
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Collect Head Terms
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2016-11-23 03:29:26 +01:00
|
|
|
struct TermCollectFunctionTermsVisitor
|
|
|
|
{
|
2017-05-31 18:03:19 +02:00
|
|
|
void visit(const Clingo::AST::Function &function, const Clingo::AST::Term &term, RuleContext &ruleContext)
|
2016-11-23 03:29:26 +01:00
|
|
|
{
|
|
|
|
if (function.external)
|
2017-05-31 18:03:19 +02:00
|
|
|
throw LogicException(term.location, "external functions currently unsupported");
|
2016-11-23 03:29:26 +01:00
|
|
|
|
2017-05-30 03:53:51 +02:00
|
|
|
ruleContext.headTerms.reserve(ruleContext.headTerms.size() + function.arguments.size());
|
2016-11-23 03:29:26 +01:00
|
|
|
|
|
|
|
for (const auto &argument : function.arguments)
|
2017-05-30 03:53:51 +02:00
|
|
|
ruleContext.headTerms.emplace_back(&argument);
|
2016-11-23 03:29:26 +01:00
|
|
|
}
|
|
|
|
|
2017-03-28 18:07:06 +02:00
|
|
|
template<class T>
|
2017-05-31 18:03:19 +02:00
|
|
|
void visit(const T &, const Clingo::AST::Term &term, RuleContext &)
|
2016-11-23 03:29:26 +01:00
|
|
|
{
|
2017-06-04 04:43:07 +02:00
|
|
|
throw LogicException(term.location, "term currently unsupported in this context, function expected");
|
2016-11-23 03:29:26 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
struct LiteralCollectFunctionTermsVisitor
|
|
|
|
{
|
2017-05-31 18:03:19 +02:00
|
|
|
void visit(const Clingo::AST::Boolean &, const Clingo::AST::Literal &, RuleContext &)
|
2016-11-23 03:29:26 +01:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2017-05-31 18:03:19 +02:00
|
|
|
void visit(const Clingo::AST::Term &term, const Clingo::AST::Literal &, RuleContext &ruleContext)
|
2016-11-23 03:29:26 +01:00
|
|
|
{
|
2017-05-31 18:03:19 +02:00
|
|
|
term.data.accept(TermCollectFunctionTermsVisitor(), term, ruleContext);
|
2016-11-23 03:29:26 +01:00
|
|
|
}
|
|
|
|
|
2017-03-28 18:07:06 +02:00
|
|
|
template<class T>
|
2017-05-31 18:03:19 +02:00
|
|
|
void visit(const T &, const Clingo::AST::Literal &literal, RuleContext &)
|
2016-11-23 03:29:26 +01:00
|
|
|
{
|
2017-05-31 18:03:19 +02:00
|
|
|
throw LogicException(literal.location, "only disjunctions of literals allowed as head literals");
|
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
|
|
|
|
{
|
2017-05-31 18:03:19 +02:00
|
|
|
void visit(const Clingo::AST::Literal &literal, const Clingo::AST::HeadLiteral &, RuleContext &ruleContext)
|
2016-11-23 03:29:26 +01:00
|
|
|
{
|
2017-05-30 03:53:51 +02:00
|
|
|
ruleContext.numberOfHeadLiterals = 1;
|
2017-03-06 15:40:23 +01:00
|
|
|
|
2017-05-31 18:03:19 +02:00
|
|
|
literal.data.accept(LiteralCollectFunctionTermsVisitor(), literal, ruleContext);
|
2016-11-23 03:29:26 +01:00
|
|
|
}
|
|
|
|
|
2017-05-31 18:03:19 +02:00
|
|
|
void visit(const Clingo::AST::Disjunction &disjunction, const Clingo::AST::HeadLiteral &headLiteral, RuleContext &ruleContext)
|
2016-11-23 03:29:26 +01:00
|
|
|
{
|
2017-05-30 03:53:51 +02: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())
|
2017-05-31 18:03:19 +02:00
|
|
|
throw LogicException(headLiteral.location, "conditional head literals currently unsupported");
|
2016-11-23 03:29:26 +01:00
|
|
|
|
2017-05-31 18:03:19 +02:00
|
|
|
conditionalLiteral.literal.data.accept(LiteralCollectFunctionTermsVisitor(), conditionalLiteral.literal, ruleContext);
|
2016-11-23 03:29:26 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-31 18:03:19 +02:00
|
|
|
void visit(const Clingo::AST::Aggregate &aggregate, const Clingo::AST::HeadLiteral &headLiteral, RuleContext &ruleContext)
|
2016-11-23 03:29:26 +01:00
|
|
|
{
|
2017-05-30 03:53:51 +02:00
|
|
|
ruleContext.isChoiceRule = true;
|
|
|
|
ruleContext.numberOfHeadLiterals = aggregate.elements.size();
|
2017-03-06 15:40:23 +01:00
|
|
|
|
|
|
|
if (aggregate.left_guard || aggregate.right_guard)
|
2017-05-31 18:03:19 +02:00
|
|
|
throw LogicException(headLiteral.location, "aggregates with left or right guards currently unsupported");
|
2017-03-06 15:40:23 +01:00
|
|
|
|
|
|
|
for (const auto &conditionalLiteral : aggregate.elements)
|
|
|
|
{
|
|
|
|
if (!conditionalLiteral.condition.empty())
|
2017-05-31 18:03:19 +02:00
|
|
|
throw LogicException(headLiteral.location, "conditional literals in aggregates currently unsupported");
|
2017-03-06 15:40:23 +01:00
|
|
|
|
2017-05-31 18:03:19 +02:00
|
|
|
conditionalLiteral.literal.data.accept(LiteralCollectFunctionTermsVisitor(), conditionalLiteral.literal, ruleContext);
|
2017-03-06 15:40:23 +01:00
|
|
|
}
|
2016-11-23 03:29:26 +01:00
|
|
|
}
|
|
|
|
|
2017-03-28 18:07:06 +02:00
|
|
|
template<class T>
|
2017-05-31 18:03:19 +02:00
|
|
|
void visit(const T &, const Clingo::AST::HeadLiteral &headLiteral, RuleContext &)
|
2016-11-23 03:29:26 +01:00
|
|
|
{
|
2017-06-04 04:43:07 +02:00
|
|
|
throw LogicException(headLiteral.location, "head literal currently unsupported in this context, expected literal, disjunction, or aggregate");
|
2016-11-23 03:29:26 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-05-30 03:53:51 +02:00
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Translate Head
|
2016-11-23 03:29:26 +01:00
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2017-03-15 16:00:00 +01:00
|
|
|
struct FunctionTermTranslateVisitor
|
2016-11-23 03:29:26 +01:00
|
|
|
{
|
2016-11-24 03:16:37 +01:00
|
|
|
// TODO: check correctness
|
2018-03-22 17:20:54 +01:00
|
|
|
std::optional<ast::Formula> visit(const Clingo::AST::Function &function, const Clingo::AST::Term &term, RuleContext &ruleContext, size_t &headVariableIndex)
|
2016-11-23 03:29:26 +01:00
|
|
|
{
|
|
|
|
if (function.external)
|
2017-05-31 18:03:19 +02:00
|
|
|
throw TranslationException(term.location, "external functions currently unsupported");
|
2016-11-23 03:29:26 +01:00
|
|
|
|
2017-03-15 16:00:00 +01:00
|
|
|
std::vector<ast::Term> arguments;
|
|
|
|
arguments.reserve(function.arguments.size());
|
2016-11-23 03:29:26 +01:00
|
|
|
|
2017-05-30 03:53:51 +02: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
|
|
|
|
2017-03-23 00:44:10 +01:00
|
|
|
return ast::Formula::make<ast::Predicate>(function.name, std::move(arguments));
|
2016-11-23 03:29:26 +01:00
|
|
|
}
|
|
|
|
|
2017-03-28 18:07:06 +02:00
|
|
|
template<class T>
|
2018-03-22 17:20:54 +01:00
|
|
|
std::optional<ast::Formula> visit(const T &, const Clingo::AST::Term &term, RuleContext &, size_t &)
|
2016-11-23 03:29:26 +01:00
|
|
|
{
|
2017-06-04 04:43:07 +02:00
|
|
|
throw TranslationException(term.location, "term currently unsupported in this context, function expected");
|
2018-03-22 17:20:54 +01:00
|
|
|
return std::nullopt;
|
2016-11-23 03:29:26 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2017-03-15 16:00:00 +01:00
|
|
|
struct LiteralTranslateVisitor
|
2016-11-23 03:29:26 +01:00
|
|
|
{
|
2018-03-22 17:20:54 +01:00
|
|
|
std::optional<ast::Formula> visit(const Clingo::AST::Boolean &boolean, const Clingo::AST::Literal &, RuleContext &, size_t &)
|
2016-11-23 03:29:26 +01:00
|
|
|
{
|
2017-03-23 00:44:10 +01:00
|
|
|
return ast::Formula::make<ast::Boolean>(boolean.value);
|
2016-11-23 03:29:26 +01:00
|
|
|
}
|
|
|
|
|
2018-03-22 17:20:54 +01:00
|
|
|
std::optional<ast::Formula> visit(const Clingo::AST::Term &term, const Clingo::AST::Literal &, RuleContext &ruleContext, size_t &headVariableIndex)
|
2016-11-23 03:29:26 +01:00
|
|
|
{
|
2017-05-31 18:03:19 +02:00
|
|
|
return term.data.accept(FunctionTermTranslateVisitor(), term, ruleContext, headVariableIndex);
|
2016-11-23 03:29:26 +01:00
|
|
|
}
|
|
|
|
|
2017-03-28 18:07:06 +02:00
|
|
|
template<class T>
|
2018-03-22 17:20:54 +01:00
|
|
|
std::optional<ast::Formula> visit(const T &, const Clingo::AST::Literal &literal, RuleContext &, size_t &)
|
2016-11-23 03:29:26 +01:00
|
|
|
{
|
2017-05-31 18:03:19 +02:00
|
|
|
throw TranslationException(literal.location, "only disjunctions of literals allowed as head literals");
|
2018-03-22 17:20:54 +01:00
|
|
|
return std::nullopt;
|
2016-11-23 03:29:26 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2017-03-15 16:00:00 +01:00
|
|
|
struct HeadLiteralTranslateToConsequentVisitor
|
2016-11-23 03:29:26 +01:00
|
|
|
{
|
2018-03-22 17:20:54 +01:00
|
|
|
std::optional<ast::Formula> visit(const Clingo::AST::Literal &literal, const Clingo::AST::HeadLiteral &, 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)
|
2017-05-31 18:03:19 +02:00
|
|
|
throw TranslationException(literal.location, "double-negated head literals currently unsupported");
|
2017-03-15 16:00:00 +01:00
|
|
|
|
2017-05-31 18:03:19 +02:00
|
|
|
auto translatedLiteral = literal.data.accept(LiteralTranslateVisitor(), literal, ruleContext, headVariableIndex);
|
2017-03-15 16:00:00 +01:00
|
|
|
|
|
|
|
if (literal.sign == Clingo::AST::Sign::None)
|
|
|
|
return translatedLiteral;
|
2016-11-24 16:04:53 +01:00
|
|
|
|
2017-03-15 16:00:00 +01:00
|
|
|
if (!translatedLiteral)
|
2018-03-22 17:20:54 +01:00
|
|
|
return std::nullopt;
|
2016-11-23 03:47:32 +01:00
|
|
|
|
2017-03-23 00:44:10 +01:00
|
|
|
return ast::Formula::make<ast::Not>(std::move(translatedLiteral.value()));
|
2016-11-23 03:29:26 +01:00
|
|
|
}
|
|
|
|
|
2018-03-22 17:20:54 +01:00
|
|
|
std::optional<ast::Formula> visit(const Clingo::AST::Disjunction &disjunction, const Clingo::AST::HeadLiteral &headLiteral, RuleContext &ruleContext, size_t &headVariableIndex)
|
2016-11-23 03:29:26 +01:00
|
|
|
{
|
2017-03-15 16:00:00 +01:00
|
|
|
std::vector<ast::Formula> arguments;
|
|
|
|
arguments.reserve(disjunction.elements.size());
|
2016-11-23 03:29:26 +01:00
|
|
|
|
2017-03-15 16:00:00 +01:00
|
|
|
for (const auto &conditionalLiteral : disjunction.elements)
|
|
|
|
{
|
2017-03-06 14:51:46 +01:00
|
|
|
if (!conditionalLiteral.condition.empty())
|
2017-05-31 18:03:19 +02:00
|
|
|
throw TranslationException(headLiteral.location, "conditional head literals currently unsupported");
|
2016-11-23 03:29:26 +01:00
|
|
|
|
2017-05-31 18:03:19 +02:00
|
|
|
auto argument = visit(conditionalLiteral.literal, headLiteral, ruleContext, headVariableIndex);
|
2017-03-15 16:00:00 +01:00
|
|
|
|
|
|
|
if (!argument)
|
2017-05-31 18:03:19 +02:00
|
|
|
throw TranslationException(headLiteral.location, "could not parse argument");
|
2016-11-23 03:29:26 +01:00
|
|
|
|
2017-03-15 16:00:00 +01:00
|
|
|
arguments.emplace_back(std::move(argument.value()));
|
2016-11-23 03:29:26 +01:00
|
|
|
}
|
2017-03-15 16:00:00 +01:00
|
|
|
|
2017-03-23 00:44:10 +01:00
|
|
|
return ast::Formula::make<ast::Or>(std::move(arguments));
|
2016-11-23 03:29:26 +01:00
|
|
|
}
|
|
|
|
|
2018-03-22 17:20:54 +01:00
|
|
|
std::optional<ast::Formula> visit(const Clingo::AST::Aggregate &aggregate, const Clingo::AST::HeadLiteral &headLiteral, 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)
|
2017-05-31 18:03:19 +02:00
|
|
|
throw TranslationException(headLiteral.location, "aggregates with left or right guards currently unsupported");
|
2017-03-06 15:40:23 +01:00
|
|
|
|
2017-03-15 16:00:00 +01:00
|
|
|
const auto translateConditionalLiteral =
|
|
|
|
[&](const auto &conditionalLiteral)
|
|
|
|
{
|
|
|
|
if (!conditionalLiteral.condition.empty())
|
2017-05-31 18:03:19 +02:00
|
|
|
throw TranslationException(headLiteral.location, "conditional head literals currently unsupported");
|
2017-03-06 15:40:23 +01:00
|
|
|
|
2017-05-31 18:03:19 +02:00
|
|
|
return this->visit(conditionalLiteral.literal, headLiteral, ruleContext, headVariableIndex);
|
2017-03-15 16:00:00 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
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
|
|
|
|
2017-03-15 16:00:00 +01:00
|
|
|
for (const auto &conditionalLiteral : aggregate.elements)
|
|
|
|
{
|
|
|
|
auto argument = translateConditionalLiteral(conditionalLiteral);
|
2017-03-06 15:40:23 +01:00
|
|
|
|
2017-03-15 16:00:00 +01:00
|
|
|
if (!argument)
|
2017-05-31 18:03:19 +02:00
|
|
|
throw TranslationException(headLiteral.location, "could not parse argument");
|
2017-03-15 16:00:00 +01:00
|
|
|
|
|
|
|
arguments.emplace_back(std::move(argument.value()));
|
2017-03-06 15:40:23 +01:00
|
|
|
}
|
2017-03-15 16:00:00 +01:00
|
|
|
|
2017-03-23 00:44:10 +01:00
|
|
|
return ast::Formula::make<ast::Or>(std::move(arguments));
|
2016-11-23 03:29:26 +01:00
|
|
|
}
|
|
|
|
|
2017-03-28 18:07:06 +02:00
|
|
|
template<class T>
|
2018-03-22 17:20:54 +01:00
|
|
|
std::optional<ast::Formula> visit(const T &, const Clingo::AST::HeadLiteral &headLiteral, RuleContext &, size_t &)
|
2016-11-23 03:29:26 +01:00
|
|
|
{
|
2017-06-04 04:43:07 +02:00
|
|
|
throw TranslationException(headLiteral.location, "head literal currently unsupported in this context, expected literal, disjunction, or aggregate");
|
2018-03-22 17:20:54 +01:00
|
|
|
return std::nullopt;
|
2016-11-23 03:29:26 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|