souffle  2.0.2-371-g6315b36
FoldAnonymousRecords.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 FoldAnonymousRecords.cpp
12  *
13  ***********************************************************************/
14 
16 #include "ast/Argument.h"
17 #include "ast/BinaryConstraint.h"
18 #include "ast/BooleanConstraint.h"
19 #include "ast/Clause.h"
20 #include "ast/Literal.h"
21 #include "ast/Program.h"
22 #include "ast/RecordInit.h"
23 #include "ast/TranslationUnit.h"
24 #include "ast/utility/Visitor.h"
28 #include <algorithm>
29 #include <cassert>
30 #include <cstddef>
31 #include <iterator>
32 #include <memory>
33 #include <utility>
34 
35 namespace souffle::ast::transform {
36 
37 bool FoldAnonymousRecords::isValidRecordConstraint(const Literal* literal) {
38  auto constraint = dynamic_cast<const BinaryConstraint*>(literal);
39 
40  if (constraint == nullptr) {
41  return false;
42  }
43 
44  const auto* left = constraint->getLHS();
45  const auto* right = constraint->getRHS();
46 
47  const auto* leftRecord = dynamic_cast<const RecordInit*>(left);
48  const auto* rightRecord = dynamic_cast<const RecordInit*>(right);
49 
50  // Check if arguments are records records.
51  if ((leftRecord == nullptr) || (rightRecord == nullptr)) {
52  return false;
53  }
54 
55  // Check if records are of the same size.
56  if (leftRecord->getChildNodes().size() != rightRecord->getChildNodes().size()) {
57  return false;
58  }
59 
60  // Check if operator is "=" or "!="
61  auto op = constraint->getBaseOperator();
62 
64 }
65 
66 bool FoldAnonymousRecords::containsValidRecordConstraint(const Clause& clause) {
67  bool contains = false;
68  visitDepthFirst(clause, [&](const BinaryConstraint& binary) {
70  });
71  return contains;
72 }
73 
75  VecOwn<Literal> replacedContraint;
76 
77  const auto* left = dynamic_cast<RecordInit*>(constraint.getLHS());
78  const auto* right = dynamic_cast<RecordInit*>(constraint.getRHS());
79  assert(left != nullptr && "Non-record passed to record method");
80  assert(right != nullptr && "Non-record passed to record method");
81 
82  auto leftChildren = left->getArguments();
83  auto rightChildren = right->getArguments();
84 
85  assert(leftChildren.size() == rightChildren.size());
86 
87  // [a, b..] = [c, d...] → a = c, b = d ...
88  for (size_t i = 0; i < leftChildren.size(); ++i) {
89  auto newConstraint = mk<BinaryConstraint>(constraint.getBaseOperator(),
90  souffle::clone(leftChildren[i]), souffle::clone(rightChildren[i]));
91  replacedContraint.push_back(std::move(newConstraint));
92  }
93 
94  // Handle edge case. Empty records.
95  if (leftChildren.size() == 0) {
96  if (isEqConstraint(constraint.getBaseOperator())) {
97  replacedContraint.emplace_back(new BooleanConstraint(true));
98  } else {
99  replacedContraint.emplace_back(new BooleanConstraint(false));
100  }
101  }
102 
103  return replacedContraint;
104 }
105 
106 void FoldAnonymousRecords::transformClause(const Clause& clause, VecOwn<Clause>& newClauses) {
107  // If we have an inequality constraint, we need to create new clauses
108  // At most one inequality constraint will be expanded in a single pass.
109  BinaryConstraint* neqConstraint = nullptr;
110 
111  VecOwn<Literal> newBody;
112  for (auto* literal : clause.getBodyLiterals()) {
113  if (isValidRecordConstraint(literal)) {
114  const BinaryConstraint& constraint = dynamic_cast<BinaryConstraint&>(*literal);
115 
116  // Simple case, [a_0, ..., a_n] = [b_0, ..., b_n]
117  if (isEqConstraint(constraint.getBaseOperator())) {
118  auto transformedLiterals = expandRecordBinaryConstraint(constraint);
119  std::move(std::begin(transformedLiterals), std::end(transformedLiterals),
120  std::back_inserter(newBody));
121 
122  // else if: Case [a_0, ..., a_n] != [b_0, ..., b_n].
123  // track single such case, it will be expanded in the end.
124  } else if (neqConstraint == nullptr) {
125  neqConstraint = dynamic_cast<BinaryConstraint*>(literal);
126 
127  // Else: repeated inequality.
128  } else {
129  newBody.push_back(souffle::clone(literal));
130  }
131 
132  // else, we simply copy the literal.
133  } else {
134  newBody.push_back(souffle::clone(literal));
135  }
136  }
137 
138  // If no inequality: create a single modified clause.
139  if (neqConstraint == nullptr) {
140  auto newClause = souffle::clone(&clause);
141  newClause->setBodyLiterals(std::move(newBody));
142  newClauses.emplace_back(std::move(newClause));
143 
144  // Else: For each pair in negation, we need an extra clause.
145  } else {
146  auto transformedLiterals = expandRecordBinaryConstraint(*neqConstraint);
147 
148  for (auto it = begin(transformedLiterals); it != end(transformedLiterals); ++it) {
149  auto newClause = souffle::clone(&clause);
150  auto copyBody = souffle::clone(newBody);
151  copyBody.push_back(std::move(*it));
152 
153  newClause->setBodyLiterals(std::move(copyBody));
154 
155  newClauses.push_back(std::move(newClause));
156  }
157  }
158 }
159 
160 bool FoldAnonymousRecords::transform(TranslationUnit& translationUnit) {
161  bool changed = false;
162  Program& program = translationUnit.getProgram();
163 
164  VecOwn<Clause> newClauses;
165 
166  for (const auto* clause : program.getClauses()) {
167  if (containsValidRecordConstraint(*clause)) {
168  changed = true;
169  transformClause(*clause, newClauses);
170  } else {
171  newClauses.emplace_back(clause->clone());
172  }
173  }
174 
175  // Update Program.
176  if (changed) {
177  program.setClauses(std::move(newClauses));
178  }
179  return changed;
180 }
181 
182 } // namespace souffle::ast::transform
BinaryConstraintOps.h
TranslationUnit.h
souffle::ast::BooleanConstraint
Boolean constraint class.
Definition: BooleanConstraint.h:45
souffle::ast::BinaryConstraint::getLHS
Argument * getLHS() const
Return left-hand side argument.
Definition: BinaryConstraint.h:59
souffle::ast::BinaryConstraint::getRHS
Argument * getRHS() const
Return right-hand side argument.
Definition: BinaryConstraint.h:64
souffle::contains
bool contains(const C &container, const typename C::value_type &element)
A utility to check generically whether a given element is contained in a given container.
Definition: ContainerUtil.h:75
MiscUtil.h
BooleanConstraint.h
souffle::ast::transform::FoldAnonymousRecords::isValidRecordConstraint
bool isValidRecordConstraint(const Literal *literal)
Determine if binary constraint can be expanded.
Definition: FoldAnonymousRecords.cpp:41
souffle::ast::transform::FoldAnonymousRecords::containsValidRecordConstraint
bool containsValidRecordConstraint(const Clause &)
Determine if the clause contains at least one binary constraint which can be expanded.
Definition: FoldAnonymousRecords.cpp:70
Argument.h
souffle::clone
auto clone(const std::vector< A * > &xs)
Definition: ContainerUtil.h:172
i
size_t i
Definition: json11.h:663
ContainerUtil.h
souffle::negatedConstraintOp
BinaryConstraintOp negatedConstraintOp(const BinaryConstraintOp op)
Negated Constraint Operator Each operator requires a negated operator which is necessary for the expa...
Definition: BinaryConstraintOps.h:297
Literal.h
souffle::ast::BinaryConstraint::getBaseOperator
BinaryConstraintOp getBaseOperator() const
Return binary operator.
Definition: BinaryConstraint.h:69
souffle::ast::transform
Definition: Program.h:45
souffle::isEqConstraint
bool isEqConstraint(const BinaryConstraintOp constraintOp)
Definition: BinaryConstraintOps.h:124
souffle::ast::transform::FoldAnonymousRecords::transform
bool transform(TranslationUnit &translationUnit) override
Definition: FoldAnonymousRecords.cpp:164
souffle::ast::transform::FoldAnonymousRecords::transformClause
void transformClause(const Clause &clause, VecOwn< Clause > &newClauses)
Process a single clause.
Definition: FoldAnonymousRecords.cpp:110
souffle::ast::BinaryConstraint
Binary constraint class.
Definition: BinaryConstraint.h:53
Program.h
Visitor.h
souffle::ast::transform::FoldAnonymousRecords::expandRecordBinaryConstraint
VecOwn< Literal > expandRecordBinaryConstraint(const BinaryConstraint &)
Expand constraint on records position-wise.
Definition: FoldAnonymousRecords.cpp:78
Clause.h
BinaryConstraint.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::VecOwn
std::vector< Own< A > > VecOwn
Definition: ContainerUtil.h:45
RecordInit.h
souffle::ast::RecordInit
Defines a record initialization class.
Definition: RecordInit.h:42
FoldAnonymousRecords.h