Support modulus operation (absolute value)
This adds support for computing the absolute value of a term along with an according unit test.
This commit is contained in:
parent
0608748349
commit
8c250f5c59
@ -5,7 +5,7 @@
|
|||||||
### Features
|
### Features
|
||||||
|
|
||||||
* more and advanced simplification rules
|
* more and advanced simplification rules
|
||||||
* adds support for exponentiation operator
|
* adds support for exponentiation (power) and modulus (absolute value)
|
||||||
* new examples: prime numbers, permutation generator, and graph coloring (extended)
|
* new examples: prime numbers, permutation generator, and graph coloring (extended)
|
||||||
|
|
||||||
## 0.1.7 (2018-04-08)
|
## 0.1.7 (2018-04-08)
|
||||||
|
@ -293,6 +293,30 @@ struct String
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
struct UnaryOperation
|
||||||
|
{
|
||||||
|
enum class Operator
|
||||||
|
{
|
||||||
|
Absolute
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit UnaryOperation(Operator operator_, Term &&argument)
|
||||||
|
: operator_{operator_},
|
||||||
|
argument{std::move(argument)}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
UnaryOperation(const UnaryOperation &other) = delete;
|
||||||
|
UnaryOperation &operator=(const UnaryOperation &other) = delete;
|
||||||
|
UnaryOperation(UnaryOperation &&other) noexcept = default;
|
||||||
|
UnaryOperation &operator=(UnaryOperation &&other) noexcept = default;
|
||||||
|
|
||||||
|
Operator operator_;
|
||||||
|
Term argument;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
struct Variable
|
struct Variable
|
||||||
{
|
{
|
||||||
explicit Variable(VariableDeclaration *declaration)
|
explicit Variable(VariableDeclaration *declaration)
|
||||||
|
@ -37,6 +37,7 @@ struct Or;
|
|||||||
struct Predicate;
|
struct Predicate;
|
||||||
struct SpecialInteger;
|
struct SpecialInteger;
|
||||||
struct String;
|
struct String;
|
||||||
|
struct UnaryOperation;
|
||||||
struct Variable;
|
struct Variable;
|
||||||
struct VariableDeclaration;
|
struct VariableDeclaration;
|
||||||
using VariableDeclarationPointer = std::unique_ptr<VariableDeclaration>;
|
using VariableDeclarationPointer = std::unique_ptr<VariableDeclaration>;
|
||||||
@ -68,6 +69,7 @@ using Term = Clingo::Variant<
|
|||||||
Interval,
|
Interval,
|
||||||
SpecialInteger,
|
SpecialInteger,
|
||||||
String,
|
String,
|
||||||
|
UnaryOperation,
|
||||||
Variable>;
|
Variable>;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -165,6 +165,14 @@ struct RecursiveTermVisitor
|
|||||||
return T::accept(string, term, std::forward<Arguments>(arguments)...);
|
return T::accept(string, term, std::forward<Arguments>(arguments)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class... Arguments>
|
||||||
|
ReturnType visit(UnaryOperation &unaryOperation, Term &term, Arguments &&... arguments)
|
||||||
|
{
|
||||||
|
unaryOperation.argument.accept(*this, unaryOperation.argument, std::forward<Arguments>(arguments)...);
|
||||||
|
|
||||||
|
return T::accept(unaryOperation, term, std::forward<Arguments>(arguments)...);
|
||||||
|
}
|
||||||
|
|
||||||
template <class... Arguments>
|
template <class... Arguments>
|
||||||
ReturnType visit(Variable &variable, Term &term, Arguments &&... arguments)
|
ReturnType visit(Variable &variable, Term &term, Arguments &&... arguments)
|
||||||
{
|
{
|
||||||
|
@ -382,6 +382,19 @@ struct TermEqualityVisitor
|
|||||||
: Tristate::False;
|
: Tristate::False;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Tristate visit(const UnaryOperation &unaryOperation, const Term &otherTerm)
|
||||||
|
{
|
||||||
|
if (!otherTerm.is<UnaryOperation>())
|
||||||
|
return Tristate::Unknown;
|
||||||
|
|
||||||
|
const auto &otherUnaryOperation = otherTerm.get<UnaryOperation>();
|
||||||
|
|
||||||
|
if (unaryOperation.operator_ != otherUnaryOperation.operator_)
|
||||||
|
return Tristate::Unknown;
|
||||||
|
|
||||||
|
return equal(unaryOperation.argument, otherUnaryOperation.argument);
|
||||||
|
}
|
||||||
|
|
||||||
Tristate visit(const Variable &variable, const Term &otherTerm)
|
Tristate visit(const Variable &variable, const Term &otherTerm)
|
||||||
{
|
{
|
||||||
if (!otherTerm.is<Variable>())
|
if (!otherTerm.is<Variable>())
|
||||||
|
@ -48,6 +48,23 @@ ast::BinaryOperation::Operator translate(Clingo::AST::BinaryOperator binaryOpera
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
ast::UnaryOperation::Operator translate(Clingo::AST::UnaryOperator unaryOperator, const Clingo::AST::Term &term)
|
||||||
|
{
|
||||||
|
switch (unaryOperator)
|
||||||
|
{
|
||||||
|
case Clingo::AST::UnaryOperator::Absolute:
|
||||||
|
return ast::UnaryOperation::Operator::Absolute;
|
||||||
|
case Clingo::AST::UnaryOperator::Minus:
|
||||||
|
throw TranslationException(term.location, "binary operation “minus” currently unsupported");
|
||||||
|
case Clingo::AST::UnaryOperator::Negation:
|
||||||
|
throw TranslationException(term.location, "binary operation “negation” currently unsupported");
|
||||||
|
}
|
||||||
|
|
||||||
|
throw TranslationException(term.location, "unknown unary operation");
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
ast::Term translate(const Clingo::AST::Term &term, RuleContext &ruleContext, const ast::VariableStack &variableStack);
|
ast::Term translate(const Clingo::AST::Term &term, RuleContext &ruleContext, const ast::VariableStack &variableStack);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -106,12 +123,6 @@ struct TermTranslateVisitor
|
|||||||
return ast::Term::make<ast::Variable>(ruleContext.freeVariables.back().get());
|
return ast::Term::make<ast::Variable>(ruleContext.freeVariables.back().get());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<ast::Term> visit(const Clingo::AST::UnaryOperation &, const Clingo::AST::Term &term, RuleContext &, const ast::VariableStack &)
|
|
||||||
{
|
|
||||||
throw TranslationException(term.location, "“unary operation” terms currently unsupported");
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<ast::Term> visit(const Clingo::AST::BinaryOperation &binaryOperation, const Clingo::AST::Term &term, RuleContext &ruleContext, const ast::VariableStack &variableStack)
|
std::optional<ast::Term> visit(const Clingo::AST::BinaryOperation &binaryOperation, const Clingo::AST::Term &term, RuleContext &ruleContext, const ast::VariableStack &variableStack)
|
||||||
{
|
{
|
||||||
const auto operator_ = translate(binaryOperation.binary_operator, term);
|
const auto operator_ = translate(binaryOperation.binary_operator, term);
|
||||||
@ -121,6 +132,14 @@ struct TermTranslateVisitor
|
|||||||
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::optional<ast::Term> visit(const Clingo::AST::UnaryOperation &unaryOperation, const Clingo::AST::Term &term, RuleContext &ruleContext, const ast::VariableStack &variableStack)
|
||||||
|
{
|
||||||
|
const auto operator_ = translate(unaryOperation.unary_operator, term);
|
||||||
|
auto argument = translate(unaryOperation.argument, ruleContext, variableStack);
|
||||||
|
|
||||||
|
return ast::Term::make<ast::UnaryOperation>(operator_, std::move(argument));
|
||||||
|
}
|
||||||
|
|
||||||
std::optional<ast::Term> visit(const Clingo::AST::Interval &interval, const Clingo::AST::Term &, RuleContext &ruleContext, const ast::VariableStack &variableStack)
|
std::optional<ast::Term> visit(const Clingo::AST::Interval &interval, const Clingo::AST::Term &, RuleContext &ruleContext, const ast::VariableStack &variableStack)
|
||||||
{
|
{
|
||||||
auto left = translate(interval.left, ruleContext, variableStack);
|
auto left = translate(interval.left, ruleContext, variableStack);
|
||||||
|
@ -53,6 +53,7 @@ output::ColorStream &print(output::ColorStream &stream, const Interval &interval
|
|||||||
output::ColorStream &print(output::ColorStream &stream, const Predicate &predicate, 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 SpecialInteger &specialInteger, PrintContext &printContext);
|
||||||
output::ColorStream &print(output::ColorStream &stream, const String &string, PrintContext &printContext);
|
output::ColorStream &print(output::ColorStream &stream, const String &string, PrintContext &printContext);
|
||||||
|
output::ColorStream &print(output::ColorStream &stream, const UnaryOperation &unaryOperation, PrintContext &printContext);
|
||||||
output::ColorStream &print(output::ColorStream &stream, const Variable &variable, 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 VariableDeclaration &variableDeclaration, PrintContext &printContext);
|
||||||
|
|
||||||
@ -282,6 +283,29 @@ inline output::ColorStream &print(output::ColorStream &stream, const String &str
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
inline output::ColorStream &print(output::ColorStream &stream, const UnaryOperation &unaryOperation, PrintContext &printContext)
|
||||||
|
{
|
||||||
|
switch (unaryOperation.operator_)
|
||||||
|
{
|
||||||
|
case UnaryOperation::Operator::Absolute:
|
||||||
|
stream << "|";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
print(stream, unaryOperation.argument, printContext);
|
||||||
|
|
||||||
|
switch (unaryOperation.operator_)
|
||||||
|
{
|
||||||
|
case UnaryOperation::Operator::Absolute:
|
||||||
|
stream << "|";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
inline output::ColorStream &print(output::ColorStream &stream, const Variable &variable, PrintContext &printContext)
|
inline output::ColorStream &print(output::ColorStream &stream, const Variable &variable, PrintContext &printContext)
|
||||||
{
|
{
|
||||||
assert(variable.declaration != nullptr);
|
assert(variable.declaration != nullptr);
|
||||||
|
@ -159,6 +159,13 @@ String prepareCopy(const String &other)
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
UnaryOperation prepareCopy(const UnaryOperation &other)
|
||||||
|
{
|
||||||
|
return UnaryOperation(other.operator_, prepareCopy(other.argument));
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
Variable prepareCopy(const Variable &other)
|
Variable prepareCopy(const Variable &other)
|
||||||
{
|
{
|
||||||
return Variable(other.declaration);
|
return Variable(other.declaration);
|
||||||
@ -320,6 +327,12 @@ struct FixDanglingVariablesInTermVisitor
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class... Arguments>
|
||||||
|
void visit(UnaryOperation &unaryOperation, Arguments &&... arguments)
|
||||||
|
{
|
||||||
|
unaryOperation.argument.accept(*this, std::forward<Arguments>(arguments)...);
|
||||||
|
}
|
||||||
|
|
||||||
void visit(Variable &variable, ScopedFormula &scopedFormula, VariableStack &variableStack,
|
void visit(Variable &variable, ScopedFormula &scopedFormula, VariableStack &variableStack,
|
||||||
std::map<VariableDeclaration *, VariableDeclaration *> &replacements)
|
std::map<VariableDeclaration *, VariableDeclaration *> &replacements)
|
||||||
{
|
{
|
||||||
|
@ -178,6 +178,11 @@ struct CollectFreeVariablesVisitor
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void visit(UnaryOperation &unaryOperation, VariableStack &variableStack, std::vector<VariableDeclaration *> &freeVariables)
|
||||||
|
{
|
||||||
|
unaryOperation.argument.accept(*this, variableStack, freeVariables);
|
||||||
|
}
|
||||||
|
|
||||||
void visit(Variable &variable, VariableStack &variableStack, std::vector<VariableDeclaration *> &freeVariables)
|
void visit(Variable &variable, VariableStack &variableStack, std::vector<VariableDeclaration *> &freeVariables)
|
||||||
{
|
{
|
||||||
if (variableStack.contains(*variable.declaration))
|
if (variableStack.contains(*variable.declaration))
|
||||||
|
@ -184,4 +184,12 @@ TEST_CASE("[completion] Rules are completed", "[completion]")
|
|||||||
|
|
||||||
CHECK(output.str() == "forall V1, V2 not color(V1, V2)\nforall U1, U2, U3 (not color(U1, U2) or not color(U1, U3) or U2 = U3)\n");
|
CHECK(output.str() == "forall V1, V2 not color(V1, V2)\nforall U1, U2, U3 (not color(U1, U2) or not color(U1, U3) or U2 = U3)\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SECTION("absolute value operation")
|
||||||
|
{
|
||||||
|
input << "adj(X, Y) :- X = 1..n, Y = 1..n, |X - Y| = 1.";
|
||||||
|
anthem::translate("input", input, context);
|
||||||
|
|
||||||
|
CHECK(output.str() == "forall V1, V2 (adj(V1, V2) <-> (V1 in 1..n and V2 in 1..n and |(V1 - V2)| = 1))\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user