Skip to content

Commit 0447ecd

Browse files
committed
Fix PartitionBodyLiteralsTransformer with subsumptive clause
The `PartitionBodyLiteralsTransformer` did not handle subsumptive clauses and treated them as normal clause. It's a design flaw of `SubsumptiveClause` being a subclass of `Clause`. Similar issue could happen for any transformation that rewrites a `Clause`. fix #2551
1 parent b37994d commit 0447ecd

File tree

9 files changed

+55
-5
lines changed

9 files changed

+55
-5
lines changed

src/ast/SubsumptiveClause.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ namespace souffle::ast {
3434
* Format:
3535
* A(x1,...) <= A(y1,...) :- <Body> .
3636
*
37+
*
38+
* Internally the least and greatest atoms of the rule's head are added to the clause body literals at
39+
* index `0` and `1` in `bodyLiterals`. The least atom of the rule's head is stored in the `head`.
40+
*
3741
*/
3842
class SubsumptiveClause : public Clause {
3943
public:

src/ast/transform/PartitionBodyLiterals.cpp

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ bool PartitionBodyLiteralsTransformer::transform(TranslationUnit& translationUni
7070
Graph<std::string> variableGraph = Graph<std::string>();
7171
std::set<std::string> ruleVariables;
7272

73+
const bool isSubsumption = isA<SubsumptiveClause>(clause);
74+
7375
// Add in the nodes
7476
// The nodes of G are the variables in the rule
7577
visit(clause, [&](const ast::Variable& var) {
@@ -110,6 +112,26 @@ bool PartitionBodyLiteralsTransformer::transform(TranslationUnit& translationUni
110112
std::set<std::string> headComponent;
111113
visit(*clause.getHead(), [&](const ast::Variable& var) { headComponent.insert(var.getName()); });
112114

115+
if (isSubsumption) {
116+
// this works because subsumptive clause first two literals are the least and greatest atoms
117+
// of the original clause's head: `A(least, ... ) <= A(greatest, ...) :- ...`.
118+
std::set<std::string> leastAtomVariables;
119+
std::set<std::string> greatestAtomVariables;
120+
visit(literalsToConsider[0],
121+
[&](const ast::Variable& var) { leastAtomVariables.insert(var.getName()); });
122+
visit(literalsToConsider[1],
123+
[&](const ast::Variable& var) { greatestAtomVariables.insert(var.getName()); });
124+
// Create edge between any couple of variables taken respectively from the least and greatest
125+
// atoms: `least <-> greatest`, since in the previous step of the algorithm we already linked
126+
// variables within each atom.
127+
if (!(leastAtomVariables.empty() || greatestAtomVariables.empty())) {
128+
const auto vL = *leastAtomVariables.begin();
129+
const auto vG = *greatestAtomVariables.begin();
130+
variableGraph.insert(vL, vG);
131+
variableGraph.insert(vG, vL);
132+
}
133+
}
134+
113135
if (!headComponent.empty()) {
114136
variableGraph.visit(*headComponent.begin(), [&](const std::string& var) {
115137
headComponent.insert(var);
@@ -181,10 +203,17 @@ bool PartitionBodyLiteralsTransformer::transform(TranslationUnit& translationUni
181203
clausesToAdd.push_back(std::move(disconnectedClause));
182204
}
183205

184-
// Create the replacement clause
185-
// a(x) <- b(x), c(y), d(z). --> a(x) <- newrel0(), newrel1(), b(x).
186-
auto replacementClause =
187-
mk<Clause>(clone(clause.getHead()), std::move(replacementAtoms), nullptr, clause.getSrcLoc());
206+
// Create the replacement clause. The original literals must appear first and in order to
207+
// satisfy the SubsumptiveClause invariants.
208+
//
209+
// `a(x) <- b(x), c(y), d(z). --> a(x) <- b(x), newrel0(), newrel1().`
210+
Clause* replacementClause;
211+
if (isSubsumption) {
212+
replacementClause =
213+
new SubsumptiveClause(clone(clause.getHead()), {}, nullptr, clause.getSrcLoc());
214+
} else {
215+
replacementClause = new Clause(clone(clause.getHead()), {}, nullptr, clause.getSrcLoc());
216+
}
188217

189218
// Add the remaining body literals to the clause
190219
for (Literal* bodyLiteral : clause.getBodyLiterals()) {
@@ -201,9 +230,11 @@ bool PartitionBodyLiteralsTransformer::transform(TranslationUnit& translationUni
201230
}
202231
}
203232

233+
replacementClause->addToBody(std::move(replacementAtoms));
234+
204235
// Replace the old clause with the new one
205236
clausesToRemove.push_back(&clause);
206-
clausesToAdd.push_back(std::move(replacementClause));
237+
clausesToAdd.push_back(std::unique_ptr<Clause>(replacementClause));
207238
});
208239

209240
// Adjust the program

src/ast/transform/SubsumptionQualifier.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ bool SubsumptionQualifierTransformer::transform(TranslationUnit& translationUnit
7272
// rewrite relation representation
7373
if (relation->getRepresentation() == RelationRepresentation::DEFAULT && hasSubsumptiveRule) {
7474
relation->setRepresentation(RelationRepresentation::BTREE_DELETE);
75+
changed = true;
7576
}
7677
}
7778
return changed;

tests/evaluation/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,3 +165,4 @@ positive_test(issue2160)
165165
add_subdirectory(issue2508)
166166
souffle_positive_functor_test(issue2508 CATEGORY evaluation)
167167
positive_test(issue2532)
168+
positive_test(issue2551)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
.decl m(s: number)
2+
.output r
3+
.decl r(s: number)
4+
.output m
5+
r(1).
6+
m(1).
7+
m(2).
8+
// m = {1,2} before subsumption, and then expect m = {1} because
9+
// m(2) is subsumed by m(1):
10+
// m(2) <= m(1) :- !r(2), m(1).
11+
m(x) <= m(y) :- !r(x), m(y).

tests/evaluation/issue2551/issue2551.err

Whitespace-only changes.

tests/evaluation/issue2551/issue2551.out

Whitespace-only changes.

tests/evaluation/issue2551/m.csv

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
1

tests/evaluation/issue2551/r.csv

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
1

0 commit comments

Comments
 (0)