souffle  2.0.2-371-g6315b36
RemoveRelationCopies.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 RemoveRelationCopies.cpp
12  *
13  ***********************************************************************/
14 
16 #include "ast/Argument.h"
17 #include "ast/Atom.h"
18 #include "ast/Clause.h"
19 #include "ast/Program.h"
20 #include "ast/QualifiedName.h"
21 #include "ast/RecordInit.h"
22 #include "ast/Relation.h"
23 #include "ast/TranslationUnit.h"
24 #include "ast/Variable.h"
25 #include "ast/analysis/IOType.h"
26 #include "ast/utility/Utils.h"
27 #include "ast/utility/Visitor.h"
29 #include <algorithm>
30 #include <cassert>
31 #include <map>
32 #include <set>
33 #include <utility>
34 #include <vector>
35 
36 namespace souffle::ast::transform {
37 
38 bool RemoveRelationCopiesTransformer::removeRelationCopies(TranslationUnit& translationUnit) {
39  using alias_map = std::map<QualifiedName, QualifiedName>;
40 
41  // collect aliases
42  alias_map isDirectAliasOf;
43 
44  auto* ioType = translationUnit.getAnalysis<analysis::IOTypeAnalysis>();
45 
46  Program& program = translationUnit.getProgram();
47 
48  // search for relations only defined by a single rule ..
49  for (Relation* rel : program.getRelations()) {
50  const auto& clauses = getClauses(program, *rel);
51  if (!ioType->isIO(rel) && clauses.size() == 1u) {
52  // .. of shape r(x,y,..) :- s(x,y,..)
53  Clause* cl = clauses[0];
54  std::vector<Atom*> bodyAtoms = getBodyLiterals<Atom>(*cl);
55  if (!isFact(*cl) && cl->getBodyLiterals().size() == 1u && bodyAtoms.size() == 1u) {
56  Atom* atom = bodyAtoms[0];
57  if (equal_targets(cl->getHead()->getArguments(), atom->getArguments())) {
58  // Requirements:
59  // 1) (checked) It is a rule with exactly one body.
60  // 3) (checked) The body consists of an atom.
61  // 4) (checked) The atom's arguments must be identical to the rule's head.
62  // 5) (pending) The rules's head must consist only of either:
63  // 5a) Variables
64  // 5b) Records unpacked into variables
65  // 6) (pending) Each variable must have a distinct name.
66  bool onlyDistinctHeadVars = true;
67  std::set<std::string> headVars;
68 
69  auto args = cl->getHead()->getArguments();
70  while (onlyDistinctHeadVars && !args.empty()) {
71  const auto cur = args.back();
72  args.pop_back();
73 
74  if (auto var = dynamic_cast<const ast::Variable*>(cur)) {
75  onlyDistinctHeadVars &= headVars.insert(var->getName()).second;
76  } else if (auto init = dynamic_cast<const RecordInit*>(cur)) {
77  // records are decomposed and their arguments are checked
78  for (auto rec_arg : init->getArguments()) {
79  args.push_back(rec_arg);
80  }
81  } else {
82  onlyDistinctHeadVars = false;
83  }
84  }
85 
86  if (onlyDistinctHeadVars) {
87  // all arguments are either distinct variables or records unpacked into distinct
88  // variables
89  isDirectAliasOf[cl->getHead()->getQualifiedName()] = atom->getQualifiedName();
90  }
91  }
92  }
93  }
94  }
95 
96  // map each relation to its ultimate alias (could be transitive)
97  alias_map isAliasOf;
98 
99  // track any copy cycles; cyclic rules are effectively empty
100  std::set<QualifiedName> cycle_reps;
101 
102  for (std::pair<QualifiedName, QualifiedName> cur : isDirectAliasOf) {
103  // compute replacement
104 
105  std::set<QualifiedName> visited;
106  visited.insert(cur.first);
107  visited.insert(cur.second);
108 
109  auto pos = isDirectAliasOf.find(cur.second);
110  while (pos != isDirectAliasOf.end()) {
111  if (visited.count(pos->second) != 0u) {
112  cycle_reps.insert(cur.second);
113  break;
114  }
115  cur.second = pos->second;
116  pos = isDirectAliasOf.find(cur.second);
117  }
118  isAliasOf[cur.first] = cur.second;
119  }
120 
121  if (isAliasOf.empty()) {
122  return false;
123  }
124 
125  // replace usage of relations according to alias map
126  visitDepthFirst(program, [&](const Atom& atom) {
127  auto pos = isAliasOf.find(atom.getQualifiedName());
128  if (pos != isAliasOf.end()) {
129  const_cast<Atom&>(atom).setQualifiedName(pos->second);
130  }
131  });
132 
133  // break remaining cycles
134  for (const auto& rep : cycle_reps) {
135  const auto& rel = *getRelation(program, rep);
136  const auto& clauses = getClauses(program, rel);
137  assert(clauses.size() == 1u && "unexpected number of clauses in relation");
138  program.removeClause(clauses[0]);
139  }
140 
141  // remove unused relations
142  for (const auto& cur : isAliasOf) {
143  if (cycle_reps.count(cur.first) == 0u) {
144  removeRelation(translationUnit, getRelation(program, cur.first)->getQualifiedName());
145  }
146  }
147 
148  return true;
149 }
150 
151 } // namespace souffle::ast::transform
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
souffle::ast::Atom::getArguments
std::vector< Argument * > getArguments() const
Return arguments.
Definition: Atom.h:77
IOType.h
souffle::ast::analysis::IOTypeAnalysis
Definition: IOType.h:39
souffle::ast::Relation
Defines a relation with a name, attributes, qualifiers, and internal representation.
Definition: Relation.h:49
souffle::ast::Clause
Intermediate representation of a horn clause.
Definition: Clause.h:51
souffle::ast::isFact
bool isFact(const Clause &clause)
Returns whether the given clause is a fact.
Definition: Utils.cpp:214
souffle::ast::analysis::Variable
A variable to be utilized within constraints to be handled by the constraint solver.
Definition: ConstraintSystem.h:41
Relation.h
souffle::ast::Atom
An atom class.
Definition: Atom.h:51
souffle::ast::Clause::getHead
Atom * getHead() const
Return the atom that represents the head of the clause.
Definition: Clause.h:74
Utils.h
Argument.h
souffle::ast::Program
The program class consists of relations, clauses and types.
Definition: Program.h:52
souffle::ast::Atom::getQualifiedName
const QualifiedName & getQualifiedName() const
Return qualified name.
Definition: Atom.h:57
ContainerUtil.h
souffle::ast::getRelation
Relation * getRelation(const Program &program, const QualifiedName &name)
Returns the relation with the given name in the program.
Definition: Utils.cpp:101
souffle::equal_targets
bool equal_targets(const Container &a, const Container &b, const Comparator &comp)
A function testing whether two containers are equal with the given Comparator.
Definition: ContainerUtil.h:433
clauses
std::vector< Own< Clause > > clauses
Definition: ComponentInstantiation.cpp:67
Atom.h
souffle::ast::transform
Definition: Program.h:45
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
QualifiedName.h
Program.h
souffle::ast::Relation::getQualifiedName
const QualifiedName & getQualifiedName() const
Get qualified relation name.
Definition: Relation.h:57
souffle::ast::transform::RemoveRelationCopiesTransformer::removeRelationCopies
static bool removeRelationCopies(TranslationUnit &translationUnit)
Replaces copies of relations by their origin in the given program.
Definition: RemoveRelationCopies.cpp:42
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
RemoveRelationCopies.h
rel
void rel(size_t limit, bool showLimit=true)
Definition: Tui.h:1086
RecordInit.h
souffle::ast::RecordInit
Defines a record initialization class.
Definition: RecordInit.h:42
souffle::ast::Clause::getBodyLiterals
std::vector< Literal * > getBodyLiterals() const
Obtains a copy of the internally maintained body literals.
Definition: Clause.h:79
Variable.h