souffle  2.0.2-371-g6315b36
SCCGraph.h
Go to the documentation of this file.
1 /*
2  * Souffle - A Datalog Compiler
3  * Copyright (c) 2013, 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 SCCGraph.h
12  *
13  * Defines the class to build the precedence graph,
14  * compute strongly connected components of the precedence graph, and
15  * build the strongly connected component graph.
16  *
17  ***********************************************************************/
18 
19 #pragma once
20 
21 #include "GraphUtils.h"
22 #include "ast/Relation.h"
23 #include "ast/analysis/Analysis.h"
24 #include "ast/analysis/IOType.h"
26 #include <cstddef>
27 #include <map>
28 #include <set>
29 #include <stack>
30 #include <string>
31 #include <vector>
32 
33 namespace souffle::ast {
34 
35 class TranslationUnit;
36 
37 namespace analysis {
38 
39 /**
40  * Analysis pass computing the strongly connected component (SCC) graph for the datalog program.
41  */
42 class SCCGraphAnalysis : public Analysis {
43 public:
44  static constexpr const char* name = "scc-graph";
45 
47 
48  void run(const TranslationUnit& translationUnit) override;
49 
50  /** Get the number of SCCs in the graph. */
51  size_t getNumberOfSCCs() const {
52  return sccToRelation.size();
53  }
54 
55  /** Get the SCC of the given relation. */
56  size_t getSCC(const Relation* rel) const {
57  return relationToScc.at(rel);
58  }
59 
60  /** Get all successor SCCs of a given SCC. */
61  const std::set<size_t>& getSuccessorSCCs(const size_t scc) const {
62  return successors.at(scc);
63  }
64 
65  /** Get all predecessor SCCs of a given SCC. */
66  const std::set<size_t>& getPredecessorSCCs(const size_t scc) const {
67  return predecessors.at(scc);
68  }
69 
70  /** Get all SCCs containing a successor of a given relation. */
71  std::set<size_t> getSuccessorSCCs(const Relation* relation) const {
72  std::set<size_t> successorSccs;
73  const auto scc = relationToScc.at(relation);
74  for (const auto& successor : precedenceGraph->graph().successors(relation)) {
75  const auto successorScc = relationToScc.at(successor);
76  if (successorScc != scc) {
77  successorSccs.insert(successorScc);
78  }
79  }
80  return successorSccs;
81  }
82 
83  /** Get all SCCs containing a predecessor of a given relation. */
84  std::set<size_t> getPredecessorSCCs(const Relation* relation) const {
85  std::set<size_t> predecessorSccs;
86  const auto scc = relationToScc.at(relation);
87  for (const auto& predecessor : precedenceGraph->graph().predecessors(relation)) {
88  const auto predecessorScc = relationToScc.at(predecessor);
89  if (predecessorScc != scc) {
90  predecessorSccs.insert(predecessorScc);
91  }
92  }
93  return predecessorSccs;
94  }
95 
96  /** Get all internal relations of a given SCC. */
97  const std::set<const Relation*>& getInternalRelations(const size_t scc) const {
98  return sccToRelation.at(scc);
99  }
100 
101  /** Get all external output predecessor relations of a given SCC. */
102  std::set<const Relation*> getExternalOutputPredecessorRelations(const size_t scc) const {
103  std::set<const Relation*> externOutPreds;
104  for (const auto& relation : getInternalRelations(scc)) {
105  for (const auto& predecessor : precedenceGraph->graph().predecessors(relation)) {
106  if (relationToScc.at(predecessor) != scc && ioType->isOutput(predecessor)) {
107  externOutPreds.insert(predecessor);
108  }
109  }
110  }
111  return externOutPreds;
112  }
113 
114  /** Get all external non-output predecessor relations of a given SCC. */
115  std::set<const Relation*> getExternalNonOutputPredecessorRelations(const size_t scc) const {
116  std::set<const Relation*> externNonOutPreds;
117  for (const auto& relation : getInternalRelations(scc)) {
118  for (const auto& predecessor : precedenceGraph->graph().predecessors(relation)) {
119  if (relationToScc.at(predecessor) != scc && !ioType->isOutput(predecessor)) {
120  externNonOutPreds.insert(predecessor);
121  }
122  }
123  }
124  return externNonOutPreds;
125  }
126 
127  /** Get all external predecessor relations of a given SCC. */
128  std::set<const Relation*> getExternalPredecessorRelations(const size_t scc) const {
129  std::set<const Relation*> externPreds;
130  for (const auto& relation : getInternalRelations(scc)) {
131  for (const auto& predecessor : precedenceGraph->graph().predecessors(relation)) {
132  if (relationToScc.at(predecessor) != scc) {
133  externPreds.insert(predecessor);
134  }
135  }
136  }
137  return externPreds;
138  }
139 
140  /** Get all internal output relations of a given SCC. */
141  std::set<const Relation*> getInternalOutputRelations(const size_t scc) const {
142  std::set<const Relation*> internOuts;
143  for (const auto& relation : getInternalRelations(scc)) {
144  if (ioType->isOutput(relation)) {
145  internOuts.insert(relation);
146  }
147  }
148  return internOuts;
149  }
150 
151  /** Get all internal relations of a given SCC with external successors. */
152  std::set<const Relation*> getInternalRelationsWithExternalSuccessors(const size_t scc) const {
153  std::set<const Relation*> internsWithExternSuccs;
154  for (const auto& relation : getInternalRelations(scc)) {
155  for (const auto& successor : precedenceGraph->graph().successors(relation)) {
156  if (relationToScc.at(successor) != scc) {
157  internsWithExternSuccs.insert(relation);
158  break;
159  }
160  }
161  }
162  return internsWithExternSuccs;
163  }
164 
165  /** Get all internal non-output relations of a given SCC with external successors. */
166  std::set<const Relation*> getInternalNonOutputRelationsWithExternalSuccessors(const size_t scc) const {
167  std::set<const Relation*> internNonOutsWithExternSuccs;
168  for (const auto& relation : getInternalRelations(scc)) {
169  if (!ioType->isOutput(relation)) {
170  for (const auto& successor : precedenceGraph->graph().successors(relation)) {
171  if (relationToScc.at(successor) != scc) {
172  internNonOutsWithExternSuccs.insert(relation);
173  break;
174  }
175  }
176  }
177  }
178  return internNonOutsWithExternSuccs;
179  }
180 
181  /** Get all internal input relations of a given SCC. */
182  std::set<const Relation*> getInternalInputRelations(const size_t scc) const {
183  std::set<const Relation*> internIns;
184  for (const auto& relation : getInternalRelations(scc)) {
185  if (ioType->isInput(relation)) {
186  internIns.insert(relation);
187  }
188  }
189  return internIns;
190  }
191 
192  /** Return if the given SCC is recursive. */
193  bool isRecursive(const size_t scc) const {
194  const std::set<const Relation*>& sccRelations = sccToRelation.at(scc);
195  if (sccRelations.size() == 1) {
196  const Relation* singleRelation = *sccRelations.begin();
197  if (precedenceGraph->graph().predecessors(singleRelation).count(singleRelation) == 0u) {
198  return false;
199  }
200  }
201  return true;
202  }
203 
204  /** Print the SCC graph. */
205  void print(std::ostream& os) const override;
206 
207 private:
209 
210  /** Map from node number to SCC number */
211  std::map<const Relation*, size_t> relationToScc;
212 
213  /** Adjacency lists for the SCC graph */
214  std::vector<std::set<size_t>> successors;
215 
216  /** Predecessor set for the SCC graph */
217  std::vector<std::set<size_t>> predecessors;
218 
219  /** Relations contained in a SCC */
220  std::vector<std::set<const Relation*>> sccToRelation;
221 
222  /** Recursive scR method for computing SCC */
223  void scR(const Relation* relation, std::map<const Relation*, size_t>& preOrder, size_t& counter,
224  std::stack<const Relation*>& S, std::stack<const Relation*>& P, size_t& numSCCs);
225 
226  IOTypeAnalysis* ioType = nullptr;
227 };
228 
229 } // namespace analysis
230 } // namespace souffle::ast
souffle::ast::analysis::SCCGraphAnalysis::SCCGraphAnalysis
SCCGraphAnalysis()
Definition: SCCGraph.h:54
souffle::ast::analysis::SCCGraphAnalysis::getExternalOutputPredecessorRelations
std::set< const Relation * > getExternalOutputPredecessorRelations(const size_t scc) const
Get all external output predecessor relations of a given SCC.
Definition: SCCGraph.h:110
souffle::ast::analysis::Analysis::Analysis
Analysis(std::string identifier)
Definition: Analysis.h:40
IOType.h
souffle::ast::analysis::SCCGraphAnalysis::getInternalNonOutputRelationsWithExternalSuccessors
std::set< const Relation * > getInternalNonOutputRelationsWithExternalSuccessors(const size_t scc) const
Get all internal non-output relations of a given SCC with external successors.
Definition: SCCGraph.h:174
souffle::ast::analysis::IOTypeAnalysis
Definition: IOType.h:39
souffle::ast::analysis::IOTypeAnalysis::isOutput
bool isOutput(const Relation *relation) const
Definition: IOType.h:53
S
#define S(x)
Definition: test.h:179
souffle::ast::analysis::SCCGraphAnalysis::run
void run(const TranslationUnit &translationUnit) override
run analysis for a Ast translation unit
Definition: SCCGraph.cpp:44
souffle::ast::analysis::SCCGraphAnalysis::getSCC
size_t getSCC(const Relation *rel) const
Get the SCC of the given relation.
Definition: SCCGraph.h:64
relation
Relation & relation
Definition: Reader.h:130
souffle::ast::analysis::SCCGraphAnalysis::print
void print(std::ostream &os) const override
Print the SCC graph.
Definition: SCCGraph.cpp:124
souffle::ast::Relation
Defines a relation with a name, attributes, qualifiers, and internal representation.
Definition: Relation.h:49
souffle::ast::analysis::PrecedenceGraphAnalysis::graph
const Graph< const Relation *, NameComparison > & graph() const
Definition: PrecedenceGraph.h:54
souffle::ast::analysis::SCCGraphAnalysis::scR
void scR(const Relation *relation, std::map< const Relation *, size_t > &preOrder, size_t &counter, std::stack< const Relation * > &S, std::stack< const Relation * > &P, size_t &numSCCs)
Recursive scR method for computing SCC.
Definition: SCCGraph.cpp:95
Relation.h
souffle::ast::analysis::SCCGraphAnalysis::predecessors
std::vector< std::set< size_t > > predecessors
Predecessor set for the SCC graph.
Definition: SCCGraph.h:225
souffle::ast::analysis::SCCGraphAnalysis::precedenceGraph
PrecedenceGraphAnalysis * precedenceGraph
Definition: SCCGraph.h:216
souffle::ast::analysis::SCCGraphAnalysis::successors
std::vector< std::set< size_t > > successors
Adjacency lists for the SCC graph.
Definition: SCCGraph.h:222
souffle::ast::analysis::SCCGraphAnalysis::getExternalNonOutputPredecessorRelations
std::set< const Relation * > getExternalNonOutputPredecessorRelations(const size_t scc) const
Get all external non-output predecessor relations of a given SCC.
Definition: SCCGraph.h:123
souffle::ast::analysis::SCCGraphAnalysis::getInternalInputRelations
std::set< const Relation * > getInternalInputRelations(const size_t scc) const
Get all internal input relations of a given SCC.
Definition: SCCGraph.h:190
souffle::ast::analysis::SCCGraphAnalysis::isRecursive
bool isRecursive(const size_t scc) const
Return if the given SCC is recursive.
Definition: SCCGraph.h:201
souffle::ast::analysis::SCCGraphAnalysis::name
static constexpr const char * name
Definition: SCCGraph.h:52
souffle::ast::analysis::SCCGraphAnalysis::sccToRelation
std::vector< std::set< const Relation * > > sccToRelation
Relations contained in a SCC.
Definition: SCCGraph.h:228
GraphUtils.h
souffle::ast::analysis::SCCGraphAnalysis::getNumberOfSCCs
size_t getNumberOfSCCs() const
Get the number of SCCs in the graph.
Definition: SCCGraph.h:59
souffle::ast::analysis::IOTypeAnalysis::isInput
bool isInput(const Relation *relation) const
Definition: IOType.h:49
souffle::ast::analysis::SCCGraphAnalysis::getInternalOutputRelations
std::set< const Relation * > getInternalOutputRelations(const size_t scc) const
Get all internal output relations of a given SCC.
Definition: SCCGraph.h:149
souffle::ast::analysis::PrecedenceGraphAnalysis
Analysis pass computing the precedence graph of the relations of the datalog progam.
Definition: PrecedenceGraph.h:43
souffle::ast::analysis::SCCGraphAnalysis::relationToScc
std::map< const Relation *, size_t > relationToScc
Map from node number to SCC number.
Definition: SCCGraph.h:219
souffle::ast::analysis::SCCGraphAnalysis::getInternalRelationsWithExternalSuccessors
std::set< const Relation * > getInternalRelationsWithExternalSuccessors(const size_t scc) const
Get all internal relations of a given SCC with external successors.
Definition: SCCGraph.h:160
souffle::ast::analysis::SCCGraphAnalysis::getSuccessorSCCs
const std::set< size_t > & getSuccessorSCCs(const size_t scc) const
Get all successor SCCs of a given SCC.
Definition: SCCGraph.h:69
souffle::ast::analysis::SCCGraphAnalysis::getPredecessorSCCs
const std::set< size_t > & getPredecessorSCCs(const size_t scc) const
Get all predecessor SCCs of a given SCC.
Definition: SCCGraph.h:74
PrecedenceGraph.h
souffle::ast
Definition: Aggregator.h:35
souffle::ast::analysis::SCCGraphAnalysis::getExternalPredecessorRelations
std::set< const Relation * > getExternalPredecessorRelations(const size_t scc) const
Get all external predecessor relations of a given SCC.
Definition: SCCGraph.h:136
rel
void rel(size_t limit, bool showLimit=true)
Definition: Tui.h:1086
Analysis.h
souffle::ast::analysis::SCCGraphAnalysis::getInternalRelations
const std::set< const Relation * > & getInternalRelations(const size_t scc) const
Get all internal relations of a given SCC.
Definition: SCCGraph.h:105
souffle::ast::analysis::SCCGraphAnalysis::ioType
IOTypeAnalysis * ioType
Definition: SCCGraph.h:234