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

Apply a grounding so that the witness of a selection aggregate (min/max) can be transferred to the outer scope. More...

#include <GroundWitnesses.h>

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

Public Member Functions

GroundWitnessesTransformerclone () 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

Apply a grounding so that the witness of a selection aggregate (min/max) can be transferred to the outer scope.

Here is an example:

Tallest(student) :- _ = max height : { Student(student, height) }.

student occurs ungrounded in the outer scope, but we can fix this by using the aggregate result to figure out which students satisfy this aggregate.

Tallest(student) :- n = max height : { Student(student0, height) }, Student(student, n).

This transformation is really just syntactic sugar.

Definition at line 49 of file GroundWitnesses.h.

Member Function Documentation

◆ clone()

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

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

Definition at line 62 of file GroundWitnesses.h.

◆ getName()

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

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

Definition at line 58 of file GroundWitnesses.h.

◆ transform()

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

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

Definition at line 31 of file GroundWitnesses.cpp.

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

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