Fix precedence of interval operator

The interval operator has a lower precedence than, for example, binary
operations. This was unexpected and incorrectly implemented in the
output functions. For now, this is fixed by enclosing intervals in
parentheses to avoid misinterpretations.

The existing unit tests are adjusted to the updated output format.
This commit is contained in:
Patrick Lühne 2018-05-04 15:30:44 +02:00
parent fa3ed31eca
commit 0ce4e54d1a
Signed by: patrick
GPG Key ID: 05F3611E97A70ABF
6 changed files with 26 additions and 26 deletions

View File

@ -219,16 +219,16 @@ inline output::ColorStream &print(output::ColorStream &stream, const Integer &in
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
inline output::ColorStream &print(output::ColorStream &stream, const Interval &interval, PrintContext &printContext, bool) inline output::ColorStream &print(output::ColorStream &stream, const Interval &interval, PrintContext &printContext, bool omitParentheses)
{ {
if (printContext.context.parenthesisStyle == ParenthesisStyle::Full) if (!omitParentheses || printContext.context.parenthesisStyle == ParenthesisStyle::Full)
stream << "("; stream << "(";
print(stream, interval.from, printContext); print(stream, interval.from, printContext);
stream << ".."; stream << "..";
print(stream, interval.to, printContext); print(stream, interval.to, printContext);
if (printContext.context.parenthesisStyle == ParenthesisStyle::Full) if (!omitParentheses || printContext.context.parenthesisStyle == ParenthesisStyle::Full)
stream << ")"; stream << ")";
return stream; return stream;

View File

@ -123,7 +123,7 @@ TEST_CASE("[completion] Rules are completed", "[completion]")
anthem::translate("input", input, context); anthem::translate("input", input, context);
CHECK(output.str() == CHECK(output.str() ==
"forall V1 (f(V1) <-> (exists U1 (V1 = f(f(f(f(U1)))) and f(U1)) or V1 in 1..5))\n"); "forall V1 (f(V1) <-> (exists U1 (V1 = f(f(f(f(U1)))) and f(U1)) or V1 in (1..5)))\n");
} }
SECTION("useless implications") SECTION("useless implications")
@ -152,8 +152,8 @@ TEST_CASE("[completion] Rules are completed", "[completion]")
CHECK(output.str() == CHECK(output.str() ==
"forall V1 (covered(V1) <-> exists U1 in(V1, U1))\n" "forall V1 (covered(V1) <-> exists U1 in(V1, U1))\n"
"forall V2, V3 (in(V2, V3) -> (V2 in 1..n and V3 in 1..r))\n" "forall V2, V3 (in(V2, V3) -> (V2 in (1..n) and V3 in (1..r)))\n"
"forall U2 (U2 in 1..n -> covered(U2))\n" "forall U2 (U2 in (1..n) -> covered(U2))\n"
"forall U3, U4, U5 (not in(U3, U4) or not in(U5, U4) or not exists X1 (X1 in (U3 + U5) and in(X1, U4)))\n"); "forall U3, U4, U5 (not in(U3, U4) or not in(U5, U4) or not exists X1 (X1 in (U3 + U5) and in(X1, U4)))\n");
} }
@ -190,6 +190,6 @@ TEST_CASE("[completion] Rules are completed", "[completion]")
input << "adj(X, Y) :- X = 1..n, Y = 1..n, |X - Y| = 1."; input << "adj(X, Y) :- X = 1..n, Y = 1..n, |X - Y| = 1.";
anthem::translate("input", input, context); 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"); CHECK(output.str() == "forall V1, V2 (adj(V1, V2) <-> (V1 in (1..n) and V2 in (1..n) and |V1 - V2| = 1))\n");
} }
} }

View File

@ -150,7 +150,7 @@ TEST_CASE("[hidden predicate elimination] Hidden predicates are correctly elimin
// TODO: simplify further // TODO: simplify further
CHECK(output.str() == CHECK(output.str() ==
"forall V1 (a(V1) <-> exists U1 (c(V1) = c(U1) and U1 in 1..4))\n"); "forall V1 (a(V1) <-> exists U1 (c(V1) = c(U1) and U1 in (1..4)))\n");
} }
SECTION("simple propositions are hidden correctly") SECTION("simple propositions are hidden correctly")

View File

