Major refactoring to uniquely link variables to their declarations (breaks simplification and completion).

This commit is contained in:
Patrick Lühne 2017-05-30 03:53:51 +02:00
parent ce159c7bf0
commit 1c925d661b
Signed by: patrick
GPG Key ID: 05F3611E97A70ABF
23 changed files with 1176 additions and 659 deletions

View File

@ -2,6 +2,7 @@
#include <boost/program_options.hpp> #include <boost/program_options.hpp>
#include <anthem/AST.h>
#include <anthem/Context.h> #include <anthem/Context.h>
#include <anthem/Translation.h> #include <anthem/Translation.h>

View File

@ -35,18 +35,18 @@ struct BinaryOperation
Modulo Modulo
}; };
BinaryOperation(const BinaryOperation &other) = delete; explicit BinaryOperation(Operator operator_, Term &&left, Term &&right)
BinaryOperation &operator=(const BinaryOperation &other) = delete;
BinaryOperation(BinaryOperation &&other) noexcept = default;
BinaryOperation &operator=(BinaryOperation &&other) noexcept = default;
BinaryOperation(Operator operator_, Term &&left, Term &&right)
: operator_{operator_}, : operator_{operator_},
left{std::move(left)}, left{std::move(left)},
right{std::move(right)} right{std::move(right)}
{ {
} }
BinaryOperation(const BinaryOperation &other) = delete;
BinaryOperation &operator=(const BinaryOperation &other) = delete;
BinaryOperation(BinaryOperation &&other) noexcept = default;
BinaryOperation &operator=(BinaryOperation &&other) noexcept = default;
Operator operator_; Operator operator_;
Term left; Term left;
Term right; Term right;
@ -56,7 +56,7 @@ struct BinaryOperation
struct Boolean struct Boolean
{ {
Boolean(bool value) explicit Boolean(bool value)
: value{value} : value{value}
{ {
} }
@ -83,7 +83,7 @@ struct Comparison
Equal Equal
}; };
Comparison(Operator operator_, Term &&left, Term &&right) explicit Comparison(Operator operator_, Term &&left, Term &&right)
: operator_{operator_}, : operator_{operator_},
left{std::move(left)}, left{std::move(left)},
right{std::move(right)} right{std::move(right)}
@ -104,7 +104,7 @@ struct Comparison
struct Constant struct Constant
{ {
Constant(std::string &&name) explicit Constant(std::string &&name)
: name{std::move(name)} : name{std::move(name)}
{ {
} }
@ -121,12 +121,12 @@ struct Constant
struct Function struct Function
{ {
Function(std::string &&name) explicit Function(std::string &&name)
: name{std::move(name)} : name{std::move(name)}
{ {
} }
Function(std::string &&name, std::vector<Term> &&arguments) explicit Function(std::string &&name, std::vector<Term> &&arguments)
: name{std::move(name)}, : name{std::move(name)},
arguments{std::move(arguments)} arguments{std::move(arguments)}
{ {
@ -146,7 +146,7 @@ struct Function
// TODO: refactor (limit element type to primitive terms) // TODO: refactor (limit element type to primitive terms)
struct In struct In
{ {
In(Term &&element, Term &&set) explicit In(Term &&element, Term &&set)
: element{std::move(element)}, : element{std::move(element)},
set{std::move(set)} set{std::move(set)}
{ {
@ -167,7 +167,7 @@ struct In
struct Integer struct Integer
{ {
Integer(int value) explicit Integer(int value)
: value{value} : value{value}
{ {
} }
@ -184,7 +184,7 @@ struct Integer
struct Interval struct Interval
{ {
Interval(Term &&from, Term &&to) explicit Interval(Term &&from, Term &&to)
: from{std::move(from)}, : from{std::move(from)},
to{std::move(to)} to{std::move(to)}
{ {
@ -201,14 +201,15 @@ struct Interval
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// TODO: implement declaration/signature
struct Predicate struct Predicate
{ {
Predicate(std::string &&name) explicit Predicate(std::string &&name)
: name{std::move(name)} : name{std::move(name)}
{ {
} }
Predicate(std::string &&name, std::vector<Term> &&arguments) explicit Predicate(std::string &&name, std::vector<Term> &&arguments)
: name{std::move(name)}, : name{std::move(name)},
arguments{std::move(arguments)} arguments{std::move(arguments)}
{ {
@ -238,7 +239,7 @@ struct SpecialInteger
Supremum Supremum
}; };
SpecialInteger(Type type) explicit SpecialInteger(Type type)
: type{type} : type{type}
{ {
} }
@ -255,7 +256,7 @@ struct SpecialInteger
struct String struct String
{ {
String(std::string &&text) explicit String(std::string &&text)
: text{std::move(text)} : text{std::move(text)}
{ {
} }
@ -272,15 +273,8 @@ struct String
struct Variable struct Variable
{ {
enum class Type explicit Variable(VariableDeclaration *declaration)
{ : declaration{declaration}
UserDefined,
Reserved
};
Variable(std::string &&name, Type type)
: name{std::move(name)},
type{type}
{ {
} }
@ -289,6 +283,32 @@ struct Variable
Variable(Variable &&other) = default; Variable(Variable &&other) = default;
Variable &operator=(Variable &&other) = default; Variable &operator=(Variable &&other) = default;
VariableDeclaration *declaration = nullptr;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
struct VariableDeclaration
{
// TODO: remove
enum class Type
{
UserDefined,
Head,
Body
};
explicit VariableDeclaration(std::string &&name, Type type)
: name{std::move(name)},
type{type}
{
}
VariableDeclaration(const VariableDeclaration &other) = delete;
VariableDeclaration &operator=(const VariableDeclaration &other) = delete;
VariableDeclaration(VariableDeclaration &&other) = default;
VariableDeclaration &operator=(VariableDeclaration &&other) = default;
std::string name; std::string name;
Type type; Type type;
}; };
@ -301,7 +321,7 @@ struct And
{ {
And() = default; And() = default;
And(std::vector<Formula> &&arguments) explicit And(std::vector<Formula> &&arguments)
: arguments{std::move(arguments)} : arguments{std::move(arguments)}
{ {
} }
@ -318,7 +338,7 @@ struct And
struct Biconditional struct Biconditional
{ {
Biconditional(Formula &&left, Formula &&right) explicit Biconditional(Formula &&left, Formula &&right)
: left{std::move(left)}, : left{std::move(left)},
right{std::move(right)} right{std::move(right)}
{ {
@ -337,7 +357,8 @@ struct Biconditional
struct Exists struct Exists
{ {
Exists(std::vector<Variable> &&variables, Formula &&argument) // TODO: rename “variables”
explicit Exists(std::vector<std::unique_ptr<VariableDeclaration>> &&variables, Formula &&argument)
: variables{std::move(variables)}, : variables{std::move(variables)},
argument{std::move(argument)} argument{std::move(argument)}
{ {
@ -348,7 +369,7 @@ struct Exists
Exists(Exists &&other) noexcept = default; Exists(Exists &&other) noexcept = default;
Exists &operator=(Exists &&other) noexcept = default; Exists &operator=(Exists &&other) noexcept = default;
std::vector<Variable> variables; std::vector<std::unique_ptr<VariableDeclaration>> variables;
Formula argument; Formula argument;
}; };
@ -356,7 +377,7 @@ struct Exists
struct ForAll struct ForAll
{ {
ForAll(std::vector<Variable> &&variables, Formula &&argument) explicit ForAll(std::vector<std::unique_ptr<VariableDeclaration>> &&variables, Formula &&argument)
: variables{std::move(variables)}, : variables{std::move(variables)},
argument{std::move(argument)} argument{std::move(argument)}
{ {
@ -367,7 +388,7 @@ struct ForAll
ForAll(ForAll &&other) noexcept = default; ForAll(ForAll &&other) noexcept = default;
ForAll &operator=(ForAll &&other) noexcept = default; ForAll &operator=(ForAll &&other) noexcept = default;
std::vector<Variable> variables; std::vector<std::unique_ptr<VariableDeclaration>> variables;
Formula argument; Formula argument;
}; };
@ -375,7 +396,7 @@ struct ForAll
struct Implies struct Implies
{ {
Implies(Formula &&antecedent, Formula &&consequent) explicit Implies(Formula &&antecedent, Formula &&consequent)
: antecedent{std::move(antecedent)}, : antecedent{std::move(antecedent)},
consequent{std::move(consequent)} consequent{std::move(consequent)}
{ {
@ -394,7 +415,7 @@ struct Implies
struct Not struct Not
{ {
Not(Formula &&argument) explicit Not(Formula &&argument)
: argument{std::move(argument)} : argument{std::move(argument)}
{ {
} }
@ -413,7 +434,7 @@ struct Or
{ {
Or() = default; Or() = default;
Or(std::vector<Formula> &&arguments) explicit Or(std::vector<Formula> &&arguments)
: arguments{std::move(arguments)} : arguments{std::move(arguments)}
{ {
} }
@ -427,258 +448,23 @@ struct Or
}; };
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// Deep Copying // High-Level
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
BinaryOperation deepCopy(const BinaryOperation &other); struct ScopedFormula
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<Variable> deepCopy(const std::vector<Variable> &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);
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Variant>
struct VariantDeepCopyVisitor
{ {
template<class T> explicit ScopedFormula(ast::Formula &&formula, std::vector<std::unique_ptr<ast::VariableDeclaration>> &&freeVariables)
Variant visit(const T &x) : formula{std::move(formula)},
freeVariables{std::move(freeVariables)}
{ {
return deepCopy(x);
} }
ast::Formula formula;
std::vector<std::unique_ptr<ast::VariableDeclaration>> freeVariables;
}; };
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
const auto deepCopyVariant =
[](const auto &variant) -> typename std::decay<decltype(variant)>::type
{
using VariantType = typename std::decay<decltype(variant)>::type;
return variant.accept(VariantDeepCopyVisitor<VariantType>());
};
////////////////////////////////////////////////////////////////////////////////////////////////////
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;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
const auto deepCopyVector =
[](const auto &vector) -> typename std::decay<decltype(vector)>::type
{
using Type = typename std::decay<decltype(vector)>::type::value_type;
std::vector<Type> result;
result.reserve(vector.size());
for (const auto &element : vector)
result.emplace_back(deepCopy(element));
return result;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
inline BinaryOperation deepCopy(const BinaryOperation &other)
{
return BinaryOperation(other.operator_, deepCopy(other.left), deepCopy(other.right));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
inline Boolean deepCopy(const Boolean &other)
{
return Boolean(other.value);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
inline Comparison deepCopy(const Comparison &other)
{
return Comparison(other.operator_, deepCopy(other.left), deepCopy(other.right));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
inline Constant deepCopy(const Constant &other)
{
return Constant(std::string(other.name));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
inline Function deepCopy(const Function &other)
{
return Function(std::string(other.name), deepCopy(other.arguments));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
inline Integer deepCopy(const Integer &other)
{
return Integer(other.value);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
inline Interval deepCopy(const Interval &other)
{
return Interval(deepCopy(other.from), deepCopy(other.to));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
inline Predicate deepCopy(const Predicate &other)
{
return Predicate(std::string(other.name), deepCopy(other.arguments));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
inline SpecialInteger deepCopy(const SpecialInteger &other)
{
return SpecialInteger(other.type);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
inline String deepCopy(const String &other)
{
return String(std::string(other.text));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
inline Variable deepCopy(const Variable &other)
{
return Variable(std::string(other.name), other.type);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
inline std::vector<Variable> deepCopy(const std::vector<Variable> &other)
{
return deepCopyVector(other);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
inline And deepCopy(const And &other)
{
return And(deepCopy(other.arguments));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
inline Biconditional deepCopy(const Biconditional &other)
{
return Biconditional(deepCopy(other.left), deepCopy(other.right));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
inline Exists deepCopy(const Exists &other)
{
return Exists(deepCopy(other.variables), deepCopy(other.argument));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
inline ForAll deepCopy(const ForAll &other)
{
return ForAll(deepCopy(other.variables), deepCopy(other.argument));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
inline In deepCopy(const In &other)
{
return In(deepCopy(other.element), deepCopy(other.set));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
inline Implies deepCopy(const Implies &other)
{
return Implies(deepCopy(other.antecedent), deepCopy(other.consequent));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
inline Not deepCopy(const Not &other)
{
return Not(deepCopy(other.argument));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
inline Or deepCopy(const Or &other)
{
return Or(deepCopy(other.arguments));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
inline Formula deepCopy(const Formula &formula)
{
return deepCopyVariant(formula);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
inline std::vector<Formula> deepCopy(const std::vector<Formula> &formulas)
{
return deepCopyVariantVector(formulas);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
inline Term deepCopy(const Term &term)
{
return deepCopyVariant(term);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
inline std::vector<Term> deepCopy(const std::vector<Term> &terms)
{
return deepCopyVariantVector(terms);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
} }
} }

60
include/anthem/ASTCopy.h Normal file
View File

@ -0,0 +1,60 @@
#ifndef __ANTHEM__AST_COPY_H
#define __ANTHEM__AST_COPY_H
#include <anthem/AST.h>
#include <anthem/ASTVisitors.h>
namespace anthem
{
namespace ast
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// ASTCopy
//
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
// Preparing Deep Copying
////////////////////////////////////////////////////////////////////////////////////////////////////
BinaryOperation prepareCopy(const BinaryOperation &other);
Boolean prepareCopy(const Boolean &other);
Comparison prepareCopy(const Comparison &other);
Constant prepareCopy(const Constant &other);
Function prepareCopy(const Function &other);
In prepareCopy(const In &other);
Integer prepareCopy(const Integer &other);
Interval prepareCopy(const Interval &other);
Predicate prepareCopy(const Predicate &other);
SpecialInteger prepareCopy(const SpecialInteger &other);
String prepareCopy(const String &other);
Variable prepareCopy(const Variable &other);
VariableDeclaration prepareCopy(const VariableDeclaration &other);
VariableDeclarationPointers prepareCopy(const VariableDeclarationPointers &other);
And prepareCopy(const And &other);
Biconditional prepareCopy(const Biconditional &other);
Exists prepareCopy(const Exists &other);
ForAll prepareCopy(const ForAll &other);
Implies prepareCopy(const Implies &other);
Not prepareCopy(const Not &other);
Or prepareCopy(const Or &other);
Term prepareCopy(const Term &term);
std::vector<Term> prepareCopy(const std::vector<Term> &terms);
Formula prepareCopy(const Formula &formula);
std::vector<Formula> prepareCopy(const std::vector<Formula> &formulas);
////////////////////////////////////////////////////////////////////////////////////////////////////
// Fixing Dangling Variables
////////////////////////////////////////////////////////////////////////////////////////////////////
void fixDanglingVariables(ScopedFormula &scopedFormula);
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@ -1,7 +1,7 @@
#ifndef __ANTHEM__AST_FORWARD_H #ifndef __ANTHEM__AST_FORWARD_H
#define __ANTHEM__AST_FORWARD_H #define __ANTHEM__AST_FORWARD_H
#include <experimental/optional> #include <memory>
#include <clingo.hh> #include <clingo.hh>
@ -38,6 +38,9 @@ struct Predicate;
struct SpecialInteger; struct SpecialInteger;
struct String; struct String;
struct Variable; struct Variable;
struct VariableDeclaration;
using VariableDeclarationPointer = std::unique_ptr<VariableDeclaration>;
using VariableDeclarationPointers = std::vector<VariableDeclarationPointer>;
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// Variants // Variants
@ -67,6 +70,12 @@ using Term = Clingo::Variant<
String, String,
Variable>; Variable>;
////////////////////////////////////////////////////////////////////////////////////////////////////
// High-Level
////////////////////////////////////////////////////////////////////////////////////////////////////
struct ScopedFormula;
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
} }

View File

@ -1,6 +1,8 @@
#ifndef __ANTHEM__AST_UTILS_H #ifndef __ANTHEM__AST_UTILS_H
#define __ANTHEM__AST_UTILS_H #define __ANTHEM__AST_UTILS_H
#include <experimental/optional>
#include <anthem/AST.h> #include <anthem/AST.h>
namespace anthem namespace anthem
@ -14,16 +16,18 @@ namespace ast
// //
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// TODO: rename to VariableDeclarationStack or ParameterStack
class VariableStack class VariableStack
{ {
public: public:
using Layer = const std::vector<ast::Variable> *; using Layer = ast::VariableDeclarationPointers *;
public: public:
void push(Layer layer); void push(Layer layer);
void pop(); void pop();
bool contains(const ast::Variable &variable) const; std::experimental::optional<ast::VariableDeclaration *> findVariableDeclaration(const char *variableName) const;
bool contains(const ast::VariableDeclaration &variableDeclaration) const;
private: private:
std::vector<Layer> m_layers; std::vector<Layer> m_layers;
@ -31,8 +35,8 @@ class VariableStack
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
std::vector<ast::Variable> collectFreeVariables(const ast::Formula &formula); std::vector<ast::VariableDeclaration *> collectFreeVariables(ast::Formula &formula);
std::vector<ast::Variable> collectFreeVariables(const ast::Formula &formula, ast::VariableStack &variableStack); std::vector<ast::VariableDeclaration *> collectFreeVariables(ast::Formula &formula, ast::VariableStack &variableStack);
bool matches(const ast::Predicate &lhs, const ast::Predicate &rhs); bool matches(const ast::Predicate &lhs, const ast::Predicate &rhs);
void collectPredicates(const ast::Formula &formula, std::vector<const ast::Predicate *> &predicates); void collectPredicates(const ast::Formula &formula, std::vector<const ast::Predicate *> &predicates);

View File

@ -110,6 +110,7 @@ struct RecursiveFormulaVisitor
template<class T> template<class T>
struct RecursiveTermVisitor struct RecursiveTermVisitor
{ {
// TODO: return type is incorrect
template <class... Arguments> template <class... Arguments>
void visit(ast::BinaryOperation &binaryOperation, ast::Term &term, Arguments &&... arguments) void visit(ast::BinaryOperation &binaryOperation, ast::Term &term, Arguments &&... arguments)
{ {

View File

@ -40,11 +40,12 @@ ast::Comparison::Operator translate(Clingo::AST::ComparisonOperator comparisonOp
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
ast::Variable makeAuxiliaryBodyVariable(int i) std::unique_ptr<ast::VariableDeclaration> makeBodyVariableDeclaration(int i)
{ {
auto variableName = std::string(AuxiliaryBodyVariablePrefix) + std::to_string(i); // TODO: drop name
auto variableName = "#" + std::string(BodyVariablePrefix) + std::to_string(i);
return ast::Variable(std::move(variableName), ast::Variable::Type::Reserved); return std::make_unique<ast::VariableDeclaration>(std::move(variableName), ast::VariableDeclaration::Type::Body);
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
@ -52,7 +53,7 @@ ast::Variable makeAuxiliaryBodyVariable(int i)
struct BodyTermTranslateVisitor struct BodyTermTranslateVisitor
{ {
// TODO: refactor // TODO: refactor
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Function &function, const Clingo::AST::Literal &literal, const Clingo::AST::Term &, Context &context) std::experimental::optional<ast::Formula> visit(const Clingo::AST::Function &function, const Clingo::AST::Literal &literal, const Clingo::AST::Term &, Context &context, RuleContext &ruleContext, ast::VariableStack &variableStack)
{ {
if (literal.sign == Clingo::AST::Sign::DoubleNegation) if (literal.sign == Clingo::AST::Sign::DoubleNegation)
throwErrorAtLocation(literal.location, "double-negated literals currently unsupported", context); throwErrorAtLocation(literal.location, "double-negated literals currently unsupported", context);
@ -67,39 +68,42 @@ struct BodyTermTranslateVisitor
return ast::Formula::make<ast::Not>(std::move(predicate)); return ast::Formula::make<ast::Not>(std::move(predicate));
} }
std::vector<ast::Variable> variables; // Create new body variable declarations
variables.reserve(function.arguments.size()); std::vector<std::unique_ptr<ast::VariableDeclaration>> parameters;
parameters.reserve(function.arguments.size());
variableStack.push(&parameters);
for (size_t i = 0; i < function.arguments.size(); i++) for (size_t i = 0; i < function.arguments.size(); i++)
variables.emplace_back(makeAuxiliaryBodyVariable(context.auxiliaryBodyVariableID + i)); parameters.emplace_back(makeBodyVariableDeclaration(i + 1));
ast::And conjunction; ast::And conjunction;
for (size_t i = 0; i < function.arguments.size(); i++) for (size_t i = 0; i < function.arguments.size(); i++)
{ {
const auto &argument = function.arguments[i]; auto &argument = function.arguments[i];
conjunction.arguments.emplace_back(ast::Formula::make<ast::In>(makeAuxiliaryBodyVariable(context.auxiliaryBodyVariableID + i), translate(argument, context))); conjunction.arguments.emplace_back(ast::Formula::make<ast::In>(ast::Variable(parameters[i].get()), translate(argument, context, ruleContext, variableStack)));
} }
ast::Predicate predicate(std::string(function.name)); ast::Predicate predicate(std::string(function.name));
predicate.arguments.reserve(function.arguments.size()); predicate.arguments.reserve(function.arguments.size());
for (size_t i = 0; i < function.arguments.size(); i++) for (size_t i = 0; i < function.arguments.size(); i++)
predicate.arguments.emplace_back(makeAuxiliaryBodyVariable(context.auxiliaryBodyVariableID + i)); predicate.arguments.emplace_back(ast::Variable(parameters[i].get()));
if (literal.sign == Clingo::AST::Sign::None) if (literal.sign == Clingo::AST::Sign::None)
conjunction.arguments.emplace_back(std::move(predicate)); conjunction.arguments.emplace_back(std::move(predicate));
else if (literal.sign == Clingo::AST::Sign::Negation) else if (literal.sign == Clingo::AST::Sign::Negation)
conjunction.arguments.emplace_back(ast::Formula::make<ast::Not>(std::move(predicate))); conjunction.arguments.emplace_back(ast::Formula::make<ast::Not>(std::move(predicate)));
context.auxiliaryBodyVariableID += function.arguments.size(); return ast::Formula::make<ast::Exists>(std::move(parameters), std::move(conjunction));
return ast::Formula::make<ast::Exists>(std::move(variables), std::move(conjunction));
} }
template<class T> template<class T>
std::experimental::optional<ast::Formula> visit(const T &, const Clingo::AST::Literal &, const Clingo::AST::Term &term, Context &context) std::experimental::optional<ast::Formula> visit(const T &, const Clingo::AST::Literal &, const Clingo::AST::Term &term, Context &context, RuleContext &, ast::VariableStack &)
{ {
assert(!term.data.is<Clingo::AST::Function>());
throwErrorAtLocation(term.location, "term currently unsupported in this context, expected function", context); throwErrorAtLocation(term.location, "term currently unsupported in this context, expected function", context);
return std::experimental::nullopt; return std::experimental::nullopt;
} }
@ -109,18 +113,18 @@ struct BodyTermTranslateVisitor
struct BodyLiteralTranslateVisitor struct BodyLiteralTranslateVisitor
{ {
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Boolean &boolean, const Clingo::AST::Literal &, Context &) std::experimental::optional<ast::Formula> visit(const Clingo::AST::Boolean &boolean, const Clingo::AST::Literal &, Context &, RuleContext &, ast::VariableStack &)
{ {
return ast::Formula::make<ast::Boolean>(boolean.value); return ast::Formula::make<ast::Boolean>(boolean.value);
} }
std::experimental::optional<ast::Formula> 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, RuleContext &ruleContext, ast::VariableStack &variableStack)
{ {
return term.data.accept(BodyTermTranslateVisitor(), literal, term, context); return term.data.accept(BodyTermTranslateVisitor(), literal, term, context, ruleContext, variableStack);
} }
// TODO: refactor // TODO: refactor
std::experimental::optional<ast::Formula> 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, RuleContext &ruleContext, ast::VariableStack &variableStack)
{ {
// Comparisons should never have a sign, because these are converted to positive comparisons by clingo // Comparisons should never have a sign, because these are converted to positive comparisons by clingo
if (literal.sign != Clingo::AST::Sign::None) if (literal.sign != Clingo::AST::Sign::None)
@ -128,24 +132,22 @@ struct BodyLiteralTranslateVisitor
const auto operator_ = translate(comparison.comparison); const auto operator_ = translate(comparison.comparison);
std::vector<ast::Variable> variables; std::vector<std::unique_ptr<ast::VariableDeclaration>> parameters;
variables.reserve(2); parameters.reserve(2);
variables.emplace_back(makeAuxiliaryBodyVariable(context.auxiliaryBodyVariableID)); parameters.emplace_back(makeBodyVariableDeclaration(1));
variables.emplace_back(makeAuxiliaryBodyVariable(context.auxiliaryBodyVariableID + 1)); parameters.emplace_back(makeBodyVariableDeclaration(2));
ast::And conjunction; ast::And conjunction;
conjunction.arguments.reserve(3); conjunction.arguments.reserve(3);
conjunction.arguments.emplace_back(ast::Formula::make<ast::In>(makeAuxiliaryBodyVariable(context.auxiliaryBodyVariableID), translate(comparison.left, context))); conjunction.arguments.emplace_back(ast::Formula::make<ast::In>(ast::Variable(parameters[0].get()), translate(comparison.left, context, ruleContext, variableStack)));
conjunction.arguments.emplace_back(ast::Formula::make<ast::In>(makeAuxiliaryBodyVariable(context.auxiliaryBodyVariableID + 1), translate(comparison.right, context))); conjunction.arguments.emplace_back(ast::Formula::make<ast::In>(ast::Variable(parameters[1].get()), translate(comparison.right, context, ruleContext, variableStack)));
conjunction.arguments.emplace_back(ast::Formula::make<ast::Comparison>(operator_, makeAuxiliaryBodyVariable(context.auxiliaryBodyVariableID), makeAuxiliaryBodyVariable(context.auxiliaryBodyVariableID + 1))); conjunction.arguments.emplace_back(ast::Formula::make<ast::Comparison>(operator_, ast::Variable(parameters[0].get()), ast::Variable(parameters[1].get())));
context.auxiliaryBodyVariableID += 2; return ast::Formula::make<ast::Exists>(std::move(parameters), std::move(conjunction));
return ast::Formula::make<ast::Exists>(std::move(variables), std::move(conjunction));
} }
template<class T> template<class T>
std::experimental::optional<ast::Formula> visit(const T &, const Clingo::AST::Literal &literal, Context &context) std::experimental::optional<ast::Formula> visit(const T &, const Clingo::AST::Literal &literal, Context &context, RuleContext &, ast::VariableStack &)
{ {
throwErrorAtLocation(literal.location, "literal currently unsupported in this context, expected function or term", context); throwErrorAtLocation(literal.location, "literal currently unsupported in this context, expected function or term", context);
return std::experimental::nullopt; return std::experimental::nullopt;
@ -156,16 +158,16 @@ struct BodyLiteralTranslateVisitor
struct BodyBodyLiteralTranslateVisitor struct BodyBodyLiteralTranslateVisitor
{ {
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Literal &literal, const Clingo::AST::BodyLiteral &bodyLiteral, Context &context) std::experimental::optional<ast::Formula> visit(const Clingo::AST::Literal &literal, const Clingo::AST::BodyLiteral &bodyLiteral, Context &context, RuleContext &ruleContext, ast::VariableStack &variableStack)
{ {
if (bodyLiteral.sign != Clingo::AST::Sign::None) if (bodyLiteral.sign != Clingo::AST::Sign::None)
throwErrorAtLocation(bodyLiteral.location, "only positive body literals supported currently", context); throwErrorAtLocation(bodyLiteral.location, "only positive body literals supported currently", context);
return literal.data.accept(BodyLiteralTranslateVisitor(), literal, context); return literal.data.accept(BodyLiteralTranslateVisitor(), literal, context, ruleContext, variableStack);
} }
template<class T> template<class T>
std::experimental::optional<ast::Formula> visit(const T &, const Clingo::AST::BodyLiteral &bodyLiteral, Context &context) std::experimental::optional<ast::Formula> visit(const T &, const Clingo::AST::BodyLiteral &bodyLiteral, Context &context, RuleContext &, ast::VariableStack &)
{ {
throwErrorAtLocation(bodyLiteral.location, "body literal currently unsupported in this context, expected literal", context); throwErrorAtLocation(bodyLiteral.location, "body literal currently unsupported in this context, expected literal", context);
return std::experimental::nullopt; return std::experimental::nullopt;

View File

@ -12,7 +12,7 @@ namespace anthem
// //
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
void complete(std::vector<ast::Formula> &formulas); void complete(std::vector<ast::ScopedFormula> &scopedFormulas);
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -1,8 +1,6 @@
#ifndef __ANTHEM__CONTEXT_H #ifndef __ANTHEM__CONTEXT_H
#define __ANTHEM__CONTEXT_H #define __ANTHEM__CONTEXT_H
#include <clingo.hh>
#include <anthem/output/Logger.h> #include <anthem/output/Logger.h>
namespace anthem namespace anthem
@ -16,25 +14,19 @@ namespace anthem
struct Context struct Context
{ {
void reset() Context() = default;
explicit Context(output::Logger &&logger)
: logger{std::move(logger)}
{ {
headTerms.clear();
isChoiceRule = false;
numberOfHeadLiterals = 0;
auxiliaryBodyVariableID = 1;
anonymousVariableID = 1;
} }
output::Logger logger; output::Logger logger;
std::vector<const Clingo::AST::Term *> headTerms;
bool isChoiceRule = false;
size_t numberOfHeadLiterals = 0;
size_t auxiliaryBodyVariableID = 1;
size_t anonymousVariableID = 1;
bool simplify = false; bool simplify = false;
bool complete = false; bool complete = false;
size_t anonymousVariableID = 1;
}; };
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -2,8 +2,10 @@
#define __ANTHEM__HEAD_H #define __ANTHEM__HEAD_H
#include <algorithm> #include <algorithm>
#include <experimental/optional>
#include <anthem/AST.h> #include <anthem/AST.h>
#include <anthem/RuleContext.h>
#include <anthem/Utils.h> #include <anthem/Utils.h>
#include <anthem/output/Formatting.h> #include <anthem/output/Formatting.h>
@ -16,21 +18,25 @@ namespace anthem
// //
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
// Collect Head Terms
////////////////////////////////////////////////////////////////////////////////////////////////////
struct TermCollectFunctionTermsVisitor struct TermCollectFunctionTermsVisitor
{ {
void visit(const Clingo::AST::Function &function, const Clingo::AST::Term &term, Context &context) void visit(const Clingo::AST::Function &function, const Clingo::AST::Term &term, Context &context, RuleContext &ruleContext)
{ {
if (function.external) if (function.external)
throwErrorAtLocation(term.location, "external functions currently unsupported", context); throwErrorAtLocation(term.location, "external functions currently unsupported", context);
context.headTerms.reserve(context.headTerms.size() + function.arguments.size()); ruleContext.headTerms.reserve(ruleContext.headTerms.size() + function.arguments.size());
for (const auto &argument : function.arguments) for (const auto &argument : function.arguments)
context.headTerms.emplace_back(&argument); ruleContext.headTerms.emplace_back(&argument);
} }
template<class T> template<class T>
void visit(const T &, const Clingo::AST::Term &term, Context &context) void visit(const T &, const Clingo::AST::Term &term, Context &context, RuleContext &)
{ {
throwErrorAtLocation(term.location, "term currently unsupported in this context, function expected", context); throwErrorAtLocation(term.location, "term currently unsupported in this context, function expected", context);
} }
@ -40,17 +46,17 @@ struct TermCollectFunctionTermsVisitor
struct LiteralCollectFunctionTermsVisitor struct LiteralCollectFunctionTermsVisitor
{ {
void visit(const Clingo::AST::Boolean &, const Clingo::AST::Literal &, Context &) void visit(const Clingo::AST::Boolean &, const Clingo::AST::Literal &, Context &, RuleContext &)
{ {
} }
void visit(const Clingo::AST::Term &term, const Clingo::AST::Literal &, Context &context) void visit(const Clingo::AST::Term &term, const Clingo::AST::Literal &, Context &context, RuleContext &ruleContext)
{ {
term.data.accept(TermCollectFunctionTermsVisitor(), term, context); term.data.accept(TermCollectFunctionTermsVisitor(), term, context, ruleContext);
} }
template<class T> template<class T>
void visit(const T &, const Clingo::AST::Literal &literal, Context &context) void visit(const T &, const Clingo::AST::Literal &literal, Context &context, RuleContext &)
{ {
throwErrorAtLocation(literal.location, "only disjunctions of literals allowed as head literals", context); throwErrorAtLocation(literal.location, "only disjunctions of literals allowed as head literals", context);
} }
@ -61,30 +67,30 @@ struct LiteralCollectFunctionTermsVisitor
// TODO: rename, because not only terms are collected anymore // TODO: rename, because not only terms are collected anymore
struct HeadLiteralCollectFunctionTermsVisitor struct HeadLiteralCollectFunctionTermsVisitor
{ {
void visit(const Clingo::AST::Literal &literal, const Clingo::AST::HeadLiteral &, Context &context) void visit(const Clingo::AST::Literal &literal, const Clingo::AST::HeadLiteral &, Context &context, RuleContext &ruleContext)
{ {
context.numberOfHeadLiterals = 1; ruleContext.numberOfHeadLiterals = 1;
literal.data.accept(LiteralCollectFunctionTermsVisitor(), literal, context); literal.data.accept(LiteralCollectFunctionTermsVisitor(), literal, context, ruleContext);
} }
void visit(const Clingo::AST::Disjunction &disjunction, const Clingo::AST::HeadLiteral &headLiteral, Context &context) void visit(const Clingo::AST::Disjunction &disjunction, const Clingo::AST::HeadLiteral &headLiteral, Context &context, RuleContext &ruleContext)
{ {
context.numberOfHeadLiterals = disjunction.elements.size(); ruleContext.numberOfHeadLiterals = disjunction.elements.size();
for (const auto &conditionalLiteral : disjunction.elements) for (const auto &conditionalLiteral : disjunction.elements)
{ {
if (!conditionalLiteral.condition.empty()) if (!conditionalLiteral.condition.empty())
throwErrorAtLocation(headLiteral.location, "conditional head literals currently unsupported", context); throwErrorAtLocation(headLiteral.location, "conditional head literals currently unsupported", context);
conditionalLiteral.literal.data.accept(LiteralCollectFunctionTermsVisitor(), conditionalLiteral.literal, context); conditionalLiteral.literal.data.accept(LiteralCollectFunctionTermsVisitor(), conditionalLiteral.literal, context, ruleContext);
} }
} }
void visit(const Clingo::AST::Aggregate &aggregate, const Clingo::AST::HeadLiteral &headLiteral, Context &context) void visit(const Clingo::AST::Aggregate &aggregate, const Clingo::AST::HeadLiteral &headLiteral, Context &context, RuleContext &ruleContext)
{ {
context.isChoiceRule = true; ruleContext.isChoiceRule = true;
context.numberOfHeadLiterals = aggregate.elements.size(); ruleContext.numberOfHeadLiterals = aggregate.elements.size();
if (aggregate.left_guard || aggregate.right_guard) if (aggregate.left_guard || aggregate.right_guard)
throwErrorAtLocation(headLiteral.location, "aggregates with left or right guards currently unsupported", context); throwErrorAtLocation(headLiteral.location, "aggregates with left or right guards currently unsupported", context);
@ -94,23 +100,25 @@ struct HeadLiteralCollectFunctionTermsVisitor
if (!conditionalLiteral.condition.empty()) if (!conditionalLiteral.condition.empty())
throwErrorAtLocation(headLiteral.location, "conditional literals in aggregates currently unsupported", context); throwErrorAtLocation(headLiteral.location, "conditional literals in aggregates currently unsupported", context);
conditionalLiteral.literal.data.accept(LiteralCollectFunctionTermsVisitor(), conditionalLiteral.literal, context); conditionalLiteral.literal.data.accept(LiteralCollectFunctionTermsVisitor(), conditionalLiteral.literal, context, ruleContext);
} }
} }
template<class T> template<class T>
void visit(const T &, const Clingo::AST::HeadLiteral &headLiteral, Context &context) void visit(const T &, const Clingo::AST::HeadLiteral &headLiteral, Context &context, RuleContext &)
{ {
throwErrorAtLocation(headLiteral.location, "head literal currently unsupported in this context, expected literal, disjunction, or aggregate", context); throwErrorAtLocation(headLiteral.location, "head literal currently unsupported in this context, expected literal, disjunction, or aggregate", context);
} }
}; };
////////////////////////////////////////////////////////////////////////////////////////////////////
// Translate Head
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
struct FunctionTermTranslateVisitor struct FunctionTermTranslateVisitor
{ {
// TODO: check correctness // TODO: check correctness
std::experimental::optional<ast::Formula> 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, RuleContext &ruleContext, size_t &headVariableIndex)
{ {
if (function.external) if (function.external)
throwErrorAtLocation(term.location, "external functions currently unsupported", context); throwErrorAtLocation(term.location, "external functions currently unsupported", context);
@ -118,22 +126,14 @@ struct FunctionTermTranslateVisitor
std::vector<ast::Term> arguments; std::vector<ast::Term> arguments;
arguments.reserve(function.arguments.size()); arguments.reserve(function.arguments.size());
for (auto i = function.arguments.cbegin(); i != function.arguments.cend(); i++) for (size_t i = 0; i < function.arguments.size(); i++)
{ arguments.emplace_back(ast::Variable(ruleContext.freeVariables[headVariableIndex++].get()));
const auto &argument = *i;
const auto matchingTerm = std::find(context.headTerms.cbegin(), context.headTerms.cend(), &argument);
assert(matchingTerm != context.headTerms.cend());
auto variableName = std::string(AuxiliaryHeadVariablePrefix) + std::to_string(matchingTerm - context.headTerms.cbegin() + 1);
arguments.emplace_back(ast::Variable(std::move(variableName), ast::Variable::Type::Reserved));
}
return ast::Formula::make<ast::Predicate>(function.name, std::move(arguments)); return ast::Formula::make<ast::Predicate>(function.name, std::move(arguments));
} }
template<class T> template<class T>
std::experimental::optional<ast::Formula> visit(const T &, const Clingo::AST::Term &term, Context &context) std::experimental::optional<ast::Formula> visit(const T &, const Clingo::AST::Term &term, Context &context, RuleContext &, size_t &)
{ {
throwErrorAtLocation(term.location, "term currently unsupported in this context, function expected", context); throwErrorAtLocation(term.location, "term currently unsupported in this context, function expected", context);
return std::experimental::nullopt; return std::experimental::nullopt;
@ -144,18 +144,18 @@ struct FunctionTermTranslateVisitor
struct LiteralTranslateVisitor struct LiteralTranslateVisitor
{ {
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Boolean &boolean, const Clingo::AST::Literal &, Context &) std::experimental::optional<ast::Formula> visit(const Clingo::AST::Boolean &boolean, const Clingo::AST::Literal &, Context &, RuleContext &, size_t &)
{ {
return ast::Formula::make<ast::Boolean>(boolean.value); return ast::Formula::make<ast::Boolean>(boolean.value);
} }
std::experimental::optional<ast::Formula> 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, RuleContext &ruleContext, size_t &headVariableIndex)
{ {
return term.data.accept(FunctionTermTranslateVisitor(), term, context); return term.data.accept(FunctionTermTranslateVisitor(), term, context, ruleContext, headVariableIndex);
} }
template<class T> template<class T>
std::experimental::optional<ast::Formula> visit(const T &, const Clingo::AST::Literal &literal, Context &context) std::experimental::optional<ast::Formula> visit(const T &, const Clingo::AST::Literal &literal, Context &context, RuleContext &, size_t &)
{ {
throwErrorAtLocation(literal.location, "only disjunctions of literals allowed as head literals", context); throwErrorAtLocation(literal.location, "only disjunctions of literals allowed as head literals", context);
return std::experimental::nullopt; return std::experimental::nullopt;
@ -166,12 +166,12 @@ struct LiteralTranslateVisitor
struct HeadLiteralTranslateToConsequentVisitor struct HeadLiteralTranslateToConsequentVisitor
{ {
std::experimental::optional<ast::Formula> 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, RuleContext &ruleContext, size_t &headVariableIndex)
{ {
if (literal.sign == Clingo::AST::Sign::DoubleNegation) if (literal.sign == Clingo::AST::Sign::DoubleNegation)
throwErrorAtLocation(literal.location, "double-negated head literals currently unsupported", context); throwErrorAtLocation(literal.location, "double-negated head literals currently unsupported", context);
auto translatedLiteral = literal.data.accept(LiteralTranslateVisitor(), literal, context); auto translatedLiteral = literal.data.accept(LiteralTranslateVisitor(), literal, context, ruleContext, headVariableIndex);
if (literal.sign == Clingo::AST::Sign::None) if (literal.sign == Clingo::AST::Sign::None)
return translatedLiteral; return translatedLiteral;
@ -182,7 +182,7 @@ struct HeadLiteralTranslateToConsequentVisitor
return ast::Formula::make<ast::Not>(std::move(translatedLiteral.value())); return ast::Formula::make<ast::Not>(std::move(translatedLiteral.value()));
} }
std::experimental::optional<ast::Formula> 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, RuleContext &ruleContext, size_t &headVariableIndex)
{ {
std::vector<ast::Formula> arguments; std::vector<ast::Formula> arguments;
arguments.reserve(disjunction.elements.size()); arguments.reserve(disjunction.elements.size());
@ -192,7 +192,7 @@ struct HeadLiteralTranslateToConsequentVisitor
if (!conditionalLiteral.condition.empty()) if (!conditionalLiteral.condition.empty())
throwErrorAtLocation(headLiteral.location, "conditional head literals currently unsupported", context); throwErrorAtLocation(headLiteral.location, "conditional head literals currently unsupported", context);
auto argument = visit(conditionalLiteral.literal, headLiteral, context); auto argument = visit(conditionalLiteral.literal, headLiteral, context, ruleContext, headVariableIndex);
if (!argument) if (!argument)
throwErrorAtLocation(headLiteral.location, "could not parse argument", context); throwErrorAtLocation(headLiteral.location, "could not parse argument", context);
@ -203,7 +203,7 @@ struct HeadLiteralTranslateToConsequentVisitor
return ast::Formula::make<ast::Or>(std::move(arguments)); return ast::Formula::make<ast::Or>(std::move(arguments));
} }
std::experimental::optional<ast::Formula> 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, RuleContext &ruleContext, size_t &headVariableIndex)
{ {
if (aggregate.left_guard || aggregate.right_guard) if (aggregate.left_guard || aggregate.right_guard)
throwErrorAtLocation(headLiteral.location, "aggregates with left or right guards currently unsupported", context); throwErrorAtLocation(headLiteral.location, "aggregates with left or right guards currently unsupported", context);
@ -214,7 +214,7 @@ struct HeadLiteralTranslateToConsequentVisitor
if (!conditionalLiteral.condition.empty()) if (!conditionalLiteral.condition.empty())
throwErrorAtLocation(headLiteral.location, "conditional head literals currently unsupported", context); throwErrorAtLocation(headLiteral.location, "conditional head literals currently unsupported", context);
return this->visit(conditionalLiteral.literal, headLiteral, context); return this->visit(conditionalLiteral.literal, headLiteral, context, ruleContext, headVariableIndex);
}; };
if (aggregate.elements.size() == 1) if (aggregate.elements.size() == 1)
@ -237,7 +237,7 @@ struct HeadLiteralTranslateToConsequentVisitor
} }
template<class T> template<class T>
std::experimental::optional<ast::Formula> visit(const T &, const Clingo::AST::HeadLiteral &headLiteral, Context &context) std::experimental::optional<ast::Formula> visit(const T &, const Clingo::AST::HeadLiteral &headLiteral, Context &context, RuleContext &, size_t &)
{ {
throwErrorAtLocation(headLiteral.location, "head literal currently unsupported in this context, expected literal, disjunction, or aggregate", context); throwErrorAtLocation(headLiteral.location, "head literal currently unsupported in this context, expected literal, disjunction, or aggregate", context);
return std::experimental::nullopt; return std::experimental::nullopt;

View File

@ -0,0 +1,34 @@
#ifndef __ANTHEM__RULE_CONTEXT_H
#define __ANTHEM__RULE_CONTEXT_H
#include <clingo.hh>
#include <anthem/ASTForward.h>
#include <anthem/output/Logger.h>
namespace anthem
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// RuleContext
//
////////////////////////////////////////////////////////////////////////////////////////////////////
struct RuleContext
{
std::vector<const Clingo::AST::Term *> headTerms;
ast::VariableDeclarationPointers freeVariables;
// Index of the first auxiliary head variable into the vector freeVariables
size_t headVariablesStartIndex = 0;
bool isChoiceRule = false;
size_t numberOfHeadLiterals = 0;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
}
#endif

View File

@ -2,8 +2,10 @@
#define __ANTHEM__STATEMENT_VISITOR_H #define __ANTHEM__STATEMENT_VISITOR_H
#include <anthem/AST.h> #include <anthem/AST.h>
#include <anthem/ASTCopy.h>
#include <anthem/Body.h> #include <anthem/Body.h>
#include <anthem/Head.h> #include <anthem/Head.h>
#include <anthem/RuleContext.h>
#include <anthem/Term.h> #include <anthem/Term.h>
#include <anthem/Utils.h> #include <anthem/Utils.h>
@ -35,7 +37,7 @@ inline void reduce(ast::Implies &implies)
struct StatementVisitor struct StatementVisitor
{ {
void visit(const Clingo::AST::Program &program, const Clingo::AST::Statement &statement, std::vector<ast::Formula> &, Context &context) void visit(const Clingo::AST::Program &program, const Clingo::AST::Statement &statement, std::vector<ast::ScopedFormula> &, Context &context)
{ {
// TODO: refactor // TODO: refactor
context.logger.log(output::Priority::Debug, (std::string("[program] ") + program.name).c_str()); context.logger.log(output::Priority::Debug, (std::string("[program] ") + program.name).c_str());
@ -44,17 +46,35 @@ struct StatementVisitor
throwErrorAtLocation(statement.location, "program parameters currently unsupported", context); throwErrorAtLocation(statement.location, "program parameters currently unsupported", context);
} }
void visit(const Clingo::AST::Rule &rule, const Clingo::AST::Statement &, std::vector<ast::Formula> &formulas, Context &context) void visit(const Clingo::AST::Rule &rule, const Clingo::AST::Statement &, std::vector<ast::ScopedFormula> &scopedFormulas, Context &context)
{ {
context.reset(); RuleContext ruleContext;
ast::VariableStack variableStack;
variableStack.push(&ruleContext.freeVariables);
// Concatenate all head terms // Collect all head terms
rule.head.data.accept(HeadLiteralCollectFunctionTermsVisitor(), rule.head, context); rule.head.data.accept(HeadLiteralCollectFunctionTermsVisitor(), rule.head, context, ruleContext);
// Create new variable declarations for the head terms
ruleContext.headVariablesStartIndex = ruleContext.freeVariables.size();
ruleContext.freeVariables.reserve(ruleContext.headTerms.size());
for (size_t i = 0; i < ruleContext.headTerms.size(); i++)
{
// TODO: drop name
auto variableName = "#" + std::string(HeadVariablePrefix) + std::to_string(ruleContext.freeVariables.size() + 1);
auto variableDeclaration = std::make_unique<ast::VariableDeclaration>(std::move(variableName), ast::VariableDeclaration::Type::Head);
ruleContext.freeVariables.emplace_back(std::move(variableDeclaration));
}
ast::And antecedent; ast::And antecedent;
// Compute consequent // Compute consequent
auto consequent = rule.head.data.accept(HeadLiteralTranslateToConsequentVisitor(), rule.head, context); auto headVariableIndex = ruleContext.headVariablesStartIndex;
auto consequent = rule.head.data.accept(HeadLiteralTranslateToConsequentVisitor(), rule.head, context, ruleContext, headVariableIndex);
assert(ruleContext.headTerms.size() == headVariableIndex - ruleContext.headVariablesStartIndex);
if (!consequent) if (!consequent)
{ {
@ -64,13 +84,13 @@ struct StatementVisitor
} }
// Generate auxiliary variables replacing the head atoms arguments // Generate auxiliary variables replacing the head atoms arguments
for (auto i = context.headTerms.cbegin(); i != context.headTerms.cend(); i++) for (auto i = ruleContext.headTerms.cbegin(); i != ruleContext.headTerms.cend(); i++)
{ {
const auto &headTerm = **i; const auto &headTerm = **i;
auto variableName = std::string(AuxiliaryHeadVariablePrefix) + std::to_string(i - context.headTerms.cbegin() + 1); const auto auxiliaryHeadVariableID = ruleContext.headVariablesStartIndex + i - ruleContext.headTerms.cbegin();
auto element = ast::Variable(std::move(variableName), ast::Variable::Type::Reserved); auto element = ast::Variable(ruleContext.freeVariables[auxiliaryHeadVariableID].get());
auto set = translate(headTerm, context); auto set = translate(headTerm, context, ruleContext, variableStack);
auto in = ast::In(std::move(element), std::move(set)); auto in = ast::In(std::move(element), std::move(set));
antecedent.arguments.emplace_back(std::move(in)); antecedent.arguments.emplace_back(std::move(in));
@ -81,7 +101,7 @@ struct StatementVisitor
{ {
const auto &bodyLiteral = *i; const auto &bodyLiteral = *i;
auto argument = bodyLiteral.data.accept(BodyBodyLiteralTranslateVisitor(), bodyLiteral, context); auto argument = bodyLiteral.data.accept(BodyBodyLiteralTranslateVisitor(), bodyLiteral, context, ruleContext, variableStack);
if (!argument) if (!argument)
throwErrorAtLocation(bodyLiteral.location, "could not translate body literal", context); throwErrorAtLocation(bodyLiteral.location, "could not translate body literal", context);
@ -89,26 +109,38 @@ struct StatementVisitor
antecedent.arguments.emplace_back(std::move(argument.value())); antecedent.arguments.emplace_back(std::move(argument.value()));
} }
if (!context.isChoiceRule) if (!ruleContext.isChoiceRule)
{ {
formulas.emplace_back(ast::Formula::make<ast::Implies>(std::move(antecedent), std::move(consequent.value()))); auto formula = ast::Formula::make<ast::Implies>(std::move(antecedent), std::move(consequent.value()));
reduce(formulas.back().get<ast::Implies>()); ast::ScopedFormula scopedFormula(std::move(formula), std::move(ruleContext.freeVariables));
scopedFormulas.emplace_back(std::move(scopedFormula));
reduce(scopedFormulas.back().formula.get<ast::Implies>());
} }
else else
{ {
const auto createFormula = const auto createFormula =
[&](ast::Formula &argument, bool isLastOne) [&](ast::Formula &argument, bool isLastOne)
{ {
auto consequent = std::move(argument); auto &consequent = argument;
if (!isLastOne) if (!isLastOne)
formulas.emplace_back(ast::Formula::make<ast::Implies>(ast::deepCopy(antecedent), std::move(consequent))); {
auto formula = ast::Formula::make<ast::Implies>(ast::prepareCopy(antecedent), std::move(consequent));
ast::ScopedFormula scopedFormula(std::move(formula), {});
ast::fixDanglingVariables(scopedFormula);
scopedFormulas.emplace_back(std::move(scopedFormula));
}
else else
formulas.emplace_back(ast::Formula::make<ast::Implies>(std::move(antecedent), std::move(consequent))); {
auto formula = ast::Formula::make<ast::Implies>(std::move(antecedent), std::move(consequent));
ast::ScopedFormula scopedFormula(std::move(formula), std::move(ruleContext.freeVariables));
scopedFormulas.emplace_back(std::move(scopedFormula));
}
auto &implies = formulas.back().get<ast::Implies>(); auto &implies = scopedFormulas.back().formula.get<ast::Implies>();
auto &antecedent = implies.antecedent.get<ast::And>(); auto &antecedent = implies.antecedent.get<ast::And>();
antecedent.arguments.emplace_back(ast::deepCopy(implies.consequent)); antecedent.arguments.emplace_back(ast::prepareCopy(implies.consequent));
ast::fixDanglingVariables(scopedFormulas.back());
reduce(implies); reduce(implies);
}; };
@ -127,7 +159,7 @@ struct StatementVisitor
} }
template<class T> template<class T>
void visit(const T &, const Clingo::AST::Statement &statement, std::vector<ast::Formula> &, Context &context) void visit(const T &, const Clingo::AST::Statement &statement, std::vector<ast::ScopedFormula> &, Context &context)
{ {
throwErrorAtLocation(statement.location, "statement currently unsupported, expected rule", context); throwErrorAtLocation(statement.location, "statement currently unsupported, expected rule", context);
} }

View File

@ -4,6 +4,8 @@
#include <algorithm> #include <algorithm>
#include <anthem/AST.h> #include <anthem/AST.h>
#include <anthem/ASTUtils.h>
#include <anthem/RuleContext.h>
#include <anthem/Utils.h> #include <anthem/Utils.h>
#include <anthem/output/Formatting.h> #include <anthem/output/Formatting.h>
@ -39,13 +41,13 @@ ast::BinaryOperation::Operator translate(Clingo::AST::BinaryOperator binaryOpera
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
ast::Term translate(const Clingo::AST::Term &term, Context &context); ast::Term translate(const Clingo::AST::Term &term, Context &context, RuleContext &ruleContext, const ast::VariableStack &variableStack);
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
struct TermTranslateVisitor struct TermTranslateVisitor
{ {
std::experimental::optional<ast::Term> visit(const Clingo::Symbol &symbol, const Clingo::AST::Term &term, Context &context) std::experimental::optional<ast::Term> visit(const Clingo::Symbol &symbol, const Clingo::AST::Term &term, Context &context, RuleContext &ruleContext, const ast::VariableStack &variableStack)
{ {
switch (symbol.type()) switch (symbol.type())
{ {
@ -66,7 +68,7 @@ struct TermTranslateVisitor
for (const auto &argument : symbol.arguments()) for (const auto &argument : symbol.arguments())
{ {
auto translatedArgument = visit(argument, term, context); auto translatedArgument = visit(argument, term, context, ruleContext, variableStack);
if (!translatedArgument) if (!translatedArgument)
throwErrorAtLocation(term.location, "could not translate argument", context); throwErrorAtLocation(term.location, "could not translate argument", context);
@ -81,43 +83,46 @@ struct TermTranslateVisitor
return std::experimental::nullopt; return std::experimental::nullopt;
} }
std::experimental::optional<ast::Term> visit(const Clingo::AST::Variable &variable, const Clingo::AST::Term &, Context &context) std::experimental::optional<ast::Term> visit(const Clingo::AST::Variable &variable, const Clingo::AST::Term &, Context &, RuleContext &ruleContext, const ast::VariableStack &variableStack)
{ {
if (strcmp(variable.name, "_") == 0) const auto matchingVariableDeclaration = variableStack.findVariableDeclaration(variable.name);
{ const auto isAnonymousVariable = (strcmp(variable.name, "_") == 0);
std::string variableName = AnonymousVariablePrefix + std::to_string(context.anonymousVariableID); const auto isUndeclaredUserVariable = !matchingVariableDeclaration;
context.anonymousVariableID++; const auto isUndeclared = isAnonymousVariable || isUndeclaredUserVariable;
return ast::Term::make<ast::Variable>(std::move(variableName), ast::Variable::Type::Reserved); if (!isUndeclared)
} return ast::Term::make<ast::Variable>(*matchingVariableDeclaration);
return ast::Term::make<ast::Variable>(std::string(variable.name), ast::Variable::Type::UserDefined); auto variableDeclaration = std::make_unique<ast::VariableDeclaration>(std::string(variable.name), ast::VariableDeclaration::Type::UserDefined);
ruleContext.freeVariables.emplace_back(std::move(variableDeclaration));
return ast::Term::make<ast::Variable>(ruleContext.freeVariables.back().get());
} }
std::experimental::optional<ast::Term> visit(const Clingo::AST::UnaryOperation &, const Clingo::AST::Term &term, Context &context) std::experimental::optional<ast::Term> visit(const Clingo::AST::UnaryOperation &, const Clingo::AST::Term &term, Context &context, RuleContext &, const ast::VariableStack &)
{ {
throwErrorAtLocation(term.location, "“unary operation” terms currently unsupported", context); throwErrorAtLocation(term.location, "“unary operation” terms currently unsupported", context);
return std::experimental::nullopt; return std::experimental::nullopt;
} }
std::experimental::optional<ast::Term> visit(const Clingo::AST::BinaryOperation &binaryOperation, const Clingo::AST::Term &term, Context &context) std::experimental::optional<ast::Term> visit(const Clingo::AST::BinaryOperation &binaryOperation, const Clingo::AST::Term &term, Context &context, RuleContext &ruleContext, const ast::VariableStack &variableStack)
{ {
const auto operator_ = translate(binaryOperation.binary_operator, term, context); const auto operator_ = translate(binaryOperation.binary_operator, term, context);
auto left = translate(binaryOperation.left, context); auto left = translate(binaryOperation.left, context, ruleContext, variableStack);
auto right = translate(binaryOperation.right, context); auto right = translate(binaryOperation.right, context, ruleContext, variableStack);
return ast::Term::make<ast::BinaryOperation>(operator_, std::move(left), std::move(right)); return ast::Term::make<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) std::experimental::optional<ast::Term> visit(const Clingo::AST::Interval &interval, const Clingo::AST::Term &, Context &context, RuleContext &ruleContext, const ast::VariableStack &variableStack)
{ {
auto left = translate(interval.left, context); auto left = translate(interval.left, context, ruleContext, variableStack);
auto right = translate(interval.right, context); auto right = translate(interval.right, context, ruleContext, variableStack);
return ast::Term::make<ast::Interval>(std::move(left), std::move(right)); return ast::Term::make<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) std::experimental::optional<ast::Term> visit(const Clingo::AST::Function &function, const Clingo::AST::Term &term, Context &context, RuleContext &ruleContext, const ast::VariableStack &variableStack)
{ {
if (function.external) if (function.external)
throwErrorAtLocation(term.location, "external functions currently unsupported", context); throwErrorAtLocation(term.location, "external functions currently unsupported", context);
@ -126,12 +131,12 @@ struct TermTranslateVisitor
arguments.reserve(function.arguments.size()); arguments.reserve(function.arguments.size());
for (const auto &argument : function.arguments) for (const auto &argument : function.arguments)
arguments.emplace_back(translate(argument, context)); arguments.emplace_back(translate(argument, context, ruleContext, variableStack));
return ast::Term::make<ast::Function>(function.name, std::move(arguments)); return ast::Term::make<ast::Function>(function.name, std::move(arguments));
} }
std::experimental::optional<ast::Term> visit(const Clingo::AST::Pool &, const Clingo::AST::Term &term, Context &context) std::experimental::optional<ast::Term> visit(const Clingo::AST::Pool &, const Clingo::AST::Term &term, Context &context, RuleContext &, const ast::VariableStack &)
{ {
throwErrorAtLocation(term.location, "“pool” terms currently unsupported", context); throwErrorAtLocation(term.location, "“pool” terms currently unsupported", context);
return std::experimental::nullopt; return std::experimental::nullopt;
@ -140,9 +145,9 @@ struct TermTranslateVisitor
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
ast::Term translate(const Clingo::AST::Term &term, Context &context) ast::Term translate(const Clingo::AST::Term &term, Context &context, RuleContext &ruleContext, const ast::VariableStack &variableStack)
{ {
auto translatedTerm = term.data.accept(TermTranslateVisitor(), term, context); auto translatedTerm = term.data.accept(TermTranslateVisitor(), term, context, ruleContext, variableStack);
if (!translatedTerm) if (!translatedTerm)
throwErrorAtLocation(term.location, "could not translate term", context); throwErrorAtLocation(term.location, "could not translate term", context);

View File

@ -57,39 +57,9 @@ inline bool isPrefix(const char *prefix, const char *string)
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
constexpr const auto AuxiliaryHeadVariablePrefix = "V"; constexpr const auto HeadVariablePrefix = "V";
constexpr const auto AuxiliaryBodyVariablePrefix = "X"; constexpr const auto BodyVariablePrefix = "X";
constexpr const auto AnonymousVariablePrefix = "A"; constexpr const auto UserVariablePrefix = "U";
constexpr const auto UserVariablePrefix = "_";
////////////////////////////////////////////////////////////////////////////////////////////////////
inline bool isReservedVariableName(const char *variableName)
{
if (!isPrefix(AuxiliaryBodyVariablePrefix, variableName)
&& !isPrefix(AuxiliaryHeadVariablePrefix, variableName)
&& !isPrefix(AnonymousVariablePrefix, variableName))
{
return false;
}
assert(std::strlen(AuxiliaryBodyVariablePrefix) == std::strlen(AuxiliaryHeadVariablePrefix));
assert(std::strlen(AuxiliaryBodyVariablePrefix) == std::strlen(AnonymousVariablePrefix));
assert(std::strlen(AuxiliaryBodyVariablePrefix) == std::strlen(UserVariablePrefix));
const auto prefixLength = std::strlen(AuxiliaryBodyVariablePrefix);
if (strlen(variableName) == prefixLength)
return false;
const char *suffix = variableName + prefixLength;
for (const auto *i = suffix; *i != '\0'; i++)
if (!std::isdigit(*i))
return false;
return true;
}
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -2,6 +2,7 @@
#define __ANTHEM__OUTPUT__AST_H #define __ANTHEM__OUTPUT__AST_H
#include <cassert> #include <cassert>
#include <map>
#include <anthem/AST.h> #include <anthem/AST.h>
#include <anthem/Utils.h> #include <anthem/Utils.h>
@ -19,36 +20,46 @@ namespace ast
// //
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
output::ColorStream &operator<<(output::ColorStream &stream, BinaryOperation::Operator operator_); struct PrintContext
output::ColorStream &operator<<(output::ColorStream &stream, const BinaryOperation &binaryOperation); {
output::ColorStream &operator<<(output::ColorStream &stream, const Boolean &boolean); std::map<const ast::VariableDeclaration *, size_t> userVariableIDs;
output::ColorStream &operator<<(output::ColorStream &stream, const Comparison &comparison); std::map<const ast::VariableDeclaration *, size_t> headVariableIDs;
output::ColorStream &operator<<(output::ColorStream &stream, const Constant &constant); std::map<const ast::VariableDeclaration *, size_t> bodyVariableIDs;
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 &print(output::ColorStream &stream, const BinaryOperation::Operator operator_, PrintContext &printContext);
output::ColorStream &operator<<(output::ColorStream &stream, const Term &term); output::ColorStream &print(output::ColorStream &stream, const BinaryOperation &binaryOperation, PrintContext &printContext);
output::ColorStream &print(output::ColorStream &stream, const Boolean &boolean, PrintContext &printContext);
output::ColorStream &print(output::ColorStream &stream, const Comparison &comparison, PrintContext &printContext);
output::ColorStream &print(output::ColorStream &stream, const Constant &constant, PrintContext &printContext);
output::ColorStream &print(output::ColorStream &stream, const Function &function, PrintContext &printContext);
output::ColorStream &print(output::ColorStream &stream, const In &in, PrintContext &printContext);
output::ColorStream &print(output::ColorStream &stream, const Integer &integer, PrintContext &printContext);
output::ColorStream &print(output::ColorStream &stream, const Interval &interval, PrintContext &printContext);
output::ColorStream &print(output::ColorStream &stream, const Predicate &predicate, PrintContext &printContext);
output::ColorStream &print(output::ColorStream &stream, const SpecialInteger &specialInteger, PrintContext &printContext);
output::ColorStream &print(output::ColorStream &stream, const String &string, PrintContext &printContext);
output::ColorStream &print(output::ColorStream &stream, const Variable &variable, PrintContext &printContext);
output::ColorStream &print(output::ColorStream &stream, const VariableDeclaration &variableDeclaration, PrintContext &printContext);
output::ColorStream &print(output::ColorStream &stream, const And &and_, PrintContext &printContext);
output::ColorStream &print(output::ColorStream &stream, const Biconditional &biconditional, PrintContext &printContext);
output::ColorStream &print(output::ColorStream &stream, const Exists &exists, PrintContext &printContext);
output::ColorStream &print(output::ColorStream &stream, const ForAll &forAll, PrintContext &printContext);
output::ColorStream &print(output::ColorStream &stream, const Implies &implies, PrintContext &printContext);
output::ColorStream &print(output::ColorStream &stream, const Not &not_, PrintContext &printContext);
output::ColorStream &print(output::ColorStream &stream, const Or &or_, PrintContext &printContext);
output::ColorStream &print(output::ColorStream &stream, const Formula &formula, PrintContext &printContext);
output::ColorStream &print(output::ColorStream &stream, const Term &term, PrintContext &printContext);
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// Primitives // Primitives
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
inline output::ColorStream &operator<<(output::ColorStream &stream, BinaryOperation::Operator operator_) inline output::ColorStream &print(output::ColorStream &stream, BinaryOperation::Operator operator_, PrintContext &)
{ {
switch (operator_) switch (operator_)
{ {
@ -69,14 +80,22 @@ inline output::ColorStream &operator<<(output::ColorStream &stream, BinaryOperat
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
inline output::ColorStream &operator<<(output::ColorStream &stream, const BinaryOperation &binaryOperation) inline output::ColorStream &print(output::ColorStream &stream, const BinaryOperation &binaryOperation, PrintContext &printContext)
{ {
return (stream << "(" << binaryOperation.left << " " << binaryOperation.operator_ << " " << binaryOperation.right << ")"); stream << "(";
print(stream, binaryOperation.left, printContext);
stream << " ";
print(stream, binaryOperation.operator_, printContext);
stream << " ";
print(stream, binaryOperation.right, printContext);
stream << ")";
return stream;
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
inline output::ColorStream &operator<<(output::ColorStream &stream, const Boolean &boolean) inline output::ColorStream &print(output::ColorStream &stream, const Boolean &boolean, PrintContext &)
{ {
if (boolean.value) if (boolean.value)
return (stream << output::Boolean("#true")); return (stream << output::Boolean("#true"));
@ -86,7 +105,7 @@ inline output::ColorStream &operator<<(output::ColorStream &stream, const Boolea
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
inline output::ColorStream &operator<<(output::ColorStream &stream, Comparison::Operator operator_) inline output::ColorStream &print(output::ColorStream &stream, Comparison::Operator operator_, PrintContext &)
{ {
switch (operator_) switch (operator_)
{ {
@ -109,21 +128,27 @@ inline output::ColorStream &operator<<(output::ColorStream &stream, Comparison::
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
inline output::ColorStream &operator<<(output::ColorStream &stream, const Comparison &comparison) inline output::ColorStream &print(output::ColorStream &stream, const Comparison &comparison, PrintContext &printContext)
{ {
return (stream << comparison.left << " " << comparison.operator_ << " " << comparison.right); print(stream, comparison.left, printContext);
stream << " ";
print(stream, comparison.operator_, printContext);
stream << " ";
print(stream, comparison.right, printContext);
return stream;
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
inline output::ColorStream &operator<<(output::ColorStream &stream, const Constant &constant) inline output::ColorStream &print(output::ColorStream &stream, const Constant &constant, PrintContext &)
{ {
return (stream << constant.name); return (stream << constant.name);
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
inline output::ColorStream &operator<<(output::ColorStream &stream, const Function &function) inline output::ColorStream &print(output::ColorStream &stream, const Function &function, PrintContext &printContext)
{ {
stream << function.name; stream << function.name;
@ -137,39 +162,49 @@ inline output::ColorStream &operator<<(output::ColorStream &stream, const Functi
if (i != function.arguments.cbegin()) if (i != function.arguments.cbegin())
stream << ", "; stream << ", ";
stream << (*i); print(stream, *i, printContext);
} }
if (function.name.empty() && function.arguments.size() == 1) if (function.name.empty() && function.arguments.size() == 1)
stream << ","; stream << ",";
return (stream << ")"); stream << ")";
return stream;
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
inline output::ColorStream &operator<<(output::ColorStream &stream, const In &in) inline output::ColorStream &print(output::ColorStream &stream, const In &in, PrintContext &printContext)
{ {
return (stream << in.element << " " << output::Keyword("in") << " " << in.set); print(stream, in.element, printContext);
stream << " " << output::Keyword("in") << " ";
print(stream, in.set, printContext);
return stream;
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
inline output::ColorStream &operator<<(output::ColorStream &stream, const Integer &integer) inline output::ColorStream &print(output::ColorStream &stream, const Integer &integer, PrintContext &)
{ {
return (stream << output::Number<int>(integer.value)); return (stream << output::Number<int>(integer.value));
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
inline output::ColorStream &operator<<(output::ColorStream &stream, const Interval &interval) inline output::ColorStream &print(output::ColorStream &stream, const Interval &interval, PrintContext &printContext)
{ {
return (stream << interval.from << ".." << interval.to); print(stream, interval.from, printContext);
stream << "..";
print(stream, interval.to, printContext);
return stream;
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
inline output::ColorStream &operator<<(output::ColorStream &stream, const Predicate &predicate) inline output::ColorStream &print(output::ColorStream &stream, const Predicate &predicate, PrintContext &printContext)
{ {
stream << predicate.name; stream << predicate.name;
@ -183,15 +218,17 @@ inline output::ColorStream &operator<<(output::ColorStream &stream, const Predic
if (i != predicate.arguments.cbegin()) if (i != predicate.arguments.cbegin())
stream << ", "; stream << ", ";
stream << (*i); print(stream, *i, printContext);
} }
return (stream << ")"); stream << ")";
return stream;
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
inline output::ColorStream &operator<<(output::ColorStream &stream, const SpecialInteger &specialInteger) inline output::ColorStream &print(output::ColorStream &stream, const SpecialInteger &specialInteger, PrintContext &)
{ {
switch (specialInteger.type) switch (specialInteger.type)
{ {
@ -206,31 +243,59 @@ inline output::ColorStream &operator<<(output::ColorStream &stream, const Specia
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
inline output::ColorStream &operator<<(output::ColorStream &stream, const String &string) inline output::ColorStream &print(output::ColorStream &stream, const String &string, PrintContext &)
{ {
return (stream << output::String(string.text.c_str())); return (stream << output::String(string.text.c_str()));
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
inline output::ColorStream &operator<<(output::ColorStream &stream, const Variable &variable) inline output::ColorStream &print(output::ColorStream &stream, const Variable &variable, PrintContext &printContext)
{ {
assert(!variable.name.empty()); assert(variable.declaration != nullptr);
assert(variable.name != "_");
if (variable.type == ast::Variable::Type::Reserved || !isReservedVariableName(variable.name.c_str())) return print(stream, *variable.declaration, printContext);
return (stream << output::Variable(variable.name.c_str())); }
const auto variableName = std::string(UserVariablePrefix) + variable.name; ////////////////////////////////////////////////////////////////////////////////////////////////////
return (stream << output::Variable(variableName.c_str())); inline output::ColorStream &print(output::ColorStream &stream, const VariableDeclaration &variableDeclaration, PrintContext &printContext)
{
const auto printVariableDeclaration =
[&stream, &variableDeclaration](const auto *prefix, auto &variableIDs) -> output::ColorStream &
{
auto matchingVariableID = variableIDs.find(&variableDeclaration);
if (matchingVariableID == variableIDs.cend())
{
auto emplaceResult = variableIDs.emplace(std::make_pair(&variableDeclaration, variableIDs.size() + 1));
assert(emplaceResult.second);
matchingVariableID = emplaceResult.first;
}
const auto variableName = std::string(prefix) + std::to_string(matchingVariableID->second);
return (stream << output::Variable(variableName.c_str()));
};
switch (variableDeclaration.type)
{
case VariableDeclaration::Type::UserDefined:
return printVariableDeclaration(UserVariablePrefix, printContext.userVariableIDs);
case VariableDeclaration::Type::Head:
return printVariableDeclaration(HeadVariablePrefix, printContext.headVariableIDs);
case VariableDeclaration::Type::Body:
return printVariableDeclaration(BodyVariablePrefix, printContext.bodyVariableIDs);
}
return stream;
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// Expressions // Expressions
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
inline output::ColorStream &operator<<(output::ColorStream &stream, const And &and_) inline output::ColorStream &print(output::ColorStream &stream, const And &and_, PrintContext &printContext)
{ {
stream << "("; stream << "(";
@ -239,22 +304,30 @@ inline output::ColorStream &operator<<(output::ColorStream &stream, const And &a
if (i != and_.arguments.cbegin()) if (i != and_.arguments.cbegin())
stream << " " << output::Keyword("and") << " "; stream << " " << output::Keyword("and") << " ";
stream << (*i); print(stream, *i, printContext);
} }
return (stream << ")"); stream << ")";
return stream;
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
inline output::ColorStream &operator<<(output::ColorStream &stream, const Biconditional &biconditional) inline output::ColorStream &print(output::ColorStream &stream, const Biconditional &biconditional, PrintContext &printContext)
{ {
return (stream << "(" << biconditional.left << " <-> " << biconditional.right << ")"); stream << "(";
print(stream, biconditional.left, printContext);
stream << " <-> ";
print(stream, biconditional.right, printContext);
stream << ")";
return stream;
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
inline output::ColorStream &operator<<(output::ColorStream &stream, const Exists &exists) inline output::ColorStream &print(output::ColorStream &stream, const Exists &exists, PrintContext &printContext)
{ {
stream << output::Keyword("exists") << " "; stream << output::Keyword("exists") << " ";
@ -263,15 +336,18 @@ inline output::ColorStream &operator<<(output::ColorStream &stream, const Exists
if (i != exists.variables.cbegin()) if (i != exists.variables.cbegin())
stream << ", "; stream << ", ";
stream << (*i); print(stream, **i, printContext);
} }
return (stream << " " << exists.argument); stream << " ";
print(stream, exists.argument, printContext);
return stream;
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
inline output::ColorStream &operator<<(output::ColorStream &stream, const ForAll &forAll) inline output::ColorStream &print(output::ColorStream &stream, const ForAll &forAll, PrintContext &printContext)
{ {
stream << output::Keyword("forall") << " "; stream << output::Keyword("forall") << " ";
@ -280,29 +356,41 @@ inline output::ColorStream &operator<<(output::ColorStream &stream, const ForAll
if (i != forAll.variables.cbegin()) if (i != forAll.variables.cbegin())
stream << ", "; stream << ", ";
stream << (*i); print(stream, **i, printContext);
} }
return (stream << " " << forAll.argument); stream << " ";
print(stream, forAll.argument, printContext);
return stream;
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
inline output::ColorStream &operator<<(output::ColorStream &stream, const Implies &implies) inline output::ColorStream &print(output::ColorStream &stream, const Implies &implies, PrintContext &printContext)
{ {
return (stream << "(" << implies.antecedent << " -> " << implies.consequent << ")"); stream << "(";
print(stream, implies.antecedent, printContext);
stream << " -> ";
print(stream, implies.consequent, printContext);
stream << ")";
return stream;
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
inline output::ColorStream &operator<<(output::ColorStream &stream, const Not &not_) inline output::ColorStream &print(output::ColorStream &stream, const Not &not_, PrintContext &printContext)
{ {
return (stream << output::Keyword("not ") << not_.argument); stream << output::Keyword("not") << " ";
print(stream, not_.argument, printContext);
return stream;
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
inline output::ColorStream &operator<<(output::ColorStream &stream, const Or &or_) inline output::ColorStream &print(output::ColorStream &stream, const Or &or_, PrintContext &printContext)
{ {
stream << "("; stream << "(";
@ -311,10 +399,12 @@ inline output::ColorStream &operator<<(output::ColorStream &stream, const Or &or
if (i != or_.arguments.cbegin()) if (i != or_.arguments.cbegin())
stream << " " << output::Keyword("or") << " "; stream << " " << output::Keyword("or") << " ";
stream << (*i); print(stream, *i, printContext);
} }
return (stream << ")"); stream << ")";
return stream;
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
@ -325,24 +415,24 @@ template<class Variant>
struct VariantPrintVisitor struct VariantPrintVisitor
{ {
template<class T> template<class T>
output::ColorStream &visit(const T &x, output::ColorStream &stream) output::ColorStream &visit(const T &x, output::ColorStream &stream, PrintContext &printContext)
{ {
return (stream << x); return print(stream, x, printContext);
} }
}; };
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
inline output::ColorStream &operator<<(output::ColorStream &stream, const Formula &formula) inline output::ColorStream &print(output::ColorStream &stream, const Formula &formula, PrintContext &printContext)
{ {
return formula.accept(VariantPrintVisitor<ast::Formula>(), stream); return formula.accept(VariantPrintVisitor<ast::Formula>(), stream, printContext);
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
inline output::ColorStream &operator<<(output::ColorStream &stream, const Term &term) inline output::ColorStream &print(output::ColorStream &stream, const Term &term, PrintContext &printContext)
{ {
return term.accept(VariantPrintVisitor<ast::Term>(), stream); return term.accept(VariantPrintVisitor<ast::Term>(), stream, printContext);
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////

498
src/anthem/ASTCopy.cpp Normal file
View File

@ -0,0 +1,498 @@
#include <anthem/ASTCopy.h>
#include <map>
#include <anthem/ASTUtils.h>
#include <anthem/ASTVisitors.h>
namespace anthem
{
namespace ast
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// ASTCopy
//
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
// Replacing Variables
////////////////////////////////////////////////////////////////////////////////////////////////////
// Replaces all occurrences of a variable in a given term with another term
struct ReplaceVariableInTermVisitor : public ast::RecursiveTermVisitor<ReplaceVariableInTermVisitor>
{
static void accept(ast::Variable &variable, ast::Term &, const ast::VariableDeclaration *original, ast::VariableDeclaration *replacement)
{
if (variable.declaration == original)
variable.declaration = replacement;
}
// Ignore all other types of expressions
template<class T>
static void accept(T &, ast::Term &, const ast::VariableDeclaration *, ast::VariableDeclaration *)
{
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////
// Replaces all occurrences of a variable in a given formula with a term
struct ReplaceVariableInFormulaVisitor : public ast::RecursiveFormulaVisitor<ReplaceVariableInFormulaVisitor>
{
static void accept(ast::Comparison &comparison, ast::Formula &, const ast::VariableDeclaration *original, ast::VariableDeclaration *replacement)
{
comparison.left.accept(ReplaceVariableInTermVisitor(), comparison.left, original, replacement);
comparison.right.accept(ReplaceVariableInTermVisitor(), comparison.right, original, replacement);
}
static void accept(ast::In &in, ast::Formula &, const ast::VariableDeclaration *original, ast::VariableDeclaration *replacement)
{
in.element.accept(ReplaceVariableInTermVisitor(), in.element, original, replacement);
in.set.accept(ReplaceVariableInTermVisitor(), in.set, original, replacement);
}
static void accept(ast::Predicate &predicate, ast::Formula &, const ast::VariableDeclaration *original, ast::VariableDeclaration *replacement)
{
for (auto &argument : predicate.arguments)
argument.accept(ReplaceVariableInTermVisitor(), argument, original, replacement);
}
// Ignore all other types of expressions
template<class T>
static void accept(T &, ast::Formula &, const ast::VariableDeclaration *, ast::VariableDeclaration *)
{
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////
// Preparing Copying
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Variant>
struct VariantDeepCopyVisitor
{
template<class T>
Variant visit(const T &x)
{
return prepareCopy(x);
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class T>
std::unique_ptr<T> prepareCopy(const std::unique_ptr<T> &uniquePtr)
{
return std::make_unique<T>(prepareCopy(*uniquePtr));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
const auto prepareCopyVariant =
[](const auto &variant) -> typename std::decay<decltype(variant)>::type
{
using VariantType = typename std::decay<decltype(variant)>::type;
return variant.accept(VariantDeepCopyVisitor<VariantType>());
};
////////////////////////////////////////////////////////////////////////////////////////////////////
const auto prepareCopyVariantVector =
[](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(prepareCopyVariant(variant));
return result;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
const auto prepareCopyVector =
[](const auto &vector) -> typename std::decay<decltype(vector)>::type
{
using Type = typename std::decay<decltype(vector)>::type::value_type;
std::vector<Type> result;
result.reserve(vector.size());
for (const auto &element : vector)
result.emplace_back(prepareCopy(element));
return result;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
BinaryOperation prepareCopy(const BinaryOperation &other)
{
return BinaryOperation(other.operator_, prepareCopy(other.left), prepareCopy(other.right));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
Boolean prepareCopy(const Boolean &other)
{
return Boolean(other.value);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
Comparison prepareCopy(const Comparison &other)
{
return Comparison(other.operator_, prepareCopy(other.left), prepareCopy(other.right));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
Constant prepareCopy(const Constant &other)
{
return Constant(std::string(other.name));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
Function prepareCopy(const Function &other)
{
return Function(std::string(other.name), prepareCopy(other.arguments));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
In prepareCopy(const In &other)
{
return In(prepareCopy(other.element), prepareCopy(other.set));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
Integer prepareCopy(const Integer &other)
{
return Integer(other.value);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
Interval prepareCopy(const Interval &other)
{
return Interval(prepareCopy(other.from), prepareCopy(other.to));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
Predicate prepareCopy(const Predicate &other)
{
return Predicate(std::string(other.name), prepareCopy(other.arguments));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
SpecialInteger prepareCopy(const SpecialInteger &other)
{
return SpecialInteger(other.type);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
String prepareCopy(const String &other)
{
return String(std::string(other.text));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
Variable prepareCopy(const Variable &other)
{
return Variable(other.declaration);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
VariableDeclaration prepareCopy(const VariableDeclaration &other)
{
return VariableDeclaration(std::string(other.name), other.type);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
VariableDeclarationPointers prepareCopy(const VariableDeclarationPointers &other)
{
return prepareCopyVector(other);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
And prepareCopy(const And &other)
{
return And(prepareCopy(other.arguments));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
Biconditional prepareCopy(const Biconditional &other)
{
return Biconditional(prepareCopy(other.left), prepareCopy(other.right));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
Exists prepareCopy(const Exists &other)
{
Exists copy(prepareCopy(other.variables), prepareCopy(other.argument));
// TODO: refactor
for (size_t i = 0; i < other.variables.size(); i++)
copy.argument.accept(ReplaceVariableInFormulaVisitor(), copy.argument, other.variables[i].get(), copy.variables[i].get());
return copy;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ForAll prepareCopy(const ForAll &other)
{
ForAll copy(prepareCopy(other.variables), prepareCopy(other.argument));
// TODO: refactor
for (size_t i = 0; i < other.variables.size(); i++)
copy.argument.accept(ReplaceVariableInFormulaVisitor(), copy.argument, other.variables[i].get(), copy.variables[i].get());
return copy;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
Implies prepareCopy(const Implies &other)
{
return Implies(prepareCopy(other.antecedent), prepareCopy(other.consequent));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
Not prepareCopy(const Not &other)
{
return Not(prepareCopy(other.argument));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
Or prepareCopy(const Or &other)
{
return Or(prepareCopy(other.arguments));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
Formula prepareCopy(const Formula &formula)
{
return prepareCopyVariant(formula);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
Term prepareCopy(const Term &term)
{
return prepareCopyVariant(term);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
std::vector<Term> prepareCopy(const std::vector<Term> &terms)
{
return prepareCopyVariantVector(terms);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
std::vector<Formula> prepareCopy(const std::vector<Formula> &formulas)
{
return prepareCopyVariantVector(formulas);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Fixing Dangling Variables
////////////////////////////////////////////////////////////////////////////////////////////////////
// Fix all dangling variables in a given term
struct FixDanglingVariablesInTermVisitor
{
template <class... Arguments>
void visit(BinaryOperation &binaryOperation, Arguments &&... arguments)
{
binaryOperation.left.accept(*this, std::forward<Arguments>(arguments)...);
binaryOperation.right.accept(*this, std::forward<Arguments>(arguments)...);
}
template <class... Arguments>
void visit(Boolean &, Arguments &&...)
{
}
template <class... Arguments>
void visit(Constant &, Arguments &&...)
{
}
template <class... Arguments>
void visit(Function &function, Arguments &&... arguments)
{
for (auto &argument : function.arguments)
argument.accept(*this, std::forward<Arguments>(arguments)...);
}
template <class... Arguments>
void visit(Integer &, Arguments &&...)
{
}
template <class... Arguments>
void visit(Interval &interval, Arguments &&... arguments)
{
interval.from.accept(*this, std::forward<Arguments>(arguments)...);
interval.to.accept(*this, std::forward<Arguments>(arguments)...);
}
template <class... Arguments>
void visit(SpecialInteger &, Arguments &&...)
{
}
template <class... Arguments>
void visit(String &, Arguments &&...)
{
}
void visit(Variable &variable, ScopedFormula &scopedFormula, VariableStack &variableStack,
std::map<VariableDeclaration *, VariableDeclaration *> &replacements)
{
const auto match = replacements.find(variable.declaration);
// Replace the variable if it is flagged for replacement
if (match != replacements.cend())
{
variable.declaration = match->second;
return;
}
// If the variable is not flagged for replacement yet, check whether it is dangling
const auto isVariableDangling = !variableStack.contains(*variable.declaration);
if (!isVariableDangling)
return;
// If the variable is dangling, declare it correctly and flag it for future replacement
auto newVariableDeclaration = std::make_unique<VariableDeclaration>(std::string(variable.declaration->name), variable.declaration->type);
scopedFormula.freeVariables.emplace_back(std::move(newVariableDeclaration));
replacements[variable.declaration] = scopedFormula.freeVariables.back().get();
variable.declaration = scopedFormula.freeVariables.back().get();
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////
// Fix all dangling variables in a given formula
struct FixDanglingVariablesInFormulaVisitor
{
template <class... Arguments>
void visit(And &and_, Arguments &&... arguments)
{
for (auto &argument : and_.arguments)
argument.accept(*this, std::forward<Arguments>(arguments)...);
}
template <class... Arguments>
void visit(Biconditional &biconditional, Arguments &&... arguments)
{
biconditional.left.accept(*this, std::forward<Arguments>(arguments)...);
biconditional.right.accept(*this, std::forward<Arguments>(arguments)...);
}
template <class... Arguments>
void visit(Boolean &, Arguments &&...)
{
}
template <class... Arguments>
void visit(Comparison &comparison, Arguments &&... arguments)
{
comparison.left.accept(FixDanglingVariablesInTermVisitor(), std::forward<Arguments>(arguments)...);
comparison.right.accept(FixDanglingVariablesInTermVisitor(), std::forward<Arguments>(arguments)...);
}
void visit(Exists &exists, ScopedFormula &scopedFormula, VariableStack &variableStack,
std::map<VariableDeclaration *, VariableDeclaration *> &replacements)
{
variableStack.push(&exists.variables);
exists.argument.accept(*this, scopedFormula, variableStack, replacements);
variableStack.pop();
}
void visit(ForAll &forAll, ScopedFormula &scopedFormula, VariableStack &variableStack,
std::map<VariableDeclaration *, VariableDeclaration *> &replacements)
{
variableStack.push(&forAll.variables);
forAll.argument.accept(*this, scopedFormula, variableStack, replacements);
variableStack.pop();
}
template <class... Arguments>
void visit(Implies &implies, Arguments &&... arguments)
{
implies.antecedent.accept(*this, std::forward<Arguments>(arguments)...);
implies.consequent.accept(*this, std::forward<Arguments>(arguments)...);
}
template <class... Arguments>
void visit(In &in, Arguments &&... arguments)
{
in.element.accept(FixDanglingVariablesInTermVisitor(), std::forward<Arguments>(arguments)...);
in.set.accept(FixDanglingVariablesInTermVisitor(), std::forward<Arguments>(arguments)...);
}
template <class... Arguments>
void visit(Not &not_, Arguments &&... arguments)
{
not_.argument.accept(*this, std::forward<Arguments>(arguments)...);
}
template <class... Arguments>
void visit(Or &or_, Arguments &&... arguments)
{
for (auto &argument : or_.arguments)
argument.accept(*this, std::forward<Arguments>(arguments)...);
}
template <class... Arguments>
void visit(Predicate &predicate, Arguments &&... arguments)
{
for (auto &argument : predicate.arguments)
argument.accept(FixDanglingVariablesInTermVisitor(), std::forward<Arguments>(arguments)...);
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////
void fixDanglingVariables(ScopedFormula &scopedFormula)
{
VariableStack variableStack;
variableStack.push(&scopedFormula.freeVariables);
std::map<VariableDeclaration *, VariableDeclaration *> replacements;
scopedFormula.formula.accept(FixDanglingVariablesInFormulaVisitor(), scopedFormula,
variableStack, replacements);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}

View File

@ -27,21 +27,43 @@ void VariableStack::pop()
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
bool VariableStack::contains(const ast::Variable &variable) const std::experimental::optional<ast::VariableDeclaration *> VariableStack::findVariableDeclaration(const char *variableName) const
{ {
const auto variableMatches = const auto variableNameMatches =
[&variable](const auto &otherVariable) [&variableName](const auto &variableDeclaration)
{ {
return variable.name == otherVariable.name; return variableDeclaration->name == variableName;
}; };
const auto layerContainsVariable = for (auto i = m_layers.rbegin(); i != m_layers.rend(); i++)
[&variable, &variableMatches](const auto &layer) {
auto &layer = **i;
const auto matchingVariableDeclaration = std::find_if(layer.begin(), layer.end(), variableNameMatches);
if (matchingVariableDeclaration != layer.end())
return matchingVariableDeclaration->get();
}
return std::experimental::nullopt;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
bool VariableStack::contains(const ast::VariableDeclaration &variableDeclaration) const
{
const auto variableDeclarationMatches =
[&variableDeclaration](const auto &other)
{ {
return (std::find_if(layer->cbegin(), layer->cend(), variableMatches) != layer->cend()); return variableDeclaration.name == other->name;
}; };
return (std::find_if(m_layers.cbegin(), m_layers.cend(), layerContainsVariable) != m_layers.cend()); const auto layerContainsVariableDeclaration =
[&variableDeclaration, &variableDeclarationMatches](const auto &layer)
{
return (std::find_if(layer->cbegin(), layer->cend(), variableDeclarationMatches) != layer->cend());
};
return (std::find_if(m_layers.cbegin(), m_layers.cend(), layerContainsVariableDeclaration) != m_layers.cend());
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
@ -52,68 +74,68 @@ struct CollectFreeVariablesVisitor
// Formulas // Formulas
//////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////
void visit(const ast::And &and_, VariableStack &variableStack, std::vector<ast::Variable> &freeVariables) void visit(ast::And &and_, VariableStack &variableStack, std::vector<ast::VariableDeclaration *> &freeVariables)
{ {
for (const auto &argument : and_.arguments) for (auto &argument : and_.arguments)
argument.accept(*this, variableStack, freeVariables); argument.accept(*this, variableStack, freeVariables);
} }
void visit(const ast::Biconditional &biconditional, VariableStack &variableStack, std::vector<ast::Variable> &freeVariables) void visit(ast::Biconditional &biconditional, VariableStack &variableStack, std::vector<ast::VariableDeclaration *> &freeVariables)
{ {
biconditional.left.accept(*this, variableStack, freeVariables); biconditional.left.accept(*this, variableStack, freeVariables);
biconditional.right.accept(*this, variableStack, freeVariables); biconditional.right.accept(*this, variableStack, freeVariables);
} }
void visit(const ast::Boolean &, VariableStack &, std::vector<ast::Variable> &) void visit(ast::Boolean &, VariableStack &, std::vector<ast::VariableDeclaration *> &)
{ {
} }
void visit(const ast::Comparison &comparison, VariableStack &variableStack, std::vector<ast::Variable> &freeVariables) void visit(ast::Comparison &comparison, VariableStack &variableStack, std::vector<ast::VariableDeclaration *> &freeVariables)
{ {
comparison.left.accept(*this, variableStack, freeVariables); comparison.left.accept(*this, variableStack, freeVariables);
comparison.right.accept(*this, variableStack, freeVariables); comparison.right.accept(*this, variableStack, freeVariables);
} }
void visit(const ast::Exists &exists, VariableStack &variableStack, std::vector<ast::Variable> &freeVariables) void visit(ast::Exists &exists, VariableStack &variableStack, std::vector<ast::VariableDeclaration *> &freeVariables)
{ {
variableStack.push(&exists.variables); variableStack.push(&exists.variables);
exists.argument.accept(*this, variableStack, freeVariables); exists.argument.accept(*this, variableStack, freeVariables);
variableStack.pop(); variableStack.pop();
} }
void visit(const ast::ForAll &forAll, VariableStack &variableStack, std::vector<ast::Variable> &freeVariables) void visit(ast::ForAll &forAll, VariableStack &variableStack, std::vector<ast::VariableDeclaration *> &freeVariables)
{ {
variableStack.push(&forAll.variables); variableStack.push(&forAll.variables);
forAll.argument.accept(*this, variableStack, freeVariables); forAll.argument.accept(*this, variableStack, freeVariables);
variableStack.pop(); variableStack.pop();
} }
void visit(const ast::Implies &implies, VariableStack &variableStack, std::vector<ast::Variable> &freeVariables) void visit(ast::Implies &implies, VariableStack &variableStack, std::vector<ast::VariableDeclaration *> &freeVariables)
{ {
implies.antecedent.accept(*this, variableStack, freeVariables); implies.antecedent.accept(*this, variableStack, freeVariables);
implies.consequent.accept(*this, variableStack, freeVariables); implies.consequent.accept(*this, variableStack, freeVariables);
} }
void visit(const ast::In &in, VariableStack &variableStack, std::vector<ast::Variable> &freeVariables) void visit(ast::In &in, VariableStack &variableStack, std::vector<ast::VariableDeclaration *> &freeVariables)
{ {
in.element.accept(*this, variableStack, freeVariables); in.element.accept(*this, variableStack, freeVariables);
in.set.accept(*this, variableStack, freeVariables); in.set.accept(*this, variableStack, freeVariables);
} }
void visit(const ast::Not &not_, VariableStack &variableStack, std::vector<ast::Variable> &freeVariables) void visit(ast::Not &not_, VariableStack &variableStack, std::vector<ast::VariableDeclaration *> &freeVariables)
{ {
not_.argument.accept(*this, variableStack, freeVariables); not_.argument.accept(*this, variableStack, freeVariables);
} }
void visit(const ast::Or &or_, VariableStack &variableStack, std::vector<ast::Variable> &freeVariables) void visit(ast::Or &or_, VariableStack &variableStack, std::vector<ast::VariableDeclaration *> &freeVariables)
{ {
for (const auto &argument : or_.arguments) for (auto &argument : or_.arguments)
argument.accept(*this, variableStack, freeVariables); argument.accept(*this, variableStack, freeVariables);
} }
void visit(const ast::Predicate &predicate, VariableStack &variableStack, std::vector<ast::Variable> &freeVariables) void visit(ast::Predicate &predicate, VariableStack &variableStack, std::vector<ast::VariableDeclaration *> &freeVariables)
{ {
for (const auto &argument : predicate.arguments) for (auto &argument : predicate.arguments)
argument.accept(*this, variableStack, freeVariables); argument.accept(*this, variableStack, freeVariables);
} }
@ -121,61 +143,55 @@ struct CollectFreeVariablesVisitor
// Terms // Terms
//////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////
void visit(const ast::BinaryOperation &binaryOperation, VariableStack &variableStack, std::vector<ast::Variable> &freeVariables) void visit(ast::BinaryOperation &binaryOperation, VariableStack &variableStack, std::vector<ast::VariableDeclaration *> &freeVariables)
{ {
binaryOperation.left.accept(*this, variableStack, freeVariables); binaryOperation.left.accept(*this, variableStack, freeVariables);
binaryOperation.right.accept(*this, variableStack, freeVariables); binaryOperation.right.accept(*this, variableStack, freeVariables);
} }
void visit(const ast::Constant &, VariableStack &, std::vector<ast::Variable> &) void visit(ast::Constant &, VariableStack &, std::vector<ast::VariableDeclaration *> &)
{ {
} }
void visit(const ast::Function &function, VariableStack &variableStack, std::vector<ast::Variable> &freeVariables) void visit(ast::Function &function, VariableStack &variableStack, std::vector<ast::VariableDeclaration *> &freeVariables)
{ {
for (const auto &argument : function.arguments) for (auto &argument : function.arguments)
argument.accept(*this, variableStack, freeVariables); argument.accept(*this, variableStack, freeVariables);
} }
void visit(const ast::Integer &, VariableStack &, std::vector<ast::Variable> &) void visit(ast::Integer &, VariableStack &, std::vector<ast::VariableDeclaration *> &)
{ {
} }
void visit(const ast::Interval &interval, VariableStack &variableStack, std::vector<ast::Variable> &freeVariables) void visit(ast::Interval &interval, VariableStack &variableStack, std::vector<ast::VariableDeclaration *> &freeVariables)
{ {
interval.from.accept(*this, variableStack, freeVariables); interval.from.accept(*this, variableStack, freeVariables);
interval.to.accept(*this, variableStack, freeVariables); interval.to.accept(*this, variableStack, freeVariables);
} }
void visit(const ast::SpecialInteger &, VariableStack &, std::vector<ast::Variable> &) void visit(ast::SpecialInteger &, VariableStack &, std::vector<ast::VariableDeclaration *> &)
{ {
} }
void visit(const ast::String &, VariableStack &, std::vector<ast::Variable> &) void visit(ast::String &, VariableStack &, std::vector<ast::VariableDeclaration *> &)
{ {
} }
void visit(const ast::Variable &variable, VariableStack &variableStack, std::vector<ast::Variable> &freeVariables) void visit(ast::Variable &variable, VariableStack &variableStack, std::vector<ast::VariableDeclaration *> &freeVariables)
{ {
if (variableStack.contains(variable)) if (variableStack.contains(*variable.declaration))
return; return;
const auto &variableMatches = if (std::find(freeVariables.cbegin(), freeVariables.cend(), variable.declaration) != freeVariables.cend())
[&variable](auto &otherVariable)
{
return variable.name == otherVariable.name;
};
if (std::find_if(freeVariables.cbegin(), freeVariables.cend(), variableMatches) != freeVariables.cend())
return; return;
freeVariables.emplace_back(ast::deepCopy(variable)); freeVariables.emplace_back(variable.declaration);
} }
}; };
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
std::vector<ast::Variable> collectFreeVariables(const ast::Formula &formula) std::vector<ast::VariableDeclaration *> collectFreeVariables(ast::Formula &formula)
{ {
ast::VariableStack variableStack; ast::VariableStack variableStack;
return collectFreeVariables(formula, variableStack); return collectFreeVariables(formula, variableStack);
@ -183,9 +199,9 @@ std::vector<ast::Variable> collectFreeVariables(const ast::Formula &formula)
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
std::vector<ast::Variable> collectFreeVariables(const ast::Formula &formula, ast::VariableStack &variableStack) std::vector<ast::VariableDeclaration *> collectFreeVariables(ast::Formula &formula, ast::VariableStack &variableStack)
{ {
std::vector<ast::Variable> freeVariables; std::vector<ast::VariableDeclaration *> freeVariables;
formula.accept(CollectFreeVariablesVisitor(), variableStack, freeVariables); formula.accept(CollectFreeVariablesVisitor(), variableStack, freeVariables);

View File

@ -1,5 +1,6 @@
#include <anthem/Completion.h> #include <anthem/Completion.h>
#include <anthem/AST.h>
#include <anthem/ASTUtils.h> #include <anthem/ASTUtils.h>
#include <anthem/ASTVisitors.h> #include <anthem/ASTVisitors.h>
#include <anthem/Utils.h> #include <anthem/Utils.h>
@ -14,16 +15,17 @@ namespace anthem
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// Copies the parameters of a predicate // Copies the parameters of a predicate
std::vector<ast::Variable> copyParameters(const ast::Predicate &predicate) std::vector<std::unique_ptr<ast::VariableDeclaration>> copyParameters(const ast::Predicate &predicate)
{ {
std::vector<ast::Variable> parameters; std::vector<std::unique_ptr<ast::VariableDeclaration>> parameters;
parameters.reserve(predicate.arity()); /*parameters.reserve(predicate.arity());
for (const auto &parameter : predicate.arguments) for (const auto &argument : predicate.arguments)
{ {
assert(parameter.is<ast::Variable>()); assert(argument.is<ast::Variable>());
parameters.emplace_back(ast::deepCopy(parameter.get<ast::Variable>())); // TODO: reimplement
} //parameters.emplace_back(ast::deepCopy(parameter.get<ast::VariableDeclaration>()));
}*/
return parameters; return parameters;
} }
@ -31,18 +33,18 @@ std::vector<ast::Variable> copyParameters(const ast::Predicate &predicate)
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// Builds the conjunction within the completed formula for a given predicate // Builds the conjunction within the completed formula for a given predicate
ast::Formula buildCompletedFormulaDisjunction(const ast::Predicate &predicate, const std::vector<ast::Variable> &parameters, const std::vector<ast::Formula> &formulas) ast::Formula buildCompletedFormulaDisjunction(const ast::Predicate &predicate, std::vector<std::unique_ptr<ast::VariableDeclaration>> &parameters, std::vector<ast::ScopedFormula> &scopedFormulas)
{ {
auto disjunction = ast::Formula::make<ast::Or>(); auto disjunction = ast::Formula::make<ast::Or>();
ast::VariableStack variableStack; /*ast::VariableStack variableStack;
variableStack.push(&parameters); variableStack.push(&parameters);
// Build the conjunction of all formulas with the predicate as consequent // Build the conjunction of all formulas with the predicate as consequent
for (const auto &formula : formulas) for (auto &scopedFormula : scopedFormulas)
{ {
assert(formula.is<ast::Implies>()); assert(scopedFormula.formula.is<ast::Implies>());
const auto &implies = formula.get<ast::Implies>(); auto &implies = scopedFormula.formula.get<ast::Implies>();
if (!implies.consequent.is<ast::Predicate>()) if (!implies.consequent.is<ast::Predicate>())
continue; continue;
@ -55,6 +57,7 @@ ast::Formula buildCompletedFormulaDisjunction(const ast::Predicate &predicate, c
auto variables = ast::collectFreeVariables(implies.antecedent, variableStack); auto variables = ast::collectFreeVariables(implies.antecedent, variableStack);
// TODO: avoid deep copies // TODO: avoid deep copies
// TODO: reimplement
if (variables.empty()) if (variables.empty())
disjunction.get<ast::Or>().arguments.emplace_back(ast::deepCopy(implies.antecedent)); disjunction.get<ast::Or>().arguments.emplace_back(ast::deepCopy(implies.antecedent));
else else
@ -62,7 +65,7 @@ ast::Formula buildCompletedFormulaDisjunction(const ast::Predicate &predicate, c
auto exists = ast::Formula::make<ast::Exists>(std::move(variables), ast::deepCopy(implies.antecedent)); auto exists = ast::Formula::make<ast::Exists>(std::move(variables), ast::deepCopy(implies.antecedent));
disjunction.get<ast::Or>().arguments.emplace_back(std::move(exists)); disjunction.get<ast::Or>().arguments.emplace_back(std::move(exists));
} }
} }*/
return disjunction; return disjunction;
} }
@ -74,7 +77,7 @@ ast::Formula buildCompletedFormulaQuantified(ast::Predicate &&predicate, ast::Fo
{ {
assert(innerFormula.is<ast::Or>()); assert(innerFormula.is<ast::Or>());
if (innerFormula.get<ast::Or>().arguments.empty()) /*if (innerFormula.get<ast::Or>().arguments.empty())
return ast::Formula::make<ast::Not>(std::move(predicate)); return ast::Formula::make<ast::Not>(std::move(predicate));
if (innerFormula.get<ast::Or>().arguments.size() == 1) if (innerFormula.get<ast::Or>().arguments.size() == 1)
@ -88,17 +91,17 @@ ast::Formula buildCompletedFormulaQuantified(ast::Predicate &&predicate, ast::Fo
return std::move(predicate); return std::move(predicate);
else else
return ast::Formula::make<ast::Not>(std::move(predicate)); return ast::Formula::make<ast::Not>(std::move(predicate));
} }*/
return ast::Formula::make<ast::Biconditional>(std::move(predicate), std::move(innerFormula)); return ast::Formula::make<ast::Biconditional>(std::move(predicate), std::move(innerFormula));
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
void completePredicate(ast::Predicate &&predicate, const std::vector<ast::Formula> &formulas, std::vector<ast::Formula> &completedFormulas) void completePredicate(ast::Predicate &&predicate, std::vector<ast::ScopedFormula> &scopedFormulas, std::vector<ast::ScopedFormula> &completedScopedFormulas)
{ {
auto parameters = copyParameters(predicate); /*auto parameters = copyParameters(predicate);
auto completedFormulaDisjunction = buildCompletedFormulaDisjunction(predicate, parameters, formulas); auto completedFormulaDisjunction = buildCompletedFormulaDisjunction(predicate, parameters, scopedFormulas);
auto completedFormulaQuantified = buildCompletedFormulaQuantified(std::move(predicate), std::move(completedFormulaDisjunction)); auto completedFormulaQuantified = buildCompletedFormulaQuantified(std::move(predicate), std::move(completedFormulaDisjunction));
if (parameters.empty()) if (parameters.empty())
@ -108,14 +111,14 @@ void completePredicate(ast::Predicate &&predicate, const std::vector<ast::Formul
} }
auto completedFormula = ast::Formula::make<ast::ForAll>(std::move(parameters), std::move(completedFormulaQuantified)); auto completedFormula = ast::Formula::make<ast::ForAll>(std::move(parameters), std::move(completedFormulaQuantified));
completedFormulas.emplace_back(std::move(completedFormula)); completedFormulas.emplace_back(std::move(completedFormula));*/
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
void completeIntegrityConstraint(const ast::Formula &formula, std::vector<ast::Formula> &completedFormulas) void completeIntegrityConstraint(ast::Formula &formula, std::vector<ast::ScopedFormula> &)
{ {
assert(formula.is<ast::Implies>()); /*assert(formula.is<ast::Implies>());
auto &implies = formula.get<ast::Implies>(); auto &implies = formula.get<ast::Implies>();
assert(implies.consequent.is<ast::Boolean>()); assert(implies.consequent.is<ast::Boolean>());
assert(implies.consequent.get<ast::Boolean>().value == false); assert(implies.consequent.get<ast::Boolean>().value == false);
@ -123,6 +126,7 @@ void completeIntegrityConstraint(const ast::Formula &formula, std::vector<ast::F
auto variables = ast::collectFreeVariables(implies.antecedent); auto variables = ast::collectFreeVariables(implies.antecedent);
// TODO: avoid deep copies // TODO: avoid deep copies
// TODO: reimplement
auto argument = ast::Formula::make<ast::Not>(ast::deepCopy(implies.antecedent)); auto argument = ast::Formula::make<ast::Not>(ast::deepCopy(implies.antecedent));
if (variables.empty()) if (variables.empty())
@ -132,20 +136,20 @@ void completeIntegrityConstraint(const ast::Formula &formula, std::vector<ast::F
} }
auto completedFormula = ast::Formula::make<ast::ForAll>(std::move(variables), std::move(argument)); auto completedFormula = ast::Formula::make<ast::ForAll>(std::move(variables), std::move(argument));
completedFormulas.emplace_back(std::move(completedFormula)); completedFormulas.emplace_back(std::move(completedFormula));*/
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
void complete(std::vector<ast::Formula> &formulas) void complete(std::vector<ast::ScopedFormula> &scopedFormulas)
{ {
// Check whether formulas are in normal form /*// Check whether formulas are in normal form
for (const auto &formula : formulas) for (const auto &scopedFormula : scopedFormulas)
{ {
if (!formula.is<ast::Implies>()) if (!scopedFormula.formula.is<ast::Implies>())
throw std::runtime_error("cannot perform completion, formula not in normal form"); throw std::runtime_error("cannot perform completion, formula not in normal form");
auto &implies = formula.get<ast::Implies>(); auto &implies = scopedFormula.formula.get<ast::Implies>();
if (!implies.consequent.is<ast::Predicate>() && !implies.consequent.is<ast::Boolean>()) if (!implies.consequent.is<ast::Predicate>() && !implies.consequent.is<ast::Boolean>())
throw std::runtime_error("cannot perform completion, only single predicates and Booleans supported as formula consequent currently"); throw std::runtime_error("cannot perform completion, only single predicates and Booleans supported as formula consequent currently");
@ -153,8 +157,8 @@ void complete(std::vector<ast::Formula> &formulas)
std::vector<const ast::Predicate *> predicates; std::vector<const ast::Predicate *> predicates;
for (const auto &formula : formulas) for (const auto &scopedFormula : scopedFormulas)
ast::collectPredicates(formula, predicates); ast::collectPredicates(scopedFormula.formula, predicates);
std::sort(predicates.begin(), predicates.end(), std::sort(predicates.begin(), predicates.end(),
[](const auto *lhs, const auto *rhs) [](const auto *lhs, const auto *rhs)
@ -167,7 +171,7 @@ void complete(std::vector<ast::Formula> &formulas)
return lhs->arity() < rhs->arity(); return lhs->arity() < rhs->arity();
}); });
std::vector<ast::Formula> completedFormulas; std::vector<ast::ScopedFormula> completedScopedFormulas;
// Complete predicates // Complete predicates
for (const auto *predicate : predicates) for (const auto *predicate : predicates)
@ -176,19 +180,20 @@ void complete(std::vector<ast::Formula> &formulas)
ast::Predicate signature(std::string(predicate->name)); ast::Predicate signature(std::string(predicate->name));
signature.arguments.reserve(predicate->arguments.size()); signature.arguments.reserve(predicate->arguments.size());
// TODO: reimplement
for (std::size_t i = 0; i < predicate->arguments.size(); i++) for (std::size_t i = 0; i < predicate->arguments.size(); i++)
{ {
auto variableName = std::string(AuxiliaryHeadVariablePrefix) + std::to_string(i + 1); auto variableName = std::string(AuxiliaryHeadVariablePrefix) + std::to_string(i + 1);
signature.arguments.emplace_back(ast::Term::make<ast::Variable>(std::move(variableName), ast::Variable::Type::Reserved)); signature.arguments.emplace_back(ast::Term::make<ast::Variable>(std::move(variableName), ast::VariableDeclaration::Type::Reserved));
} }
completePredicate(std::move(signature), formulas, completedFormulas); completePredicate(std::move(signature), scopedFormulas, completedScopedFormulas);
} }
// Complete integrity constraints // Complete integrity constraints
for (const auto &formula : formulas) for (auto &scopedFormula : scopedFormulas)
{ {
auto &implies = formula.get<ast::Implies>(); auto &implies = scopedFormula.formula.get<ast::Implies>();
if (!implies.consequent.is<ast::Boolean>()) if (!implies.consequent.is<ast::Boolean>())
continue; continue;
@ -199,10 +204,10 @@ void complete(std::vector<ast::Formula> &formulas)
if (boolean.value == true) if (boolean.value == true)
continue; continue;
completeIntegrityConstraint(formula, completedFormulas); completeIntegrityConstraint(scopedFormula.formula, completedScopedFormulas);
} }
std::swap(formulas, completedFormulas); std::swap(scopedFormulas, completedScopedFormulas);*/
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -1,5 +1,7 @@
#include <anthem/Simplification.h> #include <anthem/Simplification.h>
#include <experimental/optional>
#include <anthem/ASTVisitors.h> #include <anthem/ASTVisitors.h>
namespace anthem namespace anthem
@ -12,21 +14,19 @@ namespace anthem
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// Determines whether a term is a specific variable // Determines whether a term is a specific variable
bool matchesVariable(const ast::Term &term, const ast::Variable &variable) bool matchesVariableDeclaration(const ast::Term &term, const ast::VariableDeclaration &variableDeclaration)
{ {
if (!term.is<ast::Variable>()) if (!term.is<ast::Variable>())
return false; return false;
const auto &otherVariable = term.get<ast::Variable>(); return term.get<ast::Variable>().declaration == &variableDeclaration;
return variable.name == otherVariable.name;
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// Extracts the term t if the given formula is of the form “X = t” and X matches the given variable // Extracts the term t if the given formula is of the form “X = t” and X matches the given variable
// The input formula is not usable if a term is returned // The input formula is not usable if a term is returned
std::experimental::optional<ast::Term> extractAssignedTerm(ast::Formula &formula, const ast::Variable &variable) std::experimental::optional<ast::Term> extractAssignedTerm(ast::Formula &formula, const ast::VariableDeclaration &variableDeclaration)
{ {
if (!formula.is<ast::Comparison>()) if (!formula.is<ast::Comparison>())
return std::experimental::nullopt; return std::experimental::nullopt;
@ -36,10 +36,10 @@ std::experimental::optional<ast::Term> extractAssignedTerm(ast::Formula &formula
if (comparison.operator_ != ast::Comparison::Operator::Equal) if (comparison.operator_ != ast::Comparison::Operator::Equal)
return std::experimental::nullopt; return std::experimental::nullopt;
if (matchesVariable(comparison.left, variable)) if (matchesVariableDeclaration(comparison.left, variableDeclaration))
return std::move(comparison.right); return std::move(comparison.right);
if (matchesVariable(comparison.right, variable)) if (matchesVariableDeclaration(comparison.right, variableDeclaration))
return std::move(comparison.left); return std::move(comparison.left);
return std::experimental::nullopt; return std::experimental::nullopt;
@ -50,15 +50,16 @@ std::experimental::optional<ast::Term> extractAssignedTerm(ast::Formula &formula
// Replaces all occurrences of a variable in a given term with another term // Replaces all occurrences of a variable in a given term with another term
struct ReplaceVariableInTermVisitor : public ast::RecursiveTermVisitor<ReplaceVariableInTermVisitor> struct ReplaceVariableInTermVisitor : public ast::RecursiveTermVisitor<ReplaceVariableInTermVisitor>
{ {
static void accept(ast::Variable &variable, ast::Term &term, const ast::Variable &variableToReplace, const ast::Term &replacementTerm) static void accept(ast::Variable &, ast::Term &, const ast::VariableDeclaration &, const ast::Term &)
{ {
if (variable.name == variableToReplace.name) // TODO: reimplement
term = ast::deepCopy(replacementTerm); //if (variable.name == variableToReplace.name)
// term = ast::deepCopy(replacementTerm);
} }
// Ignore all other types of expressions // Ignore all other types of expressions
template<class T> template<class T>
static void accept(T &, ast::Term &, const ast::Variable &, const ast::Term &) static void accept(T &, ast::Term &, const ast::VariableDeclaration &, const ast::Term &)
{ {
} }
}; };
@ -68,27 +69,27 @@ struct ReplaceVariableInTermVisitor : public ast::RecursiveTermVisitor<ReplaceVa
// Replaces all occurrences of a variable in a given formula with a term // Replaces all occurrences of a variable in a given formula with a term
struct ReplaceVariableInFormulaVisitor : public ast::RecursiveFormulaVisitor<ReplaceVariableInFormulaVisitor> struct ReplaceVariableInFormulaVisitor : public ast::RecursiveFormulaVisitor<ReplaceVariableInFormulaVisitor>
{ {
static void accept(ast::Comparison &comparison, ast::Formula &, const ast::Variable &variable, const ast::Term &term) static void accept(ast::Comparison &comparison, ast::Formula &, const ast::VariableDeclaration &variableDeclaration, const ast::Term &term)
{ {
comparison.left.accept(ReplaceVariableInTermVisitor(), comparison.left, variable, term); comparison.left.accept(ReplaceVariableInTermVisitor(), comparison.left, variableDeclaration, term);
comparison.right.accept(ReplaceVariableInTermVisitor(), comparison.right, variable, term); comparison.right.accept(ReplaceVariableInTermVisitor(), comparison.right, variableDeclaration, term);
} }
static void accept(ast::In &in, ast::Formula &, const ast::Variable &variable, const ast::Term &term) static void accept(ast::In &in, ast::Formula &, const ast::VariableDeclaration &variableDeclaration, const ast::Term &term)
{ {
in.element.accept(ReplaceVariableInTermVisitor(), in.element, variable, term); in.element.accept(ReplaceVariableInTermVisitor(), in.element, variableDeclaration, term);
in.set.accept(ReplaceVariableInTermVisitor(), in.set, variable, term); in.set.accept(ReplaceVariableInTermVisitor(), in.set, variableDeclaration, term);
} }
static void accept(ast::Predicate &predicate, ast::Formula &, const ast::Variable &variable, const ast::Term &term) static void accept(ast::Predicate &predicate, ast::Formula &, const ast::VariableDeclaration &variableDeclaration, const ast::Term &term)
{ {
for (auto &argument : predicate.arguments) for (auto &argument : predicate.arguments)
argument.accept(ReplaceVariableInTermVisitor(), argument, variable, term); argument.accept(ReplaceVariableInTermVisitor(), argument, variableDeclaration, term);
} }
// Ignore all other types of expressions // Ignore all other types of expressions
template<class T> template<class T>
static void accept(T &, ast::Formula &, const ast::Variable &, const ast::Term &) static void accept(T &, ast::Formula &, const ast::VariableDeclaration &, const ast::Term &)
{ {
} }
}; };
@ -108,7 +109,7 @@ void simplify(ast::Exists &exists, ast::Formula &formula)
// Simplify formulas of type “exists X (X = t and F(X))” to “F(t)” // Simplify formulas of type “exists X (X = t and F(X))” to “F(t)”
for (auto i = exists.variables.begin(); i != exists.variables.end();) for (auto i = exists.variables.begin(); i != exists.variables.end();)
{ {
auto &variable = *i; auto &variableDeclaration = *i->get();
bool wasVariableReplaced = false; bool wasVariableReplaced = false;
@ -117,7 +118,7 @@ void simplify(ast::Exists &exists, ast::Formula &formula)
{ {
auto &argument = *j; auto &argument = *j;
// Find term that is equivalent to the given variable // Find term that is equivalent to the given variable
auto assignedTerm = extractAssignedTerm(argument, variable); auto assignedTerm = extractAssignedTerm(argument, variableDeclaration);
if (!assignedTerm) if (!assignedTerm)
continue; continue;
@ -129,7 +130,7 @@ void simplify(ast::Exists &exists, ast::Formula &formula)
continue; continue;
auto &otherArgument = *k; auto &otherArgument = *k;
otherArgument.accept(ReplaceVariableInFormulaVisitor(), otherArgument, variable, assignedTerm.value()); otherArgument.accept(ReplaceVariableInFormulaVisitor(), otherArgument, variableDeclaration, assignedTerm.value());
} }
arguments.erase(j); arguments.erase(j);

View File

@ -40,12 +40,12 @@ void translate(const char *fileName, std::istream &stream, Context &context)
auto fileContent = std::string(std::istreambuf_iterator<char>(stream), {}); auto fileContent = std::string(std::istreambuf_iterator<char>(stream), {});
std::vector<ast::Formula> formulas; std::vector<ast::ScopedFormula> scopedFormulas;
const auto translateStatement = const auto translateStatement =
[&formulas, &context](const Clingo::AST::Statement &statement) [&scopedFormulas, &context](const Clingo::AST::Statement &statement)
{ {
statement.data.accept(StatementVisitor(), statement, formulas, context); statement.data.accept(StatementVisitor(), statement, scopedFormulas, context);
}; };
const auto logger = const auto logger =
@ -57,14 +57,19 @@ void translate(const char *fileName, std::istream &stream, Context &context)
Clingo::parse_program(fileContent.c_str(), translateStatement, logger); Clingo::parse_program(fileContent.c_str(), translateStatement, logger);
if (context.simplify) if (context.simplify)
for (auto &formula : formulas) for (auto &scopedFormula : scopedFormulas)
simplify(formula); simplify(scopedFormula.formula);
if (context.complete) if (context.complete)
complete(formulas); complete(scopedFormulas);
for (const auto &formula : formulas) ast::PrintContext printContext;
context.logger.outputStream() << formula << std::endl;
for (const auto &scopedFormula : scopedFormulas)
{
ast::print(context.logger.outputStream(), scopedFormula.formula, printContext);
context.logger.outputStream() << std::endl;
}
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -2,12 +2,13 @@
#include <sstream> #include <sstream>
#include <anthem/AST.h>
#include <anthem/Context.h> #include <anthem/Context.h>
#include <anthem/Translation.h> #include <anthem/Translation.h>
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
TEST_CASE("[completion] Rules are completed", "[completion]") /*TEST_CASE("[completion] Rules are completed", "[completion]")
{ {
std::stringstream input; std::stringstream input;
std::stringstream output; std::stringstream output;
@ -147,3 +148,4 @@ TEST_CASE("[completion] Rules are completed", "[completion]")
// TODO: test collecting free variables // TODO: test collecting free variables
} }
*/

View File

@ -2,12 +2,13 @@
#include <sstream> #include <sstream>
#include <anthem/AST.h>
#include <anthem/Context.h> #include <anthem/Context.h>
#include <anthem/Translation.h> #include <anthem/Translation.h>
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
TEST_CASE("[simplification] Rules are simplified correctly", "[simplification]") /*TEST_CASE("[simplification] Rules are simplified correctly", "[simplification]")
{ {
std::stringstream input; std::stringstream input;
std::stringstream output; std::stringstream output;
@ -50,3 +51,4 @@ TEST_CASE("[simplification] Rules are simplified correctly", "[simplification]")
CHECK(output.str() == "(M > N -> #false)\n"); CHECK(output.str() == "(M > N -> #false)\n");
} }
} }
*/

View File

@ -2,6 +2,7 @@
#include <sstream> #include <sstream>
#include <anthem/AST.h>
#include <anthem/Context.h> #include <anthem/Context.h>
#include <anthem/Translation.h> #include <anthem/Translation.h>
@ -14,7 +15,7 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
std::stringstream errors; std::stringstream errors;
anthem::output::Logger logger(output, errors); anthem::output::Logger logger(output, errors);
anthem::Context context = {logger, {}}; anthem::Context context(std::move(logger));
context.simplify = false; context.simplify = false;
context.complete = false; context.complete = false;
@ -31,7 +32,7 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
input << "p(N) :- N = 1..5."; input << "p(N) :- N = 1..5.";
anthem::translate("input", input, context); anthem::translate("input", input, context);
CHECK(output.str() == "((V1 in N and exists X1, X2 (X1 in N and X2 in 1..5 and X1 = X2)) -> p(V1))\n"); CHECK(output.str() == "((V1 in U1 and exists X1, X2 (X1 in U1 and X2 in 1..5 and X1 = X2)) -> p(V1))\n");
} }
SECTION("simple example 3") SECTION("simple example 3")
@ -39,7 +40,7 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
input << "p(N + 1) :- q(N)."; input << "p(N + 1) :- q(N).";
anthem::translate("input", input, context); anthem::translate("input", input, context);
CHECK(output.str() == "((V1 in (N + 1) and exists X1 (X1 in N and q(X1))) -> p(V1))\n"); CHECK(output.str() == "((V1 in (U1 + 1) and exists X1 (X1 in U1 and q(X1))) -> p(V1))\n");
} }
SECTION("n-ary head") SECTION("n-ary head")
@ -47,7 +48,7 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
input << "p(N, 1, 2) :- N = 1..5."; input << "p(N, 1, 2) :- N = 1..5.";
anthem::translate("input", input, context); anthem::translate("input", input, context);
CHECK(output.str() == "((V1 in N and V2 in 1 and V3 in 2 and exists X1, X2 (X1 in N and X2 in 1..5 and X1 = X2)) -> p(V1, V2, V3))\n"); CHECK(output.str() == "((V1 in U1 and V2 in 1 and V3 in 2 and exists X1, X2 (X1 in U1 and X2 in 1..5 and X1 = X2)) -> p(V1, V2, V3))\n");
} }
SECTION("disjunctive head") SECTION("disjunctive head")
@ -56,7 +57,7 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
input << "q(3, N); p(N, 1, 2) :- N = 1..5."; input << "q(3, N); p(N, 1, 2) :- N = 1..5.";
anthem::translate("input", input, context); anthem::translate("input", input, context);
CHECK(output.str() == "((V1 in N and V2 in 1 and V3 in 2 and V4 in 3 and V5 in N and exists X1, X2 (X1 in N and X2 in 1..5 and X1 = X2)) -> (p(V1, V2, V3) or q(V4, V5)))\n"); CHECK(output.str() == "((V1 in U1 and V2 in 1 and V3 in 2 and V4 in 3 and V5 in U1 and exists X1, X2 (X1 in U1 and X2 in 1..5 and X1 = X2)) -> (p(V1, V2, V3) or q(V4, V5)))\n");
} }
SECTION("disjunctive head (alternative syntax)") SECTION("disjunctive head (alternative syntax)")
@ -65,7 +66,7 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
input << "q(3, N), p(N, 1, 2) :- N = 1..5."; input << "q(3, N), p(N, 1, 2) :- N = 1..5.";
anthem::translate("input", input, context); anthem::translate("input", input, context);
CHECK(output.str() == "((V1 in N and V2 in 1 and V3 in 2 and V4 in 3 and V5 in N and exists X1, X2 (X1 in N and X2 in 1..5 and X1 = X2)) -> (p(V1, V2, V3) or q(V4, V5)))\n"); CHECK(output.str() == "((V1 in U1 and V2 in 1 and V3 in 2 and V4 in 3 and V5 in U1 and exists X1, X2 (X1 in U1 and X2 in 1..5 and X1 = X2)) -> (p(V1, V2, V3) or q(V4, V5)))\n");
} }
SECTION("escaping conflicting variable names") SECTION("escaping conflicting variable names")
@ -73,7 +74,7 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
input << "p(X1, V1, A1) :- q(X1), q(V1), q(A1)."; input << "p(X1, V1, A1) :- q(X1), q(V1), q(A1).";
anthem::translate("input", input, context); anthem::translate("input", input, context);
CHECK(output.str() == "((V1 in _X1 and V2 in _V1 and V3 in _A1 and exists X1 (X1 in _X1 and q(X1)) and exists X2 (X2 in _V1 and q(X2)) and exists X3 (X3 in _A1 and q(X3))) -> p(V1, V2, V3))\n"); CHECK(output.str() == "((V1 in U1 and V2 in U2 and V3 in U3 and exists X1 (X1 in U1 and q(X1)) and exists X2 (X2 in U2 and q(X2)) and exists X3 (X3 in U3 and q(X3))) -> p(V1, V2, V3))\n");
} }
SECTION("fact") SECTION("fact")
@ -97,7 +98,7 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
input << ":- not p(I), I = 1..n."; input << ":- not p(I), I = 1..n.";
anthem::translate("input", input, context); anthem::translate("input", input, context);
CHECK(output.str() == "((exists X1 (X1 in I and not p(X1)) and exists X2, X3 (X2 in I and X3 in 1..n and X2 = X3)) -> #false)\n"); CHECK(output.str() == "((exists X1 (X1 in U1 and not p(X1)) and exists X2, X3 (X2 in U1 and X3 in 1..n and X2 = X3)) -> #false)\n");
} }
SECTION("disjunctive fact (no arguments)") SECTION("disjunctive fact (no arguments)")
@ -145,7 +146,7 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
input << "p(X, #inf) :- q(X, #sup)."; input << "p(X, #inf) :- q(X, #sup).";
anthem::translate("input", input, context); anthem::translate("input", input, context);
CHECK(output.str() == "((V1 in X and V2 in #inf and exists X1, X2 (X1 in X and X2 in #sup and q(X1, X2))) -> p(V1, V2))\n"); CHECK(output.str() == "((V1 in U1 and V2 in #inf and exists X1, X2 (X1 in U1 and X2 in #sup and q(X1, X2))) -> p(V1, V2))\n");
} }
SECTION("strings") SECTION("strings")
@ -153,7 +154,7 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
input << "p(X, \"foo\") :- q(X, \"bar\")."; input << "p(X, \"foo\") :- q(X, \"bar\").";
anthem::translate("input", input, context); anthem::translate("input", input, context);
CHECK(output.str() == "((V1 in X and V2 in \"foo\" and exists X1, X2 (X1 in X and X2 in \"bar\" and q(X1, X2))) -> p(V1, V2))\n"); CHECK(output.str() == "((V1 in U1 and V2 in \"foo\" and exists X1, X2 (X1 in U1 and X2 in \"bar\" and q(X1, X2))) -> p(V1, V2))\n");
} }
SECTION("tuples") SECTION("tuples")
@ -161,7 +162,7 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
input << "p(X, (1, 2, 3)) :- q(X, (4, 5))."; input << "p(X, (1, 2, 3)) :- q(X, (4, 5)).";
anthem::translate("input", input, context); anthem::translate("input", input, context);
CHECK(output.str() == "((V1 in X and V2 in (1, 2, 3) and exists X1, X2 (X1 in X and X2 in (4, 5) and q(X1, X2))) -> p(V1, V2))\n"); CHECK(output.str() == "((V1 in U1 and V2 in (1, 2, 3) and exists X1, X2 (X1 in U1 and X2 in (4, 5) and q(X1, X2))) -> p(V1, V2))\n");
} }
SECTION("1-ary tuples") SECTION("1-ary tuples")
@ -169,7 +170,7 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
input << "p(X, (1,)) :- q(X, (2,))."; input << "p(X, (1,)) :- q(X, (2,)).";
anthem::translate("input", input, context); anthem::translate("input", input, context);
CHECK(output.str() == "((V1 in X and V2 in (1,) and exists X1, X2 (X1 in X and X2 in (2,) and q(X1, X2))) -> p(V1, V2))\n"); CHECK(output.str() == "((V1 in U1 and V2 in (1,) and exists X1, X2 (X1 in U1 and X2 in (2,) and q(X1, X2))) -> p(V1, V2))\n");
} }
SECTION("intervals") SECTION("intervals")
@ -177,7 +178,7 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
input << "p(X, 1..10) :- q(X, 6..12)."; input << "p(X, 1..10) :- q(X, 6..12).";
anthem::translate("input", input, context); anthem::translate("input", input, context);
CHECK(output.str() == "((V1 in X and V2 in 1..10 and exists X1, X2 (X1 in X and X2 in 6..12 and q(X1, X2))) -> p(V1, V2))\n"); CHECK(output.str() == "((V1 in U1 and V2 in 1..10 and exists X1, X2 (X1 in U1 and X2 in 6..12 and q(X1, X2))) -> p(V1, V2))\n");
} }
SECTION("comparisons") SECTION("comparisons")
@ -185,7 +186,7 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
input << "p(M, N, O, P) :- M < N, P != O."; input << "p(M, N, O, P) :- M < N, P != O.";
anthem::translate("input", input, context); anthem::translate("input", input, context);
CHECK(output.str() == "((V1 in M and V2 in N and V3 in O and V4 in P and exists X1, X2 (X1 in M and X2 in N and X1 < X2) and exists X3, X4 (X3 in P and X4 in O and X3 != X4)) -> p(V1, V2, V3, V4))\n"); CHECK(output.str() == "((V1 in U1 and V2 in U2 and V3 in U3 and V4 in U4 and exists X1, X2 (X1 in U1 and X2 in U2 and X1 < X2) and exists X3, X4 (X3 in U4 and X4 in U3 and X3 != X4)) -> p(V1, V2, V3, V4))\n");
} }
SECTION("single negation with 0-ary predicates") SECTION("single negation with 0-ary predicates")
@ -201,7 +202,7 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
input << "not p(X, 1) :- not q(X, 2)."; input << "not p(X, 1) :- not q(X, 2).";
anthem::translate("input", input, context); anthem::translate("input", input, context);
CHECK(output.str() == "((V1 in X and V2 in 1 and exists X1, X2 (X1 in X and X2 in 2 and not q(X1, X2))) -> not p(V1, V2))\n"); CHECK(output.str() == "((V1 in U1 and V2 in 1 and exists X1, X2 (X1 in U1 and X2 in 2 and not q(X1, X2))) -> not p(V1, V2))\n");
} }
SECTION("variable numbering") SECTION("variable numbering")
@ -210,8 +211,8 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
input << "f; q(A1, A2); p(A3, r(A4)); g(g(A5)) :- g(A3), f, q(A4, A1), p(A2, A5)."; input << "f; q(A1, A2); p(A3, r(A4)); g(g(A5)) :- g(A3), f, q(A4, A1), p(A2, A5).";
anthem::translate("input", input, context); anthem::translate("input", input, context);
CHECK(output.str() == "((V1 in _A1 and V2 in _A2 and V3 in _A3 and V4 in r(_A4) and V5 in g(_A5)" CHECK(output.str() == "((V1 in U1 and V2 in U2 and V3 in U3 and V4 in r(U4) and V5 in g(U5)"
" and exists X1 (X1 in _A3 and g(X1)) and f and exists X2, X3 (X2 in _A4 and X3 in _A1 and q(X2, X3)) and exists X4, X5 (X4 in _A2 and X5 in _A5 and p(X4, X5)))" " and exists X1 (X1 in U3 and g(X1)) and f and exists X2, X3 (X2 in U4 and X3 in U1 and q(X2, X3)) and exists X4, X5 (X4 in U2 and X5 in U5 and p(X4, X5)))"
" -> (q(V1, V2) or p(V3, V4) or g(V5) or f))\n"); " -> (q(V1, V2) or p(V3, V4) or g(V5) or f))\n");
} }
@ -220,7 +221,7 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
input << "p(q(s(t(X1))), u(X2)) :- u(v(w(X2)), z(X1))."; input << "p(q(s(t(X1))), u(X2)) :- u(v(w(X2)), z(X1)).";
anthem::translate("input", input, context); anthem::translate("input", input, context);
CHECK(output.str() == "((V1 in q(s(t(_X1))) and V2 in u(_X2) and exists X1, X2 (X1 in v(w(_X2)) and X2 in z(_X1) and u(X1, X2))) -> p(V1, V2))\n"); CHECK(output.str() == "((V1 in q(s(t(U1))) and V2 in u(U2) and exists X1, X2 (X1 in v(w(U2)) and X2 in z(U1) and u(X1, X2))) -> p(V1, V2))\n");
} }
SECTION("choice rule (simple)") SECTION("choice rule (simple)")
@ -244,7 +245,8 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
input << "{p(1..3, N); q(2..4)}."; input << "{p(1..3, N); q(2..4)}.";
anthem::translate("input", input, context); anthem::translate("input", input, context);
CHECK(output.str() == "((V1 in 1..3 and V2 in N and V3 in 2..4 and p(V1, V2)) -> p(V1, V2))\n((V1 in 1..3 and V2 in N and V3 in 2..4 and q(V3)) -> q(V3))\n"); // TODO: eliminate V5: not needed
CHECK(output.str() == "((V1 in 1..3 and V2 in U1 and V3 in 2..4 and p(V1, V2)) -> p(V1, V2))\n((V4 in 1..3 and V5 in U2 and V6 in 2..4 and q(V6)) -> q(V6))\n");
} }
SECTION("choice rule with body") SECTION("choice rule with body")
@ -252,7 +254,7 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
input << "{p(M, N); q(P)} :- s(M, N, P)."; input << "{p(M, N); q(P)} :- s(M, N, P).";
anthem::translate("input", input, context); anthem::translate("input", input, context);
CHECK(output.str() == "((V1 in M and V2 in N and V3 in P and exists X1, X2, X3 (X1 in M and X2 in N and X3 in P and s(X1, X2, X3)) and p(V1, V2)) -> p(V1, V2))\n((V1 in M and V2 in N and V3 in P and exists X1, X2, X3 (X1 in M and X2 in N and X3 in P and s(X1, X2, X3)) and q(V3)) -> q(V3))\n"); CHECK(output.str() == "((V1 in U1 and V2 in U2 and V3 in U3 and exists X1, X2, X3 (X1 in U1 and X2 in U2 and X3 in U3 and s(X1, X2, X3)) and p(V1, V2)) -> p(V1, V2))\n((V4 in U4 and V5 in U5 and V6 in U6 and exists X4, X5, X6 (X4 in U4 and X5 in U5 and X6 in U6 and s(X4, X5, X6)) and q(V6)) -> q(V6))\n");
} }
SECTION("choice rule with negation") SECTION("choice rule with negation")
@ -260,7 +262,7 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
input << "{not p(X, 1)} :- not q(X, 2)."; input << "{not p(X, 1)} :- not q(X, 2).";
anthem::translate("input", input, context); anthem::translate("input", input, context);
CHECK(output.str() == "((V1 in X and V2 in 1 and exists X1, X2 (X1 in X and X2 in 2 and not q(X1, X2)) and not p(V1, V2)) -> not p(V1, V2))\n"); CHECK(output.str() == "((V1 in U1 and V2 in 1 and exists X1, X2 (X1 in U1 and X2 in 2 and not q(X1, X2)) and not p(V1, V2)) -> not p(V1, V2))\n");
} }
SECTION("choice rule with negation (two elements)") SECTION("choice rule with negation (two elements)")
@ -268,7 +270,7 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
input << "{not p(X, 1); not s} :- not q(X, 2)."; input << "{not p(X, 1); not s} :- not q(X, 2).";
anthem::translate("input", input, context); anthem::translate("input", input, context);
CHECK(output.str() == "((V1 in X and V2 in 1 and exists X1, X2 (X1 in X and X2 in 2 and not q(X1, X2)) and not p(V1, V2)) -> not p(V1, V2))\n((V1 in X and V2 in 1 and exists X1, X2 (X1 in X and X2 in 2 and not q(X1, X2)) and not s) -> not s)\n"); CHECK(output.str() == "((V1 in U1 and V2 in 1 and exists X1, X2 (X1 in U1 and X2 in 2 and not q(X1, X2)) and not p(V1, V2)) -> not p(V1, V2))\n((V3 in U2 and V4 in 1 and exists X3, X4 (X3 in U2 and X4 in 2 and not q(X3, X4)) and not s) -> not s)\n");
} }
SECTION("anonymous variables") SECTION("anonymous variables")
@ -276,6 +278,6 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
input << "p(_, _) :- q(_, _)."; input << "p(_, _) :- q(_, _).";
anthem::translate("input", input, context); anthem::translate("input", input, context);
CHECK(output.str() == "((V1 in A1 and V2 in A2 and exists X1, X2 (X1 in A3 and X2 in A4 and q(X1, X2))) -> p(V1, V2))\n"); CHECK(output.str() == "((V1 in U1 and V2 in U2 and exists X1, X2 (X1 in U3 and X2 in U4 and q(X1, X2))) -> p(V1, V2))\n");
} }
} }