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

Transformation pass to replaces copy of relations by their origin. More...

#include <RemoveRelationCopies.h>

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

Public Member Functions

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

Static Public Member Functions

static bool removeRelationCopies (TranslationUnit &translationUnit)
 Replaces copies of relations by their origin in the given program. More...
 

Private Member Functions

bool transform (TranslationUnit &translationUnit) override
 

Detailed Description

Transformation pass to replaces copy of relations by their origin.

For instance, if a relation r is defined by

 r(X,Y) :- s(X,Y)

and no other clause, all occurrences of r will be replaced by s.

Definition at line 35 of file RemoveRelationCopies.h.

Member Function Documentation

◆ clone()

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

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

Definition at line 53 of file RemoveRelationCopies.h.

◆ getName()

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

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

Definition at line 41 of file RemoveRelationCopies.h.

45  {

◆ removeRelationCopies()

bool souffle::ast::transform::RemoveRelationCopiesTransformer::removeRelationCopies ( TranslationUnit translationUnit)
static

Replaces copies of relations by their origin in the given program.

Parameters
programthe program to be processed
Returns
whether the program was modified

Definition at line 42 of file RemoveRelationCopies.cpp.

49  : 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

References clauses, souffle::equal_targets(), souffle::ast::Atom::getArguments(), souffle::ast::Clause::getBodyLiterals(), souffle::ast::getClauses(), souffle::ast::Clause::getHead(), souffle::ast::Atom::getQualifiedName(), souffle::ast::isFact(), and rel().

Referenced by souffle::ast::transform::test::TEST().

Here is the call graph for this function:

◆ transform()

bool souffle::ast::transform::RemoveRelationCopiesTransformer::transform ( TranslationUnit translationUnit)
inlineoverrideprivatevirtual

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

Definition at line 58 of file RemoveRelationCopies.h.


The documentation for this class was generated from the following files:
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::isFact
bool isFact(const Clause &clause)
Returns whether the given clause is a fact.
Definition: Utils.cpp:214
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
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
souffle::ast::Relation::getQualifiedName
const QualifiedName & getQualifiedName() const
Get qualified relation name.
Definition: Relation.h:57
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