souffle  2.0.2-371-g6315b36
GroundWitnesses.cpp
Go to the documentation of this file.
1 /*
2  * Souffle - A Datalog Compiler
3  * Copyright (c) 2020, The Souffle Developers. 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 GroundWitnesses.cpp
12  *
13  ***********************************************************************/
14 
16 #include "ast/Aggregator.h"
17 #include "ast/Clause.h"
18 #include "ast/analysis/Aggregate.h"
19 #include "ast/analysis/Ground.h"
20 #include "ast/utility/Visitor.h"
22 
23 #include <utility>
24 
25 namespace souffle::ast::transform {
26 
27 bool GroundWitnessesTransformer::transform(TranslationUnit& translationUnit) {
28  Program& program = translationUnit.getProgram();
29 
30  struct AggregateWithWitnesses {
31  Aggregator* aggregate;
32  Clause* originatingClause;
33  std::set<std::string> witnesses;
34 
35  AggregateWithWitnesses(Aggregator* agg, Clause* clause, std::set<std::string> witnesses)
36  : aggregate(agg), originatingClause(clause), witnesses(std::move(witnesses)) {}
37  };
38 
39  std::vector<AggregateWithWitnesses> aggregatesToFix;
40 
41  visitDepthFirst(program, [&](const Clause& clause) {
42  visitDepthFirst(clause, [&](const Aggregator& agg) {
43  auto witnessVariables = analysis::getWitnessVariables(translationUnit, clause, agg);
44  // remove any witness variables that originate from an inner aggregate
45  visitDepthFirst(agg, [&](const Aggregator& innerAgg) {
46  if (agg == innerAgg) {
47  return;
48  }
49  auto innerWitnesses = analysis::getWitnessVariables(translationUnit, clause, innerAgg);
50  for (const auto& witness : innerWitnesses) {
51  witnessVariables.erase(witness);
52  }
53  });
54  if (witnessVariables.empty()) {
55  return;
56  }
57  AggregateWithWitnesses instance(
58  const_cast<Aggregator*>(&agg), const_cast<Clause*>(&clause), witnessVariables);
59  aggregatesToFix.push_back(instance);
60  });
61  });
62 
63  for (struct AggregateWithWitnesses& aggregateToFix : aggregatesToFix) {
64  Aggregator* agg = aggregateToFix.aggregate;
65  Clause* clause = aggregateToFix.originatingClause;
66  std::set<std::string> witnesses = aggregateToFix.witnesses;
67  // agg will become invalid when it gets replaced, so we have to be careful
68  // not to use it after that point.
69  // 1. make a copy of all aggregate body literals, because they will need to
70  // be added to the rule body
71  std::vector<std::unique_ptr<Literal>> aggregateLiterals;
72  for (const auto& literal : agg->getBodyLiterals()) {
73  aggregateLiterals.push_back(souffle::clone(literal));
74  }
75  // 1a. TODO: Be sure to rename any INNER witnesses! They have no meaning here and should just be made
76  // into (For now I won't allow multi-leveled witnesses) an anonymous variable.
77 
78  // 2. Replace witness variables with unique names so they don't clash with the outside
79  std::map<std::string, std::string> newWitnessVariableName;
80  for (std::string witness : witnesses) {
81  newWitnessVariableName[witness] = analysis::findUniqueVariableName(*clause, witness + "_w");
82  }
83  visitDepthFirst(*agg, [&](const Variable& var) {
84  if (witnesses.find(var.getName()) != witnesses.end()) {
85  // if this variable is a witness, we need to replace it with its new name
86  const_cast<Variable&>(var).setName(newWitnessVariableName[var.getName()]);
87  }
88  });
89 
90  // 3. Replace any instance of the target variable with a clone of the aggregate
91  struct TargetVariableReplacer : public NodeMapper {
92  Aggregator* aggregate;
93  std::string targetVariable;
94  TargetVariableReplacer(Aggregator* agg, std::string target)
95  : aggregate(agg), targetVariable(std::move(target)) {}
96  std::unique_ptr<Node> operator()(std::unique_ptr<Node> node) const override {
97  if (auto* variable = dynamic_cast<Variable*>(node.get())) {
98  if (variable->getName() == targetVariable) {
99  auto replacement = souffle::clone(aggregate);
100  return replacement;
101  }
102  }
103  node->apply(*this);
104  return node;
105  }
106  };
107  const auto* targetVariable = dynamic_cast<const Variable*>(agg->getTargetExpression());
108  std::string targetVariableName = targetVariable->getName();
109  TargetVariableReplacer replacer(agg, targetVariableName);
110  for (std::unique_ptr<Literal>& literal : aggregateLiterals) {
111  literal->apply(replacer);
112  // 4. Finally add these new grounding literals for the witness
113  // to the body of the clause and voila! We've grounded
114  // the witness(es)! Yay!
115  clause->addToBody(souffle::clone(literal));
116  }
117  }
118  return !aggregatesToFix.empty();
119 }
120 } // namespace souffle::ast::transform
GroundWitnesses.h
souffle::ast::Clause
Intermediate representation of a horn clause.
Definition: Clause.h:51
Aggregate.h
Ground.h
souffle::clone
auto clone(const std::vector< A * > &xs)
Definition: ContainerUtil.h:172
StringUtil.h
souffle::ast::transform::GroundWitnessesTransformer::transform
bool transform(TranslationUnit &translationUnit) override
Definition: GroundWitnesses.cpp:31
souffle::ast::transform
Definition: Program.h:45
Aggregator.h
souffle::ast::Aggregator
Defines the aggregator class.
Definition: Aggregator.h:53
std
Definition: Brie.h:3053
souffle::ast::analysis::findUniqueVariableName
std::string findUniqueVariableName(const Clause &clause, std::string base)
Find a variable name using base to form a string like base1 Use this when you need to limit the scope...
Definition: Aggregate.cpp:179
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
souffle::ast::analysis::getWitnessVariables
std::set< std::string > getWitnessVariables(const TranslationUnit &tu, const Clause &clause, const Aggregator &aggregate)
Computes the set of witness variables that are used in the aggregate A variable is a witness if it oc...
Definition: Aggregate.cpp:75