forked from souffle-lang/souffle
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSCCGraph.h
238 lines (202 loc) · 8.37 KB
/
SCCGraph.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
/*
* Souffle - A Datalog Compiler
* Copyright (c) 2021, The Souffle Developers. All rights reserved
* Licensed under the Universal Permissive License v 1.0 as shown at:
* - https://opensource.org/licenses/UPL
* - <souffle root>/licenses/SOUFFLE-UPL.txt
*/
/************************************************************************
*
* @file SCCGraph.h
*
* Defines the class to build the precedence graph,
* compute strongly connected components of the precedence graph, and
* build the strongly connected component graph.
*
***********************************************************************/
#pragma once
#include "GraphUtils.h"
#include "ast/Relation.h"
#include "ast/TranslationUnit.h"
#include "ast/analysis/IOType.h"
#include "ast/analysis/PrecedenceGraph.h"
#include <cstddef>
#include <map>
#include <set>
#include <stack>
#include <string>
#include <vector>
namespace souffle::ast {
class TranslationUnit;
namespace analysis {
/**
* Analysis pass computing the strongly connected component (SCC) graph for the datalog program.
*/
class SCCGraphAnalysis : public Analysis {
public:
static constexpr const char* name = "scc-graph";
SCCGraphAnalysis() : Analysis(name) {}
void run(const TranslationUnit& translationUnit) override;
/** Get the number of SCCs in the graph. */
std::size_t getNumberOfSCCs() const {
return sccToRelation.size();
}
/** Get the SCC of the given relation. */
std::size_t getSCC(const Relation* rel) const {
return relationToScc.at(rel);
}
/** Get all successor SCCs of a given SCC. */
const std::set<std::size_t>& getSuccessorSCCs(const std::size_t scc) const {
return successors.at(scc);
}
/** Get all predecessor SCCs of a given SCC. */
const std::set<std::size_t>& getPredecessorSCCs(const std::size_t scc) const {
return predecessors.at(scc);
}
/** Get all SCCs containing a successor of a given relation. */
std::set<std::size_t> getSuccessorSCCs(const Relation* relation) const {
std::set<std::size_t> successorSccs;
const auto scc = relationToScc.at(relation);
for (const auto& successor : precedenceGraph->graph().successors(relation)) {
const auto successorScc = relationToScc.at(successor);
if (successorScc != scc) {
successorSccs.insert(successorScc);
}
}
return successorSccs;
}
/** Get all SCCs containing a predecessor of a given relation. */
std::set<std::size_t> getPredecessorSCCs(const Relation* relation) const {
std::set<std::size_t> predecessorSccs;
const auto scc = relationToScc.at(relation);
for (const auto& predecessor : precedenceGraph->graph().predecessors(relation)) {
const auto predecessorScc = relationToScc.at(predecessor);
if (predecessorScc != scc) {
predecessorSccs.insert(predecessorScc);
}
}
return predecessorSccs;
}
/** Get all internal relations of a given SCC. */
const RelationSet& getInternalRelations(const std::size_t scc) const {
return sccToRelation.at(scc);
}
/** Get all external output predecessor relations of a given SCC. */
RelationSet getExternalOutputPredecessorRelations(const std::size_t scc) const {
RelationSet externOutPreds;
for (const auto& relation : getInternalRelations(scc)) {
for (const auto& predecessor : precedenceGraph->graph().predecessors(relation)) {
if (relationToScc.at(predecessor) != scc && ioType->isOutput(predecessor)) {
externOutPreds.insert(predecessor);
}
}
}
return externOutPreds;
}
/** Get all external non-output predecessor relations of a given SCC. */
RelationSet getExternalNonOutputPredecessorRelations(const std::size_t scc) const {
RelationSet externNonOutPreds;
for (const auto& relation : getInternalRelations(scc)) {
for (const auto& predecessor : precedenceGraph->graph().predecessors(relation)) {
if (relationToScc.at(predecessor) != scc && !ioType->isOutput(predecessor)) {
externNonOutPreds.insert(predecessor);
}
}
}
return externNonOutPreds;
}
/** Get all external predecessor relations of a given SCC. */
RelationSet getExternalPredecessorRelations(const std::size_t scc) const {
RelationSet externPreds;
for (const auto& relation : getInternalRelations(scc)) {
for (const auto& predecessor : precedenceGraph->graph().predecessors(relation)) {
if (relationToScc.at(predecessor) != scc) {
externPreds.insert(predecessor);
}
}
}
return externPreds;
}
/** Get all internal output relations of a given SCC. */
RelationSet getInternalOutputRelations(const std::size_t scc) const {
RelationSet internOuts;
for (const auto& relation : getInternalRelations(scc)) {
if (ioType->isOutput(relation)) {
internOuts.insert(relation);
}
}
return internOuts;
}
/** Get all internal relations of a given SCC with external successors. */
RelationSet getInternalRelationsWithExternalSuccessors(const std::size_t scc) const {
RelationSet internsWithExternSuccs;
for (const auto& relation : getInternalRelations(scc)) {
for (const auto& successor : precedenceGraph->graph().successors(relation)) {
if (relationToScc.at(successor) != scc) {
internsWithExternSuccs.insert(relation);
break;
}
}
}
return internsWithExternSuccs;
}
/** Get all internal non-output relations of a given SCC with external successors. */
RelationSet getInternalNonOutputRelationsWithExternalSuccessors(const std::size_t scc) const {
RelationSet internNonOutsWithExternSuccs;
for (const auto& relation : getInternalRelations(scc)) {
if (!ioType->isOutput(relation)) {
for (const auto& successor : precedenceGraph->graph().successors(relation)) {
if (relationToScc.at(successor) != scc) {
internNonOutsWithExternSuccs.insert(relation);
break;
}
}
}
}
return internNonOutsWithExternSuccs;
}
/** Get all internal input relations of a given SCC. */
RelationSet getInternalInputRelations(const std::size_t scc) const {
RelationSet internIns;
for (const auto& relation : getInternalRelations(scc)) {
if (ioType->isInput(relation)) {
internIns.insert(relation);
}
}
return internIns;
}
/** Return if the given SCC is recursive. */
bool isRecursive(const std::size_t scc) const {
const RelationSet& sccRelations = sccToRelation.at(scc);
if (sccRelations.size() == 1) {
const Relation* singleRelation = *sccRelations.begin();
if (precedenceGraph->graph().predecessors(singleRelation).count(singleRelation) == 0u) {
return false;
}
}
return true;
}
/** Print the SCC graph in text format. */
void print(std::ostream& os) const override;
/** Print the SCC graph in HTML format. */
void printHTML(std::ostream& os) const;
private:
PrecedenceGraphAnalysis* precedenceGraph = nullptr;
/** Map from node number to SCC number */
std::map<const Relation*, std::size_t> relationToScc;
/** Adjacency lists for the SCC graph */
std::vector<std::set<std::size_t>> successors;
/** Predecessor set for the SCC graph */
std::vector<std::set<std::size_t>> predecessors;
/** Relations contained in a SCC */
std::vector<RelationSet> sccToRelation;
/** Recursive scR method for computing SCC */
void scR(const Relation* relation, std::map<const Relation*, std::size_t>& preOrder, std::size_t& counter,
std::stack<const Relation*>& S, std::stack<const Relation*>& P, std::size_t& numSCCs);
IOTypeAnalysis* ioType = nullptr;
std::string programName;
/** Print the SCC graph to a string. */
void printRaw(std::stringstream& ss) const;
};
} // namespace analysis
} // namespace souffle::ast