Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/ast/SubsumptiveClause.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ namespace souffle::ast {
* Format:
* A(x1,...) <= A(y1,...) :- <Body> .
*
*
* Internally the least and greatest atoms of the rule's head are added to the clause body literals at
* index `0` and `1` in `bodyLiterals`. The least atom of the rule's head is stored in the `head`.
*
*/
class SubsumptiveClause : public Clause {
public:
Expand Down
41 changes: 36 additions & 5 deletions src/ast/transform/PartitionBodyLiterals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ bool PartitionBodyLiteralsTransformer::transform(TranslationUnit& translationUni
Graph<std::string> variableGraph = Graph<std::string>();
std::set<std::string> ruleVariables;

const bool isSubsumption = isA<SubsumptiveClause>(clause);

// Add in the nodes
// The nodes of G are the variables in the rule
visit(clause, [&](const ast::Variable& var) {
Expand Down Expand Up @@ -110,6 +112,26 @@ bool PartitionBodyLiteralsTransformer::transform(TranslationUnit& translationUni
std::set<std::string> headComponent;
visit(*clause.getHead(), [&](const ast::Variable& var) { headComponent.insert(var.getName()); });

if (isSubsumption) {
// this works because subsumptive clause first two literals are the least and greatest atoms
// of the original clause's head: `A(least, ... ) <= A(greatest, ...) :- ...`.
std::set<std::string> leastAtomVariables;
std::set<std::string> greatestAtomVariables;
visit(literalsToConsider[0],
[&](const ast::Variable& var) { leastAtomVariables.insert(var.getName()); });
visit(literalsToConsider[1],
[&](const ast::Variable& var) { greatestAtomVariables.insert(var.getName()); });
// Create edge between any couple of variables taken respectively from the least and greatest
// atoms: `least <-> greatest`, since in the previous step of the algorithm we already linked
// variables within each atom.
if (!(leastAtomVariables.empty() || greatestAtomVariables.empty())) {
const auto vL = *leastAtomVariables.begin();
const auto vG = *greatestAtomVariables.begin();
variableGraph.insert(vL, vG);
variableGraph.insert(vG, vL);
}
}

if (!headComponent.empty()) {
variableGraph.visit(*headComponent.begin(), [&](const std::string& var) {
headComponent.insert(var);
Expand Down Expand Up @@ -181,10 +203,17 @@ bool PartitionBodyLiteralsTransformer::transform(TranslationUnit& translationUni
clausesToAdd.push_back(std::move(disconnectedClause));
}

// Create the replacement clause
// a(x) <- b(x), c(y), d(z). --> a(x) <- newrel0(), newrel1(), b(x).
auto replacementClause =
mk<Clause>(clone(clause.getHead()), std::move(replacementAtoms), nullptr, clause.getSrcLoc());
// Create the replacement clause. The original literals must appear first and in order to
// satisfy the SubsumptiveClause invariants.
//
// `a(x) <- b(x), c(y), d(z). --> a(x) <- b(x), newrel0(), newrel1().`
Clause* replacementClause;
if (isSubsumption) {
replacementClause =
new SubsumptiveClause(clone(clause.getHead()), {}, nullptr, clause.getSrcLoc());
} else {
replacementClause = new Clause(clone(clause.getHead()), {}, nullptr, clause.getSrcLoc());
}

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

replacementClause->addToBody(std::move(replacementAtoms));

// Replace the old clause with the new one
clausesToRemove.push_back(&clause);
clausesToAdd.push_back(std::move(replacementClause));
clausesToAdd.push_back(std::unique_ptr<Clause>(replacementClause));
});

// Adjust the program
Expand Down
1 change: 1 addition & 0 deletions src/ast/transform/SubsumptionQualifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ bool SubsumptionQualifierTransformer::transform(TranslationUnit& translationUnit
// rewrite relation representation
if (relation->getRepresentation() == RelationRepresentation::DEFAULT && hasSubsumptiveRule) {
relation->setRepresentation(RelationRepresentation::BTREE_DELETE);
changed = true;
}
}
return changed;
Expand Down
1 change: 1 addition & 0 deletions tests/evaluation/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -165,3 +165,4 @@ positive_test(issue2160)
add_subdirectory(issue2508)
souffle_positive_functor_test(issue2508 CATEGORY evaluation)
positive_test(issue2532)
positive_test(issue2551)
11 changes: 11 additions & 0 deletions tests/evaluation/issue2551/issue2551.dl
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.decl m(s: number)
.output r
.decl r(s: number)
.output m
r(1).
m(1).
m(2).
// m = {1,2} before subsumption, and then expect m = {1} because
// m(2) is subsumed by m(1):
// m(2) <= m(1) :- !r(2), m(1).
m(x) <= m(y) :- !r(x), m(y).
Empty file.
Empty file.
1 change: 1 addition & 0 deletions tests/evaluation/issue2551/m.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1
1 change: 1 addition & 0 deletions tests/evaluation/issue2551/r.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1
Loading