Implemented explicit syntax tree representation for first-order formulas.

This commit is contained in:
2017-03-15 16:00:00 +01:00
parent 7ff537a515
commit 9e6d135781
12 changed files with 1225 additions and 569 deletions

View File

@@ -22,10 +22,20 @@ struct BinaryOperation
{
enum class Operator
{
Add,
Subtract
Plus,
Minus,
Multiplication,
Division,
Modulo
};
BinaryOperation(Operator operator_, Term &&left, Term &&right)
: operator_{operator_},
left{std::move(left)},
right{std::move(right)}
{
}
Operator operator_;
Term left;
Term right;
@@ -35,53 +45,173 @@ struct BinaryOperation
struct Boolean
{
Boolean(bool value)
: value{value}
{
}
bool value = false;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
struct Equals
struct Comparison
{
enum class Operator
{
GreaterThan,
LessThan,
LessEqual,
GreaterEqual,
NotEqual,
Equal
};
Comparison(Operator operator_, Term &&left, Term &&right)
: operator_{operator_},
left{std::move(left)},
right{std::move(right)}
{
}
Operator operator_;
Term left;
Term right;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
struct Constant
{
Constant(std::string &&name)
: name{std::move(name)}
{
}
std::string name;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
struct Function
{
const char *name = nullptr;
Function(std::string &&name, std::vector<Term> &&arguments)
: name{std::move(name)},
arguments{std::move(arguments)}
{
}
std::string name;
std::vector<Term> arguments;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
struct In
{
In(Term &&element, Term &&set)
: element{std::move(element)},
set{std::move(set)}
{
}
Term element;
Term set;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
struct Integer
{
Integer(int value)
: value{value}
{
}
int value;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
struct IntegerRange
struct Interval
{
Integer from;
Integer to;
Interval(Term &&from, Term &&to)
: from{std::move(from)},
to{std::move(to)}
{
}
Term from;
Term to;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
struct Predicate
{
const char *name = nullptr;
Predicate(std::string &&name)
: name{std::move(name)}
{
}
Predicate(std::string &&name, std::vector<Term> &&arguments)
: name{std::move(name)},
arguments{std::move(arguments)}
{
}
std::string name;
std::vector<Term> arguments;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
struct SpecialInteger
{
enum class Type
{
Infimum,
Supremum
};
SpecialInteger(Type type)
: type{type}
{
}
Type type;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
struct String
{
String(std::string &&text)
: text{std::move(text)}
{
}
std::string text;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
struct Variable
{
const char *name = nullptr;
enum class Type
{
UserDefined,
Reserved
};
Variable(std::string &&name, Type type)
: name{std::move(name)},
type{type}
{
}
std::string name;
Type type;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -90,6 +220,13 @@ struct Variable
struct And
{
And() = default;
And(std::vector<Formula> &&arguments)
: arguments{std::move(arguments)}
{
}
std::vector<Formula> arguments;
};
@@ -97,6 +234,12 @@ struct And
struct Biconditional
{
Biconditional(Formula &&left, Formula &&right)
: left{std::move(left)},
right{std::move(right)}
{
}
Formula left;
Formula right;
};
@@ -105,22 +248,40 @@ struct Biconditional
struct Exists
{
Exists(std::vector<VariablePointer> &&variables, Formula &&argument)
: variables{std::move(variables)},
argument{std::move(argument)}
{
}
std::vector<VariablePointer> variables;
Formula formula;
Formula argument;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
struct ForAll
{
ForAll(std::vector<VariablePointer> &&variables, Formula &&argument)
: variables{std::move(variables)},
argument{std::move(argument)}
{
}
std::vector<VariablePointer> variables;
Formula formula;
Formula argument;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
struct Implies
{
Implies(Formula &&antecedent, Formula &&consequent)
: antecedent{std::move(antecedent)},
consequent{std::move(consequent)}
{
}
Formula antecedent;
Formula consequent;
};
@@ -129,6 +290,11 @@ struct Implies
struct Not
{
Not(Formula &&argument)
: argument{std::move(argument)}
{
}
Formula argument;
};
@@ -136,12 +302,261 @@ struct Not
struct Or
{
Or() = default;
Or(std::vector<Formula> &&arguments)
: arguments{std::move(arguments)}
{
}
std::vector<Formula> arguments;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
// Deep Copying
////////////////////////////////////////////////////////////////////////////////////////////////////
BinaryOperation deepCopy(const BinaryOperation &other);
Boolean deepCopy(const Boolean &other);
Comparison deepCopy(const Comparison &other);
Constant deepCopy(const Constant &other);
Function deepCopy(const Function &other);
Integer deepCopy(const Integer &other);
Interval deepCopy(const Interval &other);
Predicate deepCopy(const Predicate &other);
SpecialInteger deepCopy(const SpecialInteger &other);
String deepCopy(const String &other);
Variable deepCopy(const Variable &other);
std::vector<VariablePointer> deepCopy(const std::vector<VariablePointer> &other);
And deepCopy(const And &other);
Biconditional deepCopy(const Biconditional &other);
Exists deepCopy(const Exists &other);
ForAll deepCopy(const ForAll &other);
Implies deepCopy(const Implies &other);
Not deepCopy(const Not &other);
Or deepCopy(const Or &other);
Formula deepCopy(const Formula &formula);
std::vector<Formula> deepCopy(const std::vector<Formula> &formulas);
Term deepCopy(const Term &term);
std::vector<Term> deepCopy(const std::vector<Term> &terms);
////////////////////////////////////////////////////////////////////////////////////////////////////
const auto deepCopyUniquePtr =
[](const auto &uniquePtr) -> typename std::decay<decltype(uniquePtr)>::type
{
using Type = typename std::decay<decltype(uniquePtr)>::type::element_type;
return std::make_unique<Type>(deepCopy(*uniquePtr));
};
////////////////////////////////////////////////////////////////////////////////////////////////////
const auto deepCopyUniquePtrVector =
[](const auto &uniquePtrVector) -> typename std::decay<decltype(uniquePtrVector)>::type
{
using Type = typename std::decay<decltype(uniquePtrVector)>::type::value_type;
std::vector<Type> result;
result.reserve(uniquePtrVector.size());
for (const auto &uniquePtr : uniquePtrVector)
result.emplace_back(deepCopyUniquePtr(uniquePtr));
return result;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
const auto deepCopyVariant =
[](const auto &variant) -> typename std::decay<decltype(variant)>::type
{
return variant.match([](const auto &x) -> typename std::decay<decltype(variant)>::type {return deepCopyUniquePtr(x);});
};
////////////////////////////////////////////////////////////////////////////////////////////////////
const auto deepCopyVariantVector =
[](const auto &variantVector) -> typename std::decay<decltype(variantVector)>::type
{
using Type = typename std::decay<decltype(variantVector)>::type::value_type;
std::vector<Type> result;
result.reserve(variantVector.size());
for (const auto &variant : variantVector)
result.emplace_back(deepCopyVariant(variant));
return result;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
BinaryOperation deepCopy(const BinaryOperation &other)
{
return BinaryOperation(other.operator_, deepCopy(other.left), deepCopy(other.right));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
Boolean deepCopy(const Boolean &other)
{
return Boolean(other.value);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
Comparison deepCopy(const Comparison &other)
{
return Comparison(other.operator_, deepCopy(other.left), deepCopy(other.right));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
Constant deepCopy(const Constant &other)
{
return Constant(std::string(other.name));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
Function deepCopy(const Function &other)
{
return Function(std::string(other.name), deepCopy(other.arguments));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
Integer deepCopy(const Integer &other)
{
return Integer(other.value);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
Interval deepCopy(const Interval &other)
{
return Interval(deepCopy(other.from), deepCopy(other.to));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
Predicate deepCopy(const Predicate &other)
{
return Predicate(std::string(other.name), deepCopy(other.arguments));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
SpecialInteger deepCopy(const SpecialInteger &other)
{
return SpecialInteger(other.type);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
String deepCopy(const String &other)
{
return String(std::string(other.text));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
Variable deepCopy(const Variable &other)
{
return Variable(std::string(other.name), other.type);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
std::vector<VariablePointer> deepCopy(const std::vector<VariablePointer> &other)
{
return deepCopyUniquePtrVector(other);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
And deepCopy(const And &other)
{
return And(deepCopy(other.arguments));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
Biconditional deepCopy(const Biconditional &other)
{
return Biconditional(deepCopy(other.left), deepCopy(other.right));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
Exists deepCopy(const Exists &other)
{
return Exists(deepCopy(other.variables), deepCopy(other.argument));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ForAll deepCopy(const ForAll &other)
{
return ForAll(deepCopy(other.variables), deepCopy(other.argument));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
In deepCopy(const In &other)
{
return In(deepCopy(other.element), deepCopy(other.set));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
Implies deepCopy(const Implies &other)
{
return Implies(deepCopy(other.antecedent), deepCopy(other.consequent));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
Not deepCopy(const Not &other)
{
return Not(deepCopy(other.argument));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
Or deepCopy(const Or &other)
{
return Or(deepCopy(other.arguments));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
Formula deepCopy(const Formula &formula)
{
return deepCopyVariant(formula);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
std::vector<Formula> deepCopy(const std::vector<Formula> &formulas)
{
return deepCopyVariantVector(formulas);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
Term deepCopy(const Term &term)
{
return deepCopyVariant(term);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
std::vector<Term> deepCopy(const std::vector<Term> &terms)
{
return deepCopyVariantVector(terms);
}
////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@@ -24,60 +24,55 @@ struct And;
struct BinaryOperation;
struct Biconditional;
struct Boolean;
struct Comparison;
struct Constant;
struct Equals;
struct Exists;
struct ForAll;
struct Function;
struct Implies;
struct In;
struct Integer;
struct IntegerRange;
struct Interval;
struct Not;
struct Or;
struct Predicate;
struct SpecialInteger;
struct String;
struct Variable;
using AndPointer = std::unique_ptr<And>;
using BinaryOperationPointer = std::unique_ptr<BinaryOperation>;
using BiconditionalPointer = std::unique_ptr<Biconditional>;
using BooleanPointer = std::unique_ptr<Boolean>;
using ComparisonPointer = std::unique_ptr<Comparison>;
using ConstantPointer = std::unique_ptr<Constant>;
using EqualsPointer = std::unique_ptr<Equals>;
using ExistsPointer = std::unique_ptr<Exists>;
using ForAllPointer = std::unique_ptr<ForAll>;
using FunctionPointer = std::unique_ptr<Function>;
using ImpliesPointer = std::unique_ptr<Implies>;
using InPointer = std::unique_ptr<In>;
using IntegerPointer = std::unique_ptr<Integer>;
using IntegerRangePointer = std::unique_ptr<IntegerRange>;
using IntervalPointer = std::unique_ptr<Interval>;
using NotPointer = std::unique_ptr<Not>;
using OrPointer = std::unique_ptr<Or>;
using PredicatePointer = std::unique_ptr<Predicate>;
using SpecialIntegerPointer = std::unique_ptr<SpecialInteger>;
using StringPointer = std::unique_ptr<String>;
using VariablePointer = std::unique_ptr<Variable>;
////////////////////////////////////////////////////////////////////////////////////////////////////
// Variants
////////////////////////////////////////////////////////////////////////////////////////////////////
using TermT = mapbox::util::variant<
BinaryOperationPointer,
ConstantPointer,
IntegerPointer,
FunctionPointer,
VariablePointer>;
class Term : public TermT
{
using TermT::TermT;
};
using FormulaT = mapbox::util::variant<
AndPointer,
BiconditionalPointer,
BooleanPointer,
EqualsPointer,
ComparisonPointer,
ExistsPointer,
ForAllPointer,
ImpliesPointer,
InPointer,
NotPointer,
OrPointer,
PredicatePointer>;
@@ -87,7 +82,21 @@ class Formula : public FormulaT
using FormulaT::FormulaT;
};
using Formulas = std::vector<Formula>;
using TermT = mapbox::util::variant<
BinaryOperationPointer,
BooleanPointer,
ConstantPointer,
FunctionPointer,
IntegerPointer,
IntervalPointer,
SpecialIntegerPointer,
StringPointer,
VariablePointer>;
class Term : public TermT
{
using TermT::TermT;
};
////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@@ -3,9 +3,9 @@
#include <algorithm>
#include <anthem/Context.h>
#include <anthem/AST.h>
#include <anthem/Term.h>
#include <anthem/Utils.h>
#include <anthem/output/ClingoOutput.h>
#include <anthem/output/Formatting.h>
namespace anthem
@@ -17,204 +17,199 @@ namespace anthem
//
////////////////////////////////////////////////////////////////////////////////////////////////////
struct TermPrintVisitor
ast::Comparison::Operator translate(Clingo::AST::ComparisonOperator comparisonOperator)
{
void visit(const Clingo::Symbol &, const Clingo::AST::Literal &, const Clingo::AST::Term &term, Context &context)
switch (comparisonOperator)
{
case Clingo::AST::ComparisonOperator::GreaterThan:
return ast::Comparison::Operator::GreaterThan;
case Clingo::AST::ComparisonOperator::LessThan:
return ast::Comparison::Operator::LessThan;
case Clingo::AST::ComparisonOperator::LessEqual:
return ast::Comparison::Operator::LessEqual;
case Clingo::AST::ComparisonOperator::GreaterEqual:
return ast::Comparison::Operator::GreaterEqual;
case Clingo::AST::ComparisonOperator::NotEqual:
return ast::Comparison::Operator::NotEqual;
case Clingo::AST::ComparisonOperator::Equal:
return ast::Comparison::Operator::Equal;
}
return ast::Comparison::Operator::NotEqual;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ast::VariablePointer makeAuxiliaryBodyVariable(const int i)
{
auto variableName = std::string(AuxiliaryBodyVariablePrefix) + std::to_string(i);
return std::make_unique<ast::Variable>(std::move(variableName), ast::Variable::Type::Reserved);
};
////////////////////////////////////////////////////////////////////////////////////////////////////
struct BodyTermTranslateVisitor
{
std::experimental::optional<ast::Formula> visit(const Clingo::Symbol &, const Clingo::AST::Literal &, const Clingo::AST::Term &term, Context &context)
{
throwErrorAtLocation(term.location, "“symbol” terms currently unsupported in this context", context);
return std::experimental::nullopt;
}
void visit(const Clingo::AST::Variable &, const Clingo::AST::Literal &, const Clingo::AST::Term &term, Context &context)
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Variable &, const Clingo::AST::Literal &, const Clingo::AST::Term &term, Context &context)
{
throwErrorAtLocation(term.location, "“variable” terms currently unsupported in this context", context);
return std::experimental::nullopt;
}
void visit(const Clingo::AST::UnaryOperation &, const Clingo::AST::Literal &, const Clingo::AST::Term &term, Context &context)
std::experimental::optional<ast::Formula> visit(const Clingo::AST::UnaryOperation &, const Clingo::AST::Literal &, const Clingo::AST::Term &term, Context &context)
{
throwErrorAtLocation(term.location, "“unary operation” terms currently unsupported in this context", context);
return std::experimental::nullopt;
}
void visit(const Clingo::AST::BinaryOperation &, const Clingo::AST::Literal &, const Clingo::AST::Term &term, Context &context)
std::experimental::optional<ast::Formula> visit(const Clingo::AST::BinaryOperation &, const Clingo::AST::Literal &, const Clingo::AST::Term &term, Context &context)
{
throwErrorAtLocation(term.location, "“binary operation” terms currently unsupported in this context", context);
return std::experimental::nullopt;
}
void visit(const Clingo::AST::Interval &, const Clingo::AST::Literal &, const Clingo::AST::Term &term, Context &context)
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Interval &, const Clingo::AST::Literal &, const Clingo::AST::Term &term, Context &context)
{
throwErrorAtLocation(term.location, "“interval” terms currently unsupported in this context", context);
return std::experimental::nullopt;
}
// TODO: check correctness
void visit(const Clingo::AST::Function &function, const Clingo::AST::Literal &literal, const Clingo::AST::Term &, Context &context)
// TODO: refactor
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Function &function, const Clingo::AST::Literal &literal, const Clingo::AST::Term &, Context &context)
{
if (literal.sign == Clingo::AST::Sign::DoubleNegation)
throwErrorAtLocation(literal.location, "double-negated literals currently unsupported", context);
auto &outputStream = context.logger.outputStream();
if (function.arguments.empty())
return std::make_unique<ast::Predicate>(std::string(function.name));
std::vector<ast::VariablePointer> variables;
variables.reserve(function.arguments.size());
for (size_t i = 0; i < function.arguments.size(); i++)
variables.emplace_back(makeAuxiliaryBodyVariable(context.auxiliaryBodyLiteralID + i));
auto conjunction = std::make_unique<ast::And>();
for (size_t i = 0; i < function.arguments.size(); i++)
{
outputStream << output::Function(function.name);
return;
const auto &argument = function.arguments[i];
conjunction->arguments.emplace_back(std::make_unique<ast::In>(makeAuxiliaryBodyVariable(context.auxiliaryBodyLiteralID + i), translate(argument, context)));
}
outputStream << output::Keyword("exists") << " ";
auto predicate = std::make_unique<ast::Predicate>(std::string(function.name));
predicate->arguments.reserve(function.arguments.size());
for (auto i = function.arguments.cbegin(); i != function.arguments.cend(); i++)
{
if (i != function.arguments.cbegin())
outputStream << ", ";
for (size_t i = 0; i < function.arguments.size(); i++)
predicate->arguments.emplace_back(makeAuxiliaryBodyVariable(context.auxiliaryBodyLiteralID + i));
const auto variableName = std::string(AuxiliaryBodyVariablePrefix) + std::to_string(context.auxiliaryBodyLiteralID + i - function.arguments.cbegin());
outputStream << output::Variable(variableName.c_str());
}
outputStream << " (";
for (auto i = function.arguments.cbegin(); i != function.arguments.cend(); i++)
{
const auto &argument = *i;
if (i != function.arguments.cbegin())
outputStream << " " << Clingo::AST::BinaryOperator::And << " ";
const auto variableName = std::string(AuxiliaryBodyVariablePrefix) + std::to_string(context.auxiliaryBodyLiteralID + i - function.arguments.cbegin());
outputStream
<< output::Variable(variableName.c_str())
<< " " << output::Keyword("in") << " "
<< argument;
}
outputStream
<< " " << Clingo::AST::BinaryOperator::And << " "
<< literal.sign
<< output::Function(function.name) << "(";
for (auto i = function.arguments.cbegin(); i != function.arguments.cend(); i++)
{
if (i != function.arguments.cbegin())
outputStream << ", ";
const auto variableName = std::string(AuxiliaryBodyVariablePrefix) + std::to_string(context.auxiliaryBodyLiteralID + i - function.arguments.cbegin());
outputStream << output::Variable(variableName.c_str());
}
outputStream << "))";
if (literal.sign == Clingo::AST::Sign::None)
conjunction->arguments.emplace_back(std::move(predicate));
else
conjunction->arguments.emplace_back(std::make_unique<ast::Not>(std::move(predicate)));
context.auxiliaryBodyLiteralID += function.arguments.size();
return std::make_unique<ast::Exists>(std::move(variables), std::move(conjunction));
}
void visit(const Clingo::AST::Pool &, const Clingo::AST::Literal &, const Clingo::AST::Term &term, Context &context)
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Pool &, const Clingo::AST::Literal &, const Clingo::AST::Term &term, Context &context)
{
throwErrorAtLocation(term.location, "“pool” terms currently unsupported", context);
return std::experimental::nullopt;
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////
struct LiteralPrintVisitor
struct BodyLiteralTranslateVisitor
{
void visit(const Clingo::AST::Boolean &, const Clingo::AST::Literal &literal, Context &context)
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Boolean &, const Clingo::AST::Literal &literal, Context &context)
{
throwErrorAtLocation(literal.location, "“boolean” literals currently unsupported in this context", context);
return std::experimental::nullopt;
}
void 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)
{
term.data.accept(TermPrintVisitor(), literal, term, context);
return term.data.accept(BodyTermTranslateVisitor(), literal, term, context);
return std::experimental::nullopt;
}
// TODO: refactor
void visit(const Clingo::AST::Comparison &comparison, const Clingo::AST::Literal &literal, Context &context)
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Comparison &comparison, const Clingo::AST::Literal &literal, Context &context)
{
assert(literal.sign == Clingo::AST::Sign::None);
const char *operatorName = "";
const auto operator_ = translate(comparison.comparison);
switch (comparison.comparison)
{
case Clingo::AST::ComparisonOperator::GreaterThan:
operatorName = ">";
break;
case Clingo::AST::ComparisonOperator::LessThan:
operatorName = "<";
break;
case Clingo::AST::ComparisonOperator::LessEqual:
operatorName = "<=";
break;
case Clingo::AST::ComparisonOperator::GreaterEqual:
operatorName = ">=";
break;
case Clingo::AST::ComparisonOperator::NotEqual:
operatorName = "!=";
break;
case Clingo::AST::ComparisonOperator::Equal:
operatorName = "=";
break;
}
std::vector<ast::VariablePointer> variables;
variables.reserve(2);
variables.emplace_back(makeAuxiliaryBodyVariable(context.auxiliaryBodyLiteralID));
variables.emplace_back(makeAuxiliaryBodyVariable(context.auxiliaryBodyLiteralID + 1));
const auto variableName1 = std::string(AuxiliaryBodyVariablePrefix) + std::to_string(context.auxiliaryBodyLiteralID);
const auto variableName2 = std::string(AuxiliaryBodyVariablePrefix) + std::to_string(context.auxiliaryBodyLiteralID + 1);
context.logger.outputStream()
<< output::Keyword("exists") << " " << output::Variable(variableName1.c_str())
<< ", " << output::Variable(variableName2.c_str())
<< " ("
<< output::Variable(variableName1.c_str())
<< " " << output::Keyword("in") << " " << comparison.left
<< " " << Clingo::AST::BinaryOperator::And << " "
<< output::Variable(variableName2.c_str())
<< " " << output::Keyword("in") << " " << comparison.right
<< " " << Clingo::AST::BinaryOperator::And << " "
<< output::Variable(variableName1.c_str())
<< " " << output::Operator(operatorName) << " "
<< output::Variable(variableName2.c_str())
<< ")";
auto conjunction = std::make_unique<ast::And>();
conjunction->arguments.reserve(3);
conjunction->arguments.emplace_back(std::make_unique<ast::In>(makeAuxiliaryBodyVariable(context.auxiliaryBodyLiteralID), translate(comparison.left, context)));
conjunction->arguments.emplace_back(std::make_unique<ast::In>(makeAuxiliaryBodyVariable(context.auxiliaryBodyLiteralID + 1), translate(comparison.right, context)));
conjunction->arguments.emplace_back(std::make_unique<ast::Comparison>(operator_, makeAuxiliaryBodyVariable(context.auxiliaryBodyLiteralID), makeAuxiliaryBodyVariable(context.auxiliaryBodyLiteralID + 1)));
context.auxiliaryBodyLiteralID += 2;
return std::make_unique<ast::Exists>(std::move(variables), std::move(conjunction));
}
void visit(const Clingo::AST::CSPLiteral &, const Clingo::AST::Literal &literal, Context &context)
std::experimental::optional<ast::Formula> visit(const Clingo::AST::CSPLiteral &, const Clingo::AST::Literal &literal, Context &context)
{
throwErrorAtLocation(literal.location, "CSP literals currently unsupported", context);
return std::experimental::nullopt;
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////
struct BodyLiteralPrintVisitor
struct BodyBodyLiteralTranslateVisitor
{
void visit(const Clingo::AST::Literal &literal, const Clingo::AST::BodyLiteral &, Context &context)
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Literal &literal, const Clingo::AST::BodyLiteral &, Context &context)
{
literal.data.accept(LiteralPrintVisitor(), literal, context);
return literal.data.accept(BodyLiteralTranslateVisitor(), literal, context);
}
void visit(const Clingo::AST::ConditionalLiteral &, const Clingo::AST::BodyLiteral &bodyLiteral, Context &context)
std::experimental::optional<ast::Formula> visit(const Clingo::AST::ConditionalLiteral &, const Clingo::AST::BodyLiteral &bodyLiteral, Context &context)
{
throwErrorAtLocation(bodyLiteral.location, "“conditional literal” body literals currently unsupported", context);
return std::experimental::nullopt;
}
void visit(const Clingo::AST::Aggregate &, const Clingo::AST::BodyLiteral &bodyLiteral, Context &context)
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Aggregate &, const Clingo::AST::BodyLiteral &bodyLiteral, Context &context)
{
throwErrorAtLocation(bodyLiteral.location, "“aggregate” body literals currently unsupported", context);
return std::experimental::nullopt;
}
void visit(const Clingo::AST::BodyAggregate &, const Clingo::AST::BodyLiteral &bodyLiteral, Context &context)
std::experimental::optional<ast::Formula> visit(const Clingo::AST::BodyAggregate &, const Clingo::AST::BodyLiteral &bodyLiteral, Context &context)
{
throwErrorAtLocation(bodyLiteral.location, "“body aggregate” body literals currently unsupported", context);
return std::experimental::nullopt;
}
void visit(const Clingo::AST::TheoryAtom &, const Clingo::AST::BodyLiteral &bodyLiteral, Context &context)
std::experimental::optional<ast::Formula> visit(const Clingo::AST::TheoryAtom &, const Clingo::AST::BodyLiteral &bodyLiteral, Context &context)
{
throwErrorAtLocation(bodyLiteral.location, "“theory atom” body literals currently unsupported", context);
return std::experimental::nullopt;
}
void visit(const Clingo::AST::Disjoint &, const Clingo::AST::BodyLiteral &bodyLiteral, Context &context)
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Disjoint &, const Clingo::AST::BodyLiteral &bodyLiteral, Context &context)
{
throwErrorAtLocation(bodyLiteral.location, "“disjoint” body literals currently unsupported", context);
return std::experimental::nullopt;
}
};

View File

@@ -3,8 +3,8 @@
#include <algorithm>
#include <anthem/AST.h>
#include <anthem/Utils.h>
#include <anthem/output/ClingoOutput.h>
#include <anthem/output/Formatting.h>
namespace anthem
@@ -139,155 +139,179 @@ struct HeadLiteralCollectFunctionTermsVisitor
////////////////////////////////////////////////////////////////////////////////////////////////////
struct TermPrintSubstitutedVisitor
struct FunctionTermTranslateVisitor
{
void visit(const Clingo::Symbol &, const Clingo::AST::Term &term, Context &context)
std::experimental::optional<ast::Formula> visit(const Clingo::Symbol &, const Clingo::AST::Term &term, Context &context)
{
throwErrorAtLocation(term.location, "“symbol” terms not allowed, function expected", context);
return std::experimental::nullopt;
}
void visit(const Clingo::AST::Variable &, const Clingo::AST::Term &term, Context &context)
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Variable &, const Clingo::AST::Term &term, Context &context)
{
throwErrorAtLocation(term.location, "“variable” terms currently unsupported, function expected", context);
return std::experimental::nullopt;
}
void visit(const Clingo::AST::UnaryOperation &, const Clingo::AST::Term &term, Context &context)
std::experimental::optional<ast::Formula> visit(const Clingo::AST::UnaryOperation &, const Clingo::AST::Term &term, Context &context)
{
throwErrorAtLocation(term.location, "“unary operation” terms currently unsupported, function expected", context);
return std::experimental::nullopt;
}
void visit(const Clingo::AST::BinaryOperation &, const Clingo::AST::Term &term, Context &context)
std::experimental::optional<ast::Formula> visit(const Clingo::AST::BinaryOperation &, const Clingo::AST::Term &term, Context &context)
{
throwErrorAtLocation(term.location, "“binary operation” terms currently unsupported, function expected", context);
return std::experimental::nullopt;
}
void visit(const Clingo::AST::Interval &, const Clingo::AST::Term &term, Context &context)
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Interval &, const Clingo::AST::Term &term, Context &context)
{
throwErrorAtLocation(term.location, "“interval” terms currently unsupported, function expected", context);
return std::experimental::nullopt;
}
// TODO: check correctness
void visit(const Clingo::AST::Function &function, const Clingo::AST::Term &term, Context &context)
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Function &function, const Clingo::AST::Term &term, Context &context)
{
if (function.external)
throwErrorAtLocation(term.location, "external functions currently unsupported", context);
auto &outputStream = context.logger.outputStream();
outputStream << output::Function(function.name);
if (function.arguments.empty())
return;
outputStream << "(";
std::vector<ast::Term> arguments;
arguments.reserve(function.arguments.size());
for (auto i = function.arguments.cbegin(); i != function.arguments.cend(); i++)
{
if (i != function.arguments.cbegin())
outputStream << ", ";
const auto &argument = *i;
const auto matchingTerm = std::find(context.headTerms.cbegin(), context.headTerms.cend(), &argument);
assert(matchingTerm != context.headTerms.cend());
const auto variableName = std::string(AuxiliaryHeadVariablePrefix) + std::to_string(matchingTerm - context.headTerms.cbegin() + 1);
outputStream << output::Variable(variableName.c_str());
auto variableName = std::string(AuxiliaryHeadVariablePrefix) + std::to_string(matchingTerm - context.headTerms.cbegin() + 1);
arguments.emplace_back(std::make_unique<ast::Variable>(std::move(variableName), ast::Variable::Type::Reserved));
}
outputStream << ")";
return std::make_unique<ast::Predicate>(function.name, std::move(arguments));
}
void visit(const Clingo::AST::Pool &, const Clingo::AST::Term &term, Context &context)
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Pool &, const Clingo::AST::Term &term, Context &context)
{
throwErrorAtLocation(term.location, "“pool” terms currently unsupported, function expected", context);
return std::experimental::nullopt;
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////
struct LiteralPrintSubstitutedVisitor
struct LiteralTranslateVisitor
{
void visit(const Clingo::AST::Boolean &boolean, const Clingo::AST::Literal &, Context &context)
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Boolean &boolean, const Clingo::AST::Literal &, Context &)
{
context.logger.outputStream() << boolean;
return std::make_unique<ast::Boolean>(boolean.value);
}
void visit(const Clingo::AST::Term &term, const Clingo::AST::Literal &, Context &context)
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Term &term, const Clingo::AST::Literal &, Context &context)
{
term.data.accept(TermPrintSubstitutedVisitor(), term, context);
return term.data.accept(FunctionTermTranslateVisitor(), term, context);
}
void visit(const Clingo::AST::Comparison &, const Clingo::AST::Literal &literal, Context &context)
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Comparison &, const Clingo::AST::Literal &literal, Context &context)
{
throwErrorAtLocation(literal.location, "only disjunctions of literals allowed as head literals", context);
return std::experimental::nullopt;
}
void visit(const Clingo::AST::CSPLiteral &, const Clingo::AST::Literal &literal, Context &context)
std::experimental::optional<ast::Formula> visit(const Clingo::AST::CSPLiteral &, const Clingo::AST::Literal &literal, Context &context)
{
throwErrorAtLocation(literal.location, "only disjunctions of literals allowed as head literals", context);
return std::experimental::nullopt;
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////
struct HeadLiteralPrintSubstitutedVisitor
struct HeadLiteralTranslateToConsequentVisitor
{
void visit(const Clingo::AST::Literal &literal, const Clingo::AST::HeadLiteral &, Context &context)
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Literal &literal, const Clingo::AST::HeadLiteral &, Context &context)
{
if (literal.sign == Clingo::AST::Sign::DoubleNegation)
throwErrorAtLocation(literal.location, "double-negated literals currently unsupported", context);
throwErrorAtLocation(literal.location, "double-negated head literals currently unsupported", context);
context.logger.outputStream() << literal.sign;
auto translatedLiteral = literal.data.accept(LiteralTranslateVisitor(), literal, context);
literal.data.accept(LiteralPrintSubstitutedVisitor(), literal, context);
if (literal.sign == Clingo::AST::Sign::None)
return translatedLiteral;
if (!translatedLiteral)
return std::experimental::nullopt;
return std::make_unique<ast::Not>(std::move(translatedLiteral.value()));
}
void visit(const Clingo::AST::Disjunction &disjunction, const Clingo::AST::HeadLiteral &headLiteral, Context &context)
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Disjunction &disjunction, const Clingo::AST::HeadLiteral &headLiteral, Context &context)
{
for (auto i = disjunction.elements.cbegin(); i != disjunction.elements.cend(); i++)
{
const auto &conditionalLiteral = *i;
std::vector<ast::Formula> arguments;
arguments.reserve(disjunction.elements.size());
for (const auto &conditionalLiteral : disjunction.elements)
{
if (!conditionalLiteral.condition.empty())
throwErrorAtLocation(headLiteral.location, "conditional head literals currently unsupported", context);
if (i != disjunction.elements.cbegin())
context.logger.outputStream() << " " << Clingo::AST::BinaryOperator::Or << " ";
auto argument = visit(conditionalLiteral.literal, headLiteral, context);
visit(conditionalLiteral.literal, headLiteral, context);
if (!argument)
throwErrorAtLocation(headLiteral.location, "could not parse argument", context);
arguments.emplace_back(std::move(argument.value()));
}
return std::make_unique<ast::Or>(std::move(arguments));
}
void visit(const Clingo::AST::Aggregate &aggregate, const Clingo::AST::HeadLiteral &headLiteral, Context &context)
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Aggregate &aggregate, const Clingo::AST::HeadLiteral &headLiteral, Context &context)
{
if (aggregate.left_guard || aggregate.right_guard)
throwErrorAtLocation(headLiteral.location, "aggregates with left or right guards not allowed", context);
for (auto i = aggregate.elements.cbegin(); i != aggregate.elements.cend(); i++)
const auto translateConditionalLiteral =
[&](const auto &conditionalLiteral)
{
if (!conditionalLiteral.condition.empty())
throwErrorAtLocation(headLiteral.location, "conditional head literals currently unsupported", context);
return this->visit(conditionalLiteral.literal, headLiteral, context);
};
if (aggregate.elements.size() == 1)
return translateConditionalLiteral(aggregate.elements[0]);
std::vector<ast::Formula> arguments;
arguments.reserve(aggregate.elements.size());
for (const auto &conditionalLiteral : aggregate.elements)
{
const auto &conditionalLiteral = *i;
auto argument = translateConditionalLiteral(conditionalLiteral);
if (!conditionalLiteral.condition.empty())
throwErrorAtLocation(headLiteral.location, "conditional head literals currently unsupported", context);
if (!argument)
throwErrorAtLocation(headLiteral.location, "could not parse argument", context);
if (i != aggregate.elements.cbegin())
context.logger.outputStream() << " " << Clingo::AST::BinaryOperator::Or << " ";
visit(conditionalLiteral.literal, headLiteral, context);
arguments.emplace_back(std::move(argument.value()));
}
return std::make_unique<ast::Or>(std::move(arguments));
}
void visit(const Clingo::AST::HeadAggregate &, const Clingo::AST::HeadLiteral &headLiteral, Context &context)
std::experimental::optional<ast::Formula> visit(const Clingo::AST::HeadAggregate &, const Clingo::AST::HeadLiteral &headLiteral, Context &context)
{
throwErrorAtLocation(headLiteral.location, "“head aggregate” head literals currently unsupported", context);
return std::experimental::nullopt;
}
void visit(const Clingo::AST::TheoryAtom &, const Clingo::AST::HeadLiteral &headLiteral, Context &context)
std::experimental::optional<ast::Formula> visit(const Clingo::AST::TheoryAtom &, const Clingo::AST::HeadLiteral &headLiteral, Context &context)
{
throwErrorAtLocation(headLiteral.location, "“theory” head literals currently unsupported", context);
return std::experimental::nullopt;
}
};

View File

@@ -1,10 +1,11 @@
#ifndef __ANTHEM__STATEMENT_VISITOR_H
#define __ANTHEM__STATEMENT_VISITOR_H
#include <anthem/AST.h>
#include <anthem/Body.h>
#include <anthem/Head.h>
#include <anthem/Term.h>
#include <anthem/Utils.h>
#include <anthem/output/ClingoOutput.h>
namespace anthem
{
@@ -17,37 +18,46 @@ namespace anthem
struct StatementVisitor
{
void visit(const Clingo::AST::Program &program, const Clingo::AST::Statement &statement, Context &context)
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Program &program, const Clingo::AST::Statement &statement, Context &context)
{
// TODO: refactor
context.logger.log(output::Priority::Debug, (std::string("[program] ") + program.name).c_str());
if (!program.parameters.empty())
throwErrorAtLocation(statement.location, "program parameters currently unsupported", context);
return std::experimental::nullopt;
}
void visit(const Clingo::AST::Rule &rule, const Clingo::AST::Statement &, Context &context)
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Rule &rule, const Clingo::AST::Statement &, Context &context)
{
context.reset();
auto &outputStream = context.logger.outputStream();
// Concatenate all head terms
rule.head.data.accept(HeadLiteralCollectFunctionTermsVisitor(), rule.head, context);
auto antecedent = std::make_unique<ast::And>();
// Compute consequent
auto consequent = rule.head.data.accept(HeadLiteralTranslateToConsequentVisitor(), rule.head, context);
if (!consequent)
{
context.logger.log(output::Priority::Error, "could not translate formula consequent");
return std::experimental::nullopt;
}
// Print auxiliary variables replacing the head atoms arguments
for (auto i = context.headTerms.cbegin(); i != context.headTerms.cend(); i++)
{
const auto &headTerm = **i;
if (i != context.headTerms.cbegin())
outputStream << " " << Clingo::AST::BinaryOperator::And << " ";
auto variableName = std::string(AuxiliaryHeadVariablePrefix) + std::to_string(i - context.headTerms.cbegin() + 1);
auto element = std::make_unique<ast::Variable>(std::move(variableName), ast::Variable::Type::Reserved);
auto set = translate(headTerm, context);
auto in = std::make_unique<ast::In>(std::move(element), std::move(set));
const auto variableName = std::string(AuxiliaryHeadVariablePrefix) + std::to_string(i - context.headTerms.cbegin() + 1);
outputStream
<< output::Variable(variableName.c_str())
<< " " << output::Keyword("in") << " " << headTerm;
antecedent->arguments.emplace_back(std::move(in));
}
// Print translated body literals
@@ -55,97 +65,94 @@ struct StatementVisitor
{
const auto &bodyLiteral = *i;
if (!context.headTerms.empty() || i != rule.body.cbegin())
outputStream << " " << Clingo::AST::BinaryOperator::And << " ";
if (bodyLiteral.sign != Clingo::AST::Sign::None)
throwErrorAtLocation(bodyLiteral.location, "only positive literals currently supported", context);
bodyLiteral.data.accept(BodyLiteralPrintVisitor(), bodyLiteral, context);
auto argument = bodyLiteral.data.accept(BodyBodyLiteralTranslateVisitor(), bodyLiteral, context);
if (!argument)
throwErrorAtLocation(bodyLiteral.location, "could not translate body literal", context);
antecedent->arguments.emplace_back(std::move(argument.value()));
}
// Handle choice rules
if (context.isChoiceRule)
{
const bool isFirstOutput = rule.body.empty() && context.headTerms.empty();
antecedent->arguments.emplace_back(ast::deepCopy(consequent.value()));
if (!isFirstOutput)
outputStream << " " << Clingo::AST::BinaryOperator::And << " ";
// Use “true” as the consequent in case it is empty
if (antecedent->arguments.empty())
return std::make_unique<ast::Implies>(std::make_unique<ast::Boolean>(true), std::move(consequent.value()));
else if (antecedent->arguments.size() == 1)
return std::make_unique<ast::Implies>(std::move(antecedent->arguments[0]), std::move(consequent.value()));
if (context.numberOfHeadLiterals > 1 && !isFirstOutput)
outputStream << "(";
rule.head.data.accept(HeadLiteralPrintSubstitutedVisitor(), rule.head, context);
if (context.numberOfHeadLiterals > 1 && !isFirstOutput)
outputStream << ")";
}
// Print “true” on the left side of the formula in case there is nothing else
if (rule.body.empty() && context.headTerms.empty() && !context.isChoiceRule)
outputStream << Clingo::AST::Boolean({true});
outputStream << " " << output::Operator("->") << " ";
// Print consequent of the implication
rule.head.data.accept(HeadLiteralPrintSubstitutedVisitor(), rule.head, context);
outputStream << std::endl;
return std::make_unique<ast::Implies>(std::move(antecedent), std::move(consequent.value()));
}
void visit(const Clingo::AST::Definition &, const Clingo::AST::Statement &statement, Context &context)
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Definition &, const Clingo::AST::Statement &statement, Context &context)
{
throwErrorAtLocation(statement.location, "“definition” statements currently unsupported", context);
return std::experimental::nullopt;
}
void visit(const Clingo::AST::ShowSignature &, const Clingo::AST::Statement &statement, Context &context)
std::experimental::optional<ast::Formula> visit(const Clingo::AST::ShowSignature &, const Clingo::AST::Statement &statement, Context &context)
{
throwErrorAtLocation(statement.location, "“show signature” statements currently unsupported", context);
return std::experimental::nullopt;
}
void visit(const Clingo::AST::ShowTerm &, const Clingo::AST::Statement &statement, Context &context)
std::experimental::optional<ast::Formula> visit(const Clingo::AST::ShowTerm &, const Clingo::AST::Statement &statement, Context &context)
{
throwErrorAtLocation(statement.location, "“show term” statements currently unsupported", context);
return std::experimental::nullopt;
}
void visit(const Clingo::AST::Minimize &, const Clingo::AST::Statement &statement, Context &context)
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Minimize &, const Clingo::AST::Statement &statement, Context &context)
{
throwErrorAtLocation(statement.location, "“minimize” statements currently unsupported", context);
return std::experimental::nullopt;
}
void visit(const Clingo::AST::Script &, const Clingo::AST::Statement &statement, Context &context)
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Script &, const Clingo::AST::Statement &statement, Context &context)
{
throwErrorAtLocation(statement.location, "“script” statements currently unsupported", context);
return std::experimental::nullopt;
}
void visit(const Clingo::AST::External &, const Clingo::AST::Statement &statement, Context &context)
std::experimental::optional<ast::Formula> visit(const Clingo::AST::External &, const Clingo::AST::Statement &statement, Context &context)
{
throwErrorAtLocation(statement.location, "“external” statements currently unsupported", context);
return std::experimental::nullopt;
}
void visit(const Clingo::AST::Edge &, const Clingo::AST::Statement &statement, Context &context)
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Edge &, const Clingo::AST::Statement &statement, Context &context)
{
throwErrorAtLocation(statement.location, "“edge” statements currently unsupported", context);
return std::experimental::nullopt;
}
void visit(const Clingo::AST::Heuristic &, const Clingo::AST::Statement &statement, Context &context)
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Heuristic &, const Clingo::AST::Statement &statement, Context &context)
{
throwErrorAtLocation(statement.location, "“heuristic” statements currently unsupported", context);
return std::experimental::nullopt;
}
void visit(const Clingo::AST::ProjectAtom &, const Clingo::AST::Statement &statement, Context &context)
std::experimental::optional<ast::Formula> visit(const Clingo::AST::ProjectAtom &, const Clingo::AST::Statement &statement, Context &context)
{
throwErrorAtLocation(statement.location, "“project atom” statements currently unsupported", context);
return std::experimental::nullopt;
}
void visit(const Clingo::AST::ProjectSignature &, const Clingo::AST::Statement &statement, Context &context)
std::experimental::optional<ast::Formula> visit(const Clingo::AST::ProjectSignature &, const Clingo::AST::Statement &statement, Context &context)
{
throwErrorAtLocation(statement.location, "“project signature” statements currently unsupported", context);
return std::experimental::nullopt;
}
void visit(const Clingo::AST::TheoryDefinition &, const Clingo::AST::Statement &statement, Context &context)
std::experimental::optional<ast::Formula> visit(const Clingo::AST::TheoryDefinition &, const Clingo::AST::Statement &statement, Context &context)
{
throwErrorAtLocation(statement.location, "“theory definition” statements currently unsupported", context);
return std::experimental::nullopt;
}
};

132
include/anthem/Term.h Normal file
View File

@@ -0,0 +1,132 @@
#ifndef __ANTHEM__TERM_H
#define __ANTHEM__TERM_H
#include <algorithm>
#include <anthem/AST.h>
#include <anthem/Utils.h>
#include <anthem/output/Formatting.h>
namespace anthem
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Term
//
////////////////////////////////////////////////////////////////////////////////////////////////////
ast::BinaryOperation::Operator translate(Clingo::AST::BinaryOperator binaryOperator, const Clingo::AST::Term &term, Context &context)
{
switch (binaryOperator)
{
case Clingo::AST::BinaryOperator::Plus:
return ast::BinaryOperation::Operator::Plus;
case Clingo::AST::BinaryOperator::Minus:
return ast::BinaryOperation::Operator::Minus;
case Clingo::AST::BinaryOperator::Multiplication:
return ast::BinaryOperation::Operator::Multiplication;
case Clingo::AST::BinaryOperator::Division:
return ast::BinaryOperation::Operator::Division;
case Clingo::AST::BinaryOperator::Modulo:
return ast::BinaryOperation::Operator::Modulo;
default:
throwErrorAtLocation(term.location, "“binary operation” terms currently unsupported", context);
}
return ast::BinaryOperation::Operator::Plus;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ast::Term translate(const Clingo::AST::Term &term, Context &context);
////////////////////////////////////////////////////////////////////////////////////////////////////
struct TermTranslateVisitor
{
std::experimental::optional<ast::Term> visit(const Clingo::Symbol &symbol, const Clingo::AST::Term &term, Context &context)
{
switch (symbol.type())
{
case Clingo::SymbolType::Number:
return std::make_unique<ast::Integer>(symbol.number());
case Clingo::SymbolType::Infimum:
return std::make_unique<ast::SpecialInteger>(ast::SpecialInteger::Type::Infimum);
case Clingo::SymbolType::Supremum:
return std::make_unique<ast::SpecialInteger>(ast::SpecialInteger::Type::Supremum);
case Clingo::SymbolType::String:
return std::make_unique<ast::String>(std::string(symbol.string()));
default:
throwErrorAtLocation(term.location, "only numeric “symbol” terms allowed", context);
}
return std::experimental::nullopt;
}
std::experimental::optional<ast::Term> visit(const Clingo::AST::Variable &variable, const Clingo::AST::Term &, Context &)
{
return std::make_unique<ast::Variable>(std::string(variable.name), ast::Variable::Type::UserDefined);
}
std::experimental::optional<ast::Term> visit(const Clingo::AST::UnaryOperation &, const Clingo::AST::Term &term, Context &context)
{
throwErrorAtLocation(term.location, "“unary operation” terms currently unsupported", context);
return std::experimental::nullopt;
}
std::experimental::optional<ast::Term> visit(const Clingo::AST::BinaryOperation &binaryOperation, const Clingo::AST::Term &term, Context &context)
{
const auto operator_ = translate(binaryOperation.binary_operator, term, context);
auto left = translate(binaryOperation.left, context);
auto right = translate(binaryOperation.right, context);
return std::make_unique<ast::BinaryOperation>(operator_, std::move(left), std::move(right));
}
std::experimental::optional<ast::Term> visit(const Clingo::AST::Interval &interval, const Clingo::AST::Term &, Context &context)
{
auto left = translate(interval.left, context);
auto right = translate(interval.right, context);
return std::make_unique<ast::Interval>(std::move(left), std::move(right));
}
std::experimental::optional<ast::Term> visit(const Clingo::AST::Function &function, const Clingo::AST::Term &term, Context &context)
{
if (function.external)
throwErrorAtLocation(term.location, "external functions currently unsupported", context);
std::vector<ast::Term> arguments;
arguments.reserve(function.arguments.size());
for (const auto &argument : function.arguments)
arguments.emplace_back(translate(argument, context));
return std::make_unique<ast::Function>(function.name, std::move(arguments));
}
std::experimental::optional<ast::Term> visit(const Clingo::AST::Pool &, const Clingo::AST::Term &term, Context &context)
{
throwErrorAtLocation(term.location, "“pool” terms currently unsupported", context);
return std::experimental::nullopt;
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////
ast::Term translate(const Clingo::AST::Term &term, Context &context)
{
auto translatedTerm = term.data.accept(TermTranslateVisitor(), term, context);
if (!translatedTerm)
throwErrorAtLocation(term.location, "could not translate term", context);
return std::move(translatedTerm.value());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
#endif

345
include/anthem/output/AST.h Normal file
View File

@@ -0,0 +1,345 @@
#ifndef __ANTHEM__OUTPUT__AST_H
#define __ANTHEM__OUTPUT__AST_H
#include <cassert>
#include <anthem/AST.h>
#include <anthem/Utils.h>
#include <anthem/output/ColorStream.h>
#include <anthem/output/Formatting.h>
namespace anthem
{
namespace ast
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// AST
//
////////////////////////////////////////////////////////////////////////////////////////////////////
output::ColorStream &operator<<(output::ColorStream &stream, BinaryOperation::Operator operator_);
output::ColorStream &operator<<(output::ColorStream &stream, const BinaryOperation &binaryOperation);
output::ColorStream &operator<<(output::ColorStream &stream, const Boolean &boolean);
output::ColorStream &operator<<(output::ColorStream &stream, const Comparison &comparison);
output::ColorStream &operator<<(output::ColorStream &stream, const Constant &constant);
output::ColorStream &operator<<(output::ColorStream &stream, const Function &function);
output::ColorStream &operator<<(output::ColorStream &stream, const In &in);
output::ColorStream &operator<<(output::ColorStream &stream, const Integer &integer);
output::ColorStream &operator<<(output::ColorStream &stream, const Interval &interval);
output::ColorStream &operator<<(output::ColorStream &stream, const Predicate &predicate);
output::ColorStream &operator<<(output::ColorStream &stream, const SpecialInteger &specialInteger);
output::ColorStream &operator<<(output::ColorStream &stream, const String &string);
output::ColorStream &operator<<(output::ColorStream &stream, const Variable &variable);
output::ColorStream &operator<<(output::ColorStream &stream, const And &and_);
output::ColorStream &operator<<(output::ColorStream &stream, const Biconditional &biconditional);
output::ColorStream &operator<<(output::ColorStream &stream, const Exists &exists);
output::ColorStream &operator<<(output::ColorStream &stream, const ForAll &forAll);
output::ColorStream &operator<<(output::ColorStream &stream, const Implies &implies);
output::ColorStream &operator<<(output::ColorStream &stream, const Not &not_);
output::ColorStream &operator<<(output::ColorStream &stream, const Or &or_);
output::ColorStream &operator<<(output::ColorStream &stream, const Formula &formula);
output::ColorStream &operator<<(output::ColorStream &stream, const Term &term);
////////////////////////////////////////////////////////////////////////////////////////////////////
// Primitives
////////////////////////////////////////////////////////////////////////////////////////////////////
output::ColorStream &operator<<(output::ColorStream &stream, BinaryOperation::Operator operator_)
{
switch (operator_)
{
case BinaryOperation::Operator::Plus:
return (stream << output::Operator("+"));
case BinaryOperation::Operator::Minus:
return (stream << output::Operator("-"));
case BinaryOperation::Operator::Multiplication:
return (stream << output::Operator("*"));
case BinaryOperation::Operator::Division:
return (stream << output::Operator("/"));
case BinaryOperation::Operator::Modulo:
return (stream << output::Operator("%"));
}
return stream;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
output::ColorStream &operator<<(output::ColorStream &stream, const BinaryOperation &binaryOperation)
{
return (stream << "(" << binaryOperation.left << " " << binaryOperation.operator_ << " " << binaryOperation.right << ")");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
output::ColorStream &operator<<(output::ColorStream &stream, const Boolean &boolean)
{
if (boolean.value)
return (stream << output::Boolean("#true"));
return (stream << output::Boolean("#false"));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
output::ColorStream &operator<<(output::ColorStream &stream, Comparison::Operator operator_)
{
switch (operator_)
{
case Comparison::Operator::GreaterThan:
return (stream << output::Operator(">"));
case Comparison::Operator::LessThan:
return (stream << output::Operator("<"));
case Comparison::Operator::LessEqual:
return (stream << output::Operator("<="));
case Comparison::Operator::GreaterEqual:
return (stream << output::Operator(">="));
case Comparison::Operator::NotEqual:
return (stream << output::Operator("!="));
case Comparison::Operator::Equal:
return (stream << output::Operator("="));
}
return stream;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
output::ColorStream &operator<<(output::ColorStream &stream, const Comparison &comparison)
{
return (stream << comparison.left << " " << comparison.operator_ << " " << comparison.right);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
output::ColorStream &operator<<(output::ColorStream &stream, const Constant &constant)
{
return (stream << constant.name);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
output::ColorStream &operator<<(output::ColorStream &stream, const Function &function)
{
stream << function.name;
if (function.arguments.empty())
return stream;
stream << "(";
for (auto i = function.arguments.cbegin(); i != function.arguments.cend(); i++)
{
if (i != function.arguments.cbegin())
stream << ", ";
stream << (*i);
}
if (function.name.empty() && function.arguments.size() == 1)
stream << ",";
return (stream << ")");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
output::ColorStream &operator<<(output::ColorStream &stream, const In &in)
{
return (stream << in.element << " " << output::Keyword("in") << " " << in.set);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
output::ColorStream &operator<<(output::ColorStream &stream, const Integer &integer)
{
return (stream << output::Number<int>(integer.value));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
output::ColorStream &operator<<(output::ColorStream &stream, const Interval &interval)
{
return (stream << interval.from << ".." << interval.to);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
output::ColorStream &operator<<(output::ColorStream &stream, const Predicate &predicate)
{
stream << predicate.name;
if (predicate.arguments.empty())
return stream;
stream << "(";
for (auto i = predicate.arguments.cbegin(); i != predicate.arguments.cend(); i++)
{
if (i != predicate.arguments.cbegin())
stream << ", ";
stream << (*i);
}
return (stream << ")");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
output::ColorStream &operator<<(output::ColorStream &stream, const SpecialInteger &specialInteger)
{
switch (specialInteger.type)
{
case SpecialInteger::Type::Infimum:
return (stream << output::Number<std::string>("#inf"));
case SpecialInteger::Type::Supremum:
return (stream << output::Number<std::string>("#sup"));
}
return stream;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
output::ColorStream &operator<<(output::ColorStream &stream, const String &string)
{
return (stream << output::String(string.text.c_str()));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
output::ColorStream &operator<<(output::ColorStream &stream, const Variable &variable)
{
assert(!variable.name.empty());
assert(variable.name[0] >= 65 && variable.name[0] <= 90);
if (variable.type == ast::Variable::Type::Reserved || !isReservedVariableName(variable.name.c_str()))
return (stream << output::Variable(variable.name.c_str()));
const auto variableName = std::string(UserVariablePrefix) + variable.name;
return (stream << output::Variable(variableName.c_str()));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Expressions
////////////////////////////////////////////////////////////////////////////////////////////////////
output::ColorStream &operator<<(output::ColorStream &stream, const And &and_)
{
stream << "(";
for (auto i = and_.arguments.cbegin(); i != and_.arguments.cend(); i++)
{
if (i != and_.arguments.cbegin())
stream << " " << output::Keyword("and") << " ";
stream << (*i);
}
return (stream << ")");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
output::ColorStream &operator<<(output::ColorStream &stream, const Biconditional &biconditional)
{
return (stream << "(" << biconditional.left << " <-> " << biconditional.right << ")");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
output::ColorStream &operator<<(output::ColorStream &stream, const Exists &exists)
{
stream << output::Keyword("exists") << " ";
for (auto i = exists.variables.cbegin(); i != exists.variables.cend(); i++)
{
if (i != exists.variables.cbegin())
stream << ", ";
stream << (**i);
}
return (stream << " " << exists.argument);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
output::ColorStream &operator<<(output::ColorStream &stream, const ForAll &forAll)
{
stream << output::Keyword("forall") << " ";
for (auto i = forAll.variables.cbegin(); i != forAll.variables.cend(); i++)
{
if (i != forAll.variables.cbegin())
stream << ", ";
stream << (**i);
}
return (stream << " " << forAll.argument);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
output::ColorStream &operator<<(output::ColorStream &stream, const Implies &implies)
{
return (stream << "(" << implies.antecedent << " -> " << implies.consequent << ")");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
output::ColorStream &operator<<(output::ColorStream &stream, const Not &not_)
{
return (stream << output::Keyword("not ") << not_.argument);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
output::ColorStream &operator<<(output::ColorStream &stream, const Or &or_)
{
stream << "(";
for (auto i = or_.arguments.cbegin(); i != or_.arguments.cend(); i++)
{
if (i != or_.arguments.cbegin())
stream << " " << output::Keyword("or") << " ";
stream << (*i);
}
return (stream << ")");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Variants
////////////////////////////////////////////////////////////////////////////////////////////////////
output::ColorStream &operator<<(output::ColorStream &stream, const Formula &formula)
{
formula.match([&](const auto &x){stream << *x;});
return stream;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
output::ColorStream &operator<<(output::ColorStream &stream, const Term &term)
{
term.match([&](const auto &x){stream << *x;});
return stream;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -1,36 +0,0 @@
#ifndef __ANTHEM__OUTPUT__CLINGO_OUTPUT_H
#define __ANTHEM__OUTPUT__CLINGO_OUTPUT_H
#include <clingo.hh>
#include <anthem/output/ColorStream.h>
namespace anthem
{
namespace output
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// ClingoOutput
//
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &operator<<(ColorStream &stream, const Clingo::Symbol &symbol);
ColorStream &operator<<(ColorStream &stream, const Clingo::AST::Sign &sign);
ColorStream &operator<<(ColorStream &stream, const Clingo::AST::Boolean &boolean);
ColorStream &operator<<(ColorStream &stream, const Clingo::AST::Variable &variable);
ColorStream &operator<<(ColorStream &stream, const Clingo::AST::BinaryOperator &binaryOperator);
ColorStream &operator<<(ColorStream &stream, const Clingo::AST::UnaryOperation &unaryOperation);
ColorStream &operator<<(ColorStream &stream, const Clingo::AST::BinaryOperation &binaryOperation);
ColorStream &operator<<(ColorStream &stream, const Clingo::AST::Interval &interval);
ColorStream &operator<<(ColorStream &stream, const Clingo::AST::Function &function);
ColorStream &operator<<(ColorStream &stream, const Clingo::AST::Pool &pool);
ColorStream &operator<<(ColorStream &stream, const Clingo::AST::Term &term);
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -118,7 +118,7 @@ struct Keyword
inline ColorStream &operator<<(ColorStream &stream, const Keyword &keyword)
{
return (stream
<< Format({Color::Blue, FontWeight::Bold})
<< Format({Color::Blue, FontWeight::Normal})
<< keyword.name
<< ResetFormat());
}