@ -26,7 +26,7 @@ TEST_CASE("[integer detection] Integer variables are correctly detected", "[inte
anthem::translate("input", input, context); anthem::translate("input", input, context);
CHECK(output.str() == CHECK(output.str() ==
"forall N1 (p(N1) <-> N1 in 1..5)\n" "forall N1 (p(N1) <-> N1 in (1..5))\n"
"int(p/1@1)\n"); "int(p/1@1)\n");
} }
@ -38,7 +38,7 @@ TEST_CASE("[integer detection] Integer variables are correctly detected", "[inte
anthem::translate("input", input, context); anthem::translate("input", input, context);
CHECK(output.str() == CHECK(output.str() ==
"forall V1 (p(V1) <-> (V1 in 1..5 or V1 = error))\n"); "forall V1 (p(V1) <-> (V1 in (1..5) or V1 = error))\n");
} }
SECTION("integer parameter with arithmetics") SECTION("integer parameter with arithmetics")
@ -47,7 +47,7 @@ TEST_CASE("[integer detection] Integer variables are correctly detected", "[inte
anthem::translate("input", input, context); anthem::translate("input", input, context);
CHECK(output.str() == CHECK(output.str() ==
"forall N1 (p(N1) <-> N1 in ((2 + 1..5) * 2))\n" "forall N1 (p(N1) <-> N1 in ((2 + (1..5)) * 2))\n"
"int(p/1@1)\n"); "int(p/1@1)\n");
} }
@ -59,7 +59,7 @@ TEST_CASE("[integer detection] Integer variables are correctly detected", "[inte
anthem::translate("input", input, context); anthem::translate("input", input, context);
CHECK(output.str() == CHECK(output.str() ==
"forall N1 (p(N1) <-> N1 in 1..5)\n" "forall N1 (p(N1) <-> N1 in (1..5))\n"
"forall N2 (q(N2) <-> exists N3 (p(N3) and N2 in ((N3 + 5) / 3)))\n" "forall N2 (q(N2) <-> exists N3 (p(N3) and N2 in ((N3 + 5) / 3)))\n"
"int(p/1@1)\n" "int(p/1@1)\n"
"int(q/1@1)\n"); "int(q/1@1)\n");
@ -74,7 +74,7 @@ TEST_CASE("[integer detection] Integer variables are correctly detected", "[inte
anthem::translate("input", input, context); anthem::translate("input", input, context);
CHECK(output.str() == CHECK(output.str() ==
"forall N1 (p(N1) <-> N1 in 1..5)\n" "forall N1 (p(N1) <-> N1 in (1..5))\n"
"forall V1 (q(V1) <-> V1 = error)\n" "forall V1 (q(V1) <-> V1 = error)\n"
"forall N2, V2, N3 (r(N2, V2, N3) <-> exists N4 (p(N4) and N2 = (N4 ** 2) and q(V2) and p(N3)))\n" "forall N2, V2, N3 (r(N2, V2, N3) <-> exists N4 (p(N4) and N2 = (N4 ** 2) and q(V2) and p(N3)))\n"
"int(p/1@1)\n" "int(p/1@1)\n"
@ -89,7 +89,7 @@ TEST_CASE("[integer detection] Integer variables are correctly detected", "[inte
anthem::translate("input", input, context); anthem::translate("input", input, context);
CHECK(output.str() == CHECK(output.str() ==
"forall N1 (p(N1) <-> N1 in 2..n)\n" "forall N1 (p(N1) <-> N1 in (2..n))\n"
"int(p/1@1)\n"); "int(p/1@1)\n");
} }

View File

@ -40,7 +40,7 @@ TEST_CASE("[simplification] Rules are simplified correctly", "[simplification]")
input << ":- not covered(I), I = 1..n."; input << ":- not covered(I), I = 1..n.";
anthem::translate("input", input, context); anthem::translate("input", input, context);
CHECK(output.str() == "((not covered(U1) and U1 in 1..n) -> #false)\n"); CHECK(output.str() == "((not covered(U1) and U1 in (1..n)) -> #false)\n");
} }
SECTION("comparisons") SECTION("comparisons")

View File

@ -24,7 +24,7 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
input << "p(1..5)."; input << "p(1..5).";
anthem::translate("input", input, context); anthem::translate("input", input, context);
CHECK(output.str() == "(V1 in 1..5 -> p(V1))\n"); CHECK(output.str() == "(V1 in (1..5) -> p(V1))\n");
} }
SECTION("simple example 2") SECTION("simple example 2")
@ -32,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 U1 and exists X1, X2 (X1 in U1 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")
@ -48,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 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"); 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")
@ -57,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 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"); 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)")
@ -66,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 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"); 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")
@ -98,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 U1 and not p(X1)) and exists X2, X3 (X2 in U1 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)")
@ -178,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 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"); 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("intervals with variable") SECTION("intervals with variable")
@ -186,7 +186,7 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
input << ":- q(N), 1 = 1..N."; input << ":- q(N), 1 = 1..N.";
anthem::translate("input", input, context); anthem::translate("input", input, context);
CHECK(output.str() == "((exists X1 (X1 in U1 and q(X1)) and exists X2, X3 (X2 in 1 and X3 in 1..U1 and X2 = X3)) -> #false)\n"); CHECK(output.str() == "((exists X1 (X1 in U1 and q(X1)) and exists X2, X3 (X2 in 1 and X3 in (1..U1) and X2 = X3)) -> #false)\n");
} }
SECTION("intervals with two variables") SECTION("intervals with two variables")
@ -194,7 +194,7 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
input << ":- q(M, N), M = 1..N."; input << ":- q(M, N), M = 1..N.";
anthem::translate("input", input, context); anthem::translate("input", input, context);
CHECK(output.str() == "((exists X1, X2 (X1 in U1 and X2 in U2 and q(X1, X2)) and exists X3, X4 (X3 in U1 and X4 in 1..U2 and X3 = X4)) -> #false)\n"); CHECK(output.str() == "((exists X1, X2 (X1 in U1 and X2 in U2 and q(X1, X2)) and exists X3, X4 (X3 in U1 and X4 in (1..U2) and X3 = X4)) -> #false)\n");
} }
SECTION("comparisons") SECTION("comparisons")
@ -262,7 +262,7 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
anthem::translate("input", input, context); anthem::translate("input", input, context);
// TODO: eliminate V5: not needed // 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"); 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")
@ -302,6 +302,6 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
input << "p(N, N ** N) :- N = 1..n."; input << "p(N, N ** N) :- N = 1..n.";
anthem::translate("input", input, context); anthem::translate("input", input, context);
CHECK(output.str() == "((V1 in U1 and V2 in (U1 ** U1) and exists X1, X2 (X1 in U1 and X2 in 1..n and X1 = X2)) -> p(V1, V2))\n"); CHECK(output.str() == "((V1 in U1 and V2 in (U1 ** U1) and exists X1, X2 (X1 in U1 and X2 in (1..n) and X1 = X2)) -> p(V1, V2))\n");
} }
} }