souffle  2.0.2-371-g6315b36
RemoveEmptyRelations.cpp
Go to the documentation of this file.
1 /*
2  * Souffle - A Datalog Compiler
3  * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved
4  * Licensed under the Universal Permissive License v 1.0 as shown at:
5  * - https://opensource.org/licenses/UPL
6  * - <souffle root>/licenses/SOUFFLE-UPL.txt
7  */
8 
9 /************************************************************************
10  *
11  * @file RemoveEmptyRelations.cpp
12  *
13  ***********************************************************************/
14 
16 #include "ast/Aggregator.h"
17 #include "ast/Atom.h"
18 #include "ast/Clause.h"
19 #include "ast/Literal.h"
20 #include "ast/Negation.h"
21 #include "ast/Program.h"
22 #include "ast/Relation.h"
23 #include "ast/TranslationUnit.h"
24 #include "ast/analysis/IOType.h"
25 #include "ast/utility/Utils.h"
26 #include "ast/utility/Visitor.h"
28 #include <algorithm>
29 #include <memory>
30 #include <set>
31 #include <utility>
32 #include <vector>
33 
34 namespace souffle::ast::transform {
35 
36 bool RemoveEmptyRelationsTransformer::removeEmptyRelations(TranslationUnit& translationUnit) {
37  Program& program = translationUnit.getProgram();
38  auto* ioTypes = translationUnit.getAnalysis<analysis::IOTypeAnalysis>();
39  std::set<QualifiedName> emptyRelations;
40  bool changed = false;
41  for (auto rel : program.getRelations()) {
42  if (!getClauses(program, *rel).empty() || ioTypes->isInput(rel)) {
43  continue;
44  }
45  emptyRelations.insert(rel->getQualifiedName());
46 
47  bool usedInAggregate = false;
48  visitDepthFirst(program, [&](const Aggregator& agg) {
49  for (const auto lit : agg.getBodyLiterals()) {
50  visitDepthFirst(*lit, [&](const Atom& atom) {
51  if (getAtomRelation(&atom, &program) == rel) {
52  usedInAggregate = true;
53  }
54  });
55  }
56  });
57 
58  if (!usedInAggregate && !ioTypes->isOutput(rel)) {
59  removeRelation(translationUnit, rel->getQualifiedName());
60  changed = true;
61  }
62  }
63 
64  for (const auto& relName : emptyRelations) {
65  changed |= removeEmptyRelationUses(translationUnit, relName);
66  }
67 
68  return changed;
69 }
70 
71 bool RemoveEmptyRelationsTransformer::removeEmptyRelationUses(
72  TranslationUnit& translationUnit, const QualifiedName& emptyRelationName) {
73  Program& program = translationUnit.getProgram();
74  bool changed = false;
75 
76  //
77  // (1) drop rules from the program that have empty relations in their bodies.
78  // (2) drop negations of empty relations
79  //
80  // get all clauses
81  std::vector<const Clause*> clauses;
82  visitDepthFirst(program, [&](const Clause& cur) { clauses.push_back(&cur); });
83 
84  // clean all clauses
85  for (const Clause* cl : clauses) {
86  // check for an atom whose relation is the empty relation
87 
88  bool removed = false;
89  for (Literal* lit : cl->getBodyLiterals()) {
90  if (auto* arg = dynamic_cast<Atom*>(lit)) {
91  if (arg->getQualifiedName() == emptyRelationName) {
92  program.removeClause(cl);
93  removed = true;
94  changed = true;
95  break;
96  }
97  }
98  }
99 
100  if (!removed) {
101  // check whether a negation with empty relations exists
102 
103  bool rewrite = false;
104  for (Literal* lit : cl->getBodyLiterals()) {
105  if (auto* neg = dynamic_cast<Negation*>(lit)) {
106  if (neg->getAtom()->getQualifiedName() == emptyRelationName) {
107  rewrite = true;
108  break;
109  }
110  }
111  }
112 
113  if (rewrite) {
114  // clone clause without negation for empty relations
115 
116  auto res = Own<Clause>(cloneHead(cl));
117 
118  for (Literal* lit : cl->getBodyLiterals()) {
119  if (auto* neg = dynamic_cast<Negation*>(lit)) {
120  if (neg->getAtom()->getQualifiedName() != emptyRelationName) {
121  res->addToBody(souffle::clone(lit));
122  }
123  } else {
124  res->addToBody(souffle::clone(lit));
125  }
126  }
127 
128  program.removeClause(cl);
129  program.addClause(std::move(res));
130  changed = true;
131  }
132  }
133  }
134 
135  return changed;
136 }
137 
138 } // namespace souffle::ast::transform
souffle::ast::cloneHead
Clause * cloneHead(const Clause *clause)
Returns a clause which contains head of the given clause.
Definition: Utils.cpp:254
TranslationUnit.h
souffle::ast::removeRelation
void removeRelation(TranslationUnit &tu, const QualifiedName &name)
Remove relation and all its clauses from the program.
Definition: Utils.cpp:105
IOType.h
MiscUtil.h
souffle::ast::Clause
Intermediate representation of a horn clause.
Definition: Clause.h:51
RemoveEmptyRelations.h
Relation.h
souffle::ast::Atom
An atom class.
Definition: Atom.h:51
Utils.h
souffle::ast::transform::RemoveEmptyRelationsTransformer::removeEmptyRelations
static bool removeEmptyRelations(TranslationUnit &translationUnit)
Eliminate all empty relations (and their uses) in the given program.
Definition: RemoveEmptyRelations.cpp:40
souffle::clone
auto clone(const std::vector< A * > &xs)
Definition: ContainerUtil.h:172
clauses
std::vector< Own< Clause > > clauses
Definition: ComponentInstantiation.cpp:67
Atom.h
Literal.h
souffle::ast::Literal
Defines an abstract class for literals in a horn clause.
Definition: Literal.h:36
souffle::ast::transform
Definition: Program.h:45
Negation.h
souffle::ast::getClauses
std::vector< Clause * > getClauses(const Program &program, const QualifiedName &relationName)
Returns a vector of clauses in the program describing the relation with the given name.
Definition: Utils.cpp:77
Aggregator.h
souffle::ast::Aggregator::getBodyLiterals
std::vector< Literal * > getBodyLiterals() const
Return body literals.
Definition: Aggregator.h:71
souffle::ast::Aggregator
Defines the aggregator class.
Definition: Aggregator.h:53
Program.h
Visitor.h
Clause.h
souffle::ast::visitDepthFirst
void visitDepthFirst(const Node &root, Visitor< R, Ps... > &visitor, Args &... args)
A utility function visiting all nodes within the ast rooted by the given node recursively in a depth-...
Definition: Visitor.h:273
rel
void rel(size_t limit, bool showLimit=true)
Definition: Tui.h:1086