souffle  2.0.2-371-g6315b36
Public Member Functions | Private Member Functions
souffle::ast::transform::PartitionBodyLiteralsTransformer Class Reference

Transformation pass to move literals into new clauses if they are independent of remaining literals. More...

#include <PartitionBodyLiterals.h>

Inheritance diagram for souffle::ast::transform::PartitionBodyLiteralsTransformer:
Inheritance graph
Collaboration diagram for souffle::ast::transform::PartitionBodyLiteralsTransformer:
Collaboration graph

Public Member Functions

PartitionBodyLiteralsTransformerclone () const override
 
std::string getName () const override
 
- Public Member Functions inherited from souffle::ast::transform::Transformer
bool apply (TranslationUnit &translationUnit)
 
virtual ~Transformer ()=default
 

Private Member Functions

bool transform (TranslationUnit &translationUnit) override
 

Detailed Description

Transformation pass to move literals into new clauses if they are independent of remaining literals.

E.g. a(x) :- b(x), c(y), d(y), e(z). is transformed into:

Definition at line 49 of file PartitionBodyLiterals.h.

Member Function Documentation

◆ clone()

PartitionBodyLiteralsTransformer* souffle::ast::transform::PartitionBodyLiteralsTransformer::clone ( ) const
inlineoverridevirtual

Implements souffle::ast::transform::Transformer.

Definition at line 66 of file PartitionBodyLiterals.h.

◆ getName()

std::string souffle::ast::transform::PartitionBodyLiteralsTransformer::getName ( ) const
inlineoverridevirtual

Implements souffle::ast::transform::Transformer.

Definition at line 62 of file PartitionBodyLiterals.h.

◆ transform()

bool souffle::ast::transform::PartitionBodyLiteralsTransformer::transform ( TranslationUnit translationUnit)
overrideprivatevirtual

Implements souffle::ast::transform::Transformer.

Definition at line 41 of file PartitionBodyLiterals.cpp.

68  {
69  // Create the variable dependency graph G
70  Graph<std::string> variableGraph = Graph<std::string>();
71  std::set<std::string> ruleVariables;
72 
73  // Add in the nodes
74  // The nodes of G are the variables in the rule
75  visitDepthFirst(clause, [&](const ast::Variable& var) {
76  variableGraph.insert(var.getName());
77  ruleVariables.insert(var.getName());
78  });
79 
80  // Add in the edges
81  // Since we are only looking at reachability in the final graph, it is
82  // enough to just add in an (undirected) edge from the first variable
83  // in the literal to each of the other variables.
84  std::vector<Literal*> literalsToConsider = clause.getBodyLiterals();
85  literalsToConsider.push_back(clause.getHead());
86 
87  for (Literal* clauseLiteral : literalsToConsider) {
88  std::set<std::string> literalVariables;
89 
90  // Store all variables in the literal
91  visitDepthFirst(*clauseLiteral,
92  [&](const ast::Variable& var) { literalVariables.insert(var.getName()); });
93 
94  // No new edges if only one variable is present
95  if (literalVariables.size() > 1) {
96  std::string firstVariable = *literalVariables.begin();
97  literalVariables.erase(literalVariables.begin());
98 
99  // Create the undirected edge
100  for (const std::string& var : literalVariables) {
101  variableGraph.insert(firstVariable, var);
102  variableGraph.insert(var, firstVariable);
103  }
104  }
105  }
106 
107  // Find the connected components of G
108  std::set<std::string> seenNodes;
109 
110  // Find the connected component associated with the head
111  std::set<std::string> headComponent;
113  *clause.getHead(), [&](const ast::Variable& var) { headComponent.insert(var.getName()); });
114 
115  if (!headComponent.empty()) {
116  variableGraph.visitDepthFirst(*headComponent.begin(), [&](const std::string& var) {
117  headComponent.insert(var);
118  seenNodes.insert(var);
119  });
120  }
121 
122  // Compute all other connected components in the graph G
123  std::set<std::set<std::string>> connectedComponents;
124 
125  for (std::string var : ruleVariables) {
126  if (seenNodes.find(var) != seenNodes.end()) {
127  // Node has already been added to a connected component
128  continue;
129  }
130 
131  // Construct the connected component
132  std::set<std::string> component;
133  variableGraph.visitDepthFirst(var, [&](const std::string& child) {
134  component.insert(child);
135  seenNodes.insert(child);
136  });
137  connectedComponents.insert(component);
138  }
139 
140  if (connectedComponents.empty()) {
141  // No separate connected components, so no point partitioning
142  return;
143  }
144 
145  // Need to extract some disconnected lits!
146  changed = true;
147  std::vector<Atom*> replacementAtoms;
148 
149  // Construct the new rules
150  for (const std::set<std::string>& component : connectedComponents) {
151  // Come up with a unique new name for the relation
152  static int disconnectedCount = 0;
153  std::stringstream nextName;
154  nextName << "+disconnected" << disconnectedCount;
155  QualifiedName newRelationName = nextName.str();
156  disconnectedCount++;
157 
158  // Create the extracted relation and clause for the component
159  // newrelX() <- disconnectedLiterals(x).
160  auto newRelation = mk<Relation>();
161  newRelation->setQualifiedName(newRelationName);
162  program.addRelation(std::move(newRelation));
163 
164  auto* disconnectedClause = new Clause();
165  disconnectedClause->setSrcLoc(clause.getSrcLoc());
166  disconnectedClause->setHead(mk<Atom>(newRelationName));
167 
168  // Find the body literals for this connected component
169  std::vector<Literal*> associatedLiterals;
170  for (Literal* bodyLiteral : clause.getBodyLiterals()) {
171  bool associated = false;
172  visitDepthFirst(*bodyLiteral, [&](const ast::Variable& var) {
173  if (component.find(var.getName()) != component.end()) {
174  associated = true;
175  }
176  });
177  if (associated) {
178  disconnectedClause->addToBody(souffle::clone(bodyLiteral));
179  }
180  }
181 
182  // Create the atom to replace all these literals
183  replacementAtoms.push_back(new Atom(newRelationName));
184 
185  // Add the clause to the program
186  clausesToAdd.push_back(disconnectedClause);
187  }
188 
189  // Create the replacement clause
190  // a(x) <- b(x), c(y), d(z). --> a(x) <- newrel0(), newrel1(), b(x).
191  auto* replacementClause = new Clause();
192  replacementClause->setSrcLoc(clause.getSrcLoc());
193  replacementClause->setHead(souffle::clone(clause.getHead()));
194 
195  // Add the new propositions to the clause first
196  for (Atom* newAtom : replacementAtoms) {
197  replacementClause->addToBody(Own<Literal>(newAtom));
198  }
199 
200  // Add the remaining body literals to the clause
201  for (Literal* bodyLiteral : clause.getBodyLiterals()) {
202  bool associated = false;
203  bool hasVariables = false;
204  visitDepthFirst(*bodyLiteral, [&](const ast::Variable& var) {
205  hasVariables = true;
206  if (headComponent.find(var.getName()) != headComponent.end()) {
207  associated = true;
208  }
209  });
210  if (associated || !hasVariables) {
211  replacementClause->addToBody(souffle::clone(bodyLiteral));
212  }
213  }
214 
215  // Replace the old clause with the new one
216  clausesToRemove.push_back(&clause);
217  clausesToAdd.push_back(replacementClause);
218  });
219 
220  // Adjust the program
221  for (Clause* newClause : clausesToAdd) {
222  program.addClause(Own<Clause>(newClause));
223  }
224 
225  for (const Clause* oldClause : clausesToRemove) {
226  program.removeClause(oldClause);
227  }
228 
229  return changed;
230 }
231 
232 } // namespace souffle::ast::transform

References souffle::clone(), souffle::ast::Clause::getBodyLiterals(), souffle::ast::Clause::getHead(), souffle::ast::Node::getSrcLoc(), and souffle::ast::visitDepthFirst().

Here is the call graph for this function:

The documentation for this class was generated from the following files:
souffle::clone
auto clone(const std::vector< A * > &xs)
Definition: ContainerUtil.h:172
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