ABC: A System for Sequential Synthesis and Verification
 
Loading...
Searching...
No Matches
rrrPartitioner.h
Go to the documentation of this file.
1#pragma once
2
3#include <utility>
4#include <map>
5#include <tuple>
6#include <random>
7
8#include "rrrParameter.h"
9#include "rrrUtils.h"
10
12
13namespace rrr {
14
15 template <typename Ntk>
17 private:
18 // pointer to network
19 Ntk *pNtk;
20
21 // parameters
22 int nVerbose;
23 int nPartitionSize;
24 int nPartitionSizeMin;
25 std::string strVerbosePrefix;
26
27 // data
28 std::map<Ntk *, std::tuple<std::set<int>, std::vector<int>, std::vector<bool>, std::vector<int>>> mSubNtk2Io;
29 std::set<int> sBlocked;
30 std::vector<bool> vFailed;
31
32 // print
33 template<typename... Args>
34 void Print(int nVerboseLevel, Args... args);
35
36 // subroutines
37 void GetIo(std::set<int> const &sNodes, std::set<int> &sInputs, std::set<int> &sOutputs);
38 std::set<int> GetFanouts(std::set<int> const &sNodes, std::set<int> const &sOutputs);
39 std::set<int> GetUnblockedNeighborsAndInners(int id, int nRadius);
40 Ntk *ExtractDisjoint(int id);
41
42 public:
43 // constructors
44 Partitioner(Parameter const *pPar);
45 void AssignNetwork(Ntk *pNtk);
46
47 // APIs
48 Ntk *Extract(int iSeed);
49 void Insert(Ntk *pSubNtk);
50 };
51
52 /* {{{ Print */
53
54 template <typename Ntk>
55 template <typename... Args>
56 inline void Partitioner<Ntk>::Print(int nVerboseLevel, Args... args) {
57 if(nVerbose > nVerboseLevel) {
58 std::cout << strVerbosePrefix;
59 for(int i = 0; i < nVerboseLevel; i++) {
60 std::cout << "\t";
61 }
62 PrintNext(std::cout, args...);
63 std::cout << std::endl;
64 }
65 }
66
67 /* }}} */
68
69 /* {{{ Subroutines */
70
71 template <typename Ntk>
72 void Partitioner<Ntk>::GetIo(std::set<int> const &sNodes, std::set<int> &sInputs, std::set<int> &sOutputs) {
73 sInputs.clear();
74 sOutputs.clear();
75 for(int id: sNodes) {
76 pNtk->ForEachFanin(id, [&](int fi) {
77 if(!sNodes.count(fi)) {
78 sInputs.insert(fi);
79 }
80 });
81 bool fOutput = false;
82 pNtk->ForEachFanout(id, true, [&](int fo) {
83 if(!sNodes.count(fo)) {
84 fOutput = true;
85 }
86 });
87 if(fOutput) {
88 sOutputs.insert(id);
89 }
90 }
91 }
92
93 template <typename Ntk>
94 std::set<int> Partitioner<Ntk>::GetFanouts(std::set<int> const &sNodes, std::set<int> const &sOutputs) {
95 std::set<int> sFanouts;
96 for(int id: sOutputs) {
97 pNtk->ForEachFanout(id, false, [&](int fo) {
98 if(!sNodes.count(fo)) {
99 sFanouts.insert(fo);
100 }
101 });
102 }
103 return sFanouts;
104 }
105
106 template <typename Ntk>
107 std::set<int> Partitioner<Ntk>::GetUnblockedNeighborsAndInners(int id, int nRadius) {
108 // return empty set on failure
109 // get neighbors
110 std::vector<int> vNodes = pNtk->GetNeighbors(id, false, nRadius);
111 vNodes.push_back(id);
112 std::set<int> sNodes(vNodes.begin(), vNodes.end());
113 Print(2, "radius", NS(), nRadius, ":", "size =", int_size(sNodes));
114 // remove nodes that are already blocked
115 for(std::set<int>::iterator it = sNodes.begin(); it != sNodes.end();) {
116 if(sBlocked.count(*it)) {
117 it = sNodes.erase(it);
118 } else {
119 it++;
120 }
121 }
122 Print(2, "unblocked:", "size =", int_size(sNodes));
123 if(int_size(sNodes) > nPartitionSize) {
124 // too large
125 return std::set<int>();
126 }
127 // get tentative partition IO
128 std::set<int> sInputs, sOutputs;
129 GetIo(sNodes, sInputs, sOutputs);
130 Print(3, "nodes:", sNodes);
131 Print(3, "inputs:", sInputs);
132 Print(3, "outputs:", sOutputs);
133 // include inner nodes
134 std::set<int> sFanouts = GetFanouts(sNodes, sOutputs);
135 std::vector<int> vInners = pNtk->GetInners(sFanouts, sInputs);
136 while(!vInners.empty()) {
137 Print(2, "inner size =", int_size(vInners));
138 // check overlap
139 for(int id: vInners) {
140 if(sBlocked.count(id)) {
141 // overlapped
142 return std::set<int>();
143 }
144 }
145 // expand
146 sNodes.insert(vInners.begin(), vInners.end());
147 Print(2, "expanded:", "size =", int_size(sNodes));
148 if(int_size(sNodes) > nPartitionSize) {
149 // too large
150 return std::set<int>();
151 }
152 GetIo(sNodes, sInputs, sOutputs);
153 Print(3, "nodes:", sNodes);
154 Print(3, "inputs:", sInputs);
155 Print(3, "outputs:", sOutputs);
156 // recompute fanouts
157 sFanouts = GetFanouts(sNodes, sOutputs);
158 vInners = pNtk->GetInners(sFanouts, sInputs);
159 }
160 return sNodes;
161 }
162
163 template <typename Ntk>
164 Ntk *Partitioner<Ntk>::ExtractDisjoint(int id) {
165 // collect neighbor
166 assert(!sBlocked.count(id));
167 int nRadius = 1;
168 std::set<int> sNodes = GetUnblockedNeighborsAndInners(id, nRadius);
169 Print(1, "radius", NS(), nRadius, ":", "size =", int_size(sNodes));
170 if(sNodes.empty()) {
171 return NULL;
172 }
173 std::set<int> sNodesNew = GetUnblockedNeighborsAndInners(id, nRadius + 1);
174 Print(1, "radius", NS(), nRadius + 1, ":", "size =", int_size(sNodesNew));
175 // gradually increase radius until it hits partition size limit
176 while(!sNodesNew.empty()) {
177 if(int_size(sNodes) == int_size(sNodesNew)) { // likely already maximum
178 break;
179 }
180 sNodes = sNodesNew;
181 nRadius++;
182 sNodesNew = GetUnblockedNeighborsAndInners(id, nRadius + 1);
183 Print(1, "radius", NS(), nRadius + 1, ":", "size =", int_size(sNodesNew));
184 }
185 if(int_size(sNodes) < nPartitionSizeMin) {
186 // too small
187 return NULL;
188 }
189 std::set<int> sInputs, sOutputs;
190 GetIo(sNodes, sInputs, sOutputs);
191 /* fall back method by removing TFI of outputs reachable to inputs
192 if(!vInners.empty()) {
193 for(int id: sOutputs) {
194 if(!sNodes.count(id)) { // already removed
195 continue;
196 }
197 std::set<int> sFanouts = GetFanouts(sNodes, sOutputs);
198 if(pNtk->IsReachable(sFanouts, sInputs)) {
199 Print(2, "node", id, "is reachable");
200 sNodes.erase(id);
201 pNtk->ForEachTfiEnd(id, sInputs, [&](int fi) {
202 int r = sNodes.erase(fi);
203 assert(r);
204 });
205 Print(1, "shrinking:", "size =", int_size(sNodes));
206 if(int_size(sNodes) < nPartitionSizeMin) {
207 // too small
208 return NULL;
209 }
210 // recompute inputs
211 sInputs.clear();
212 for(int id: sNodes) {
213 pNtk->ForEachFanin(id, [&](int fi) {
214 if(!sNodes.count(fi)) {
215 sInputs.insert(fi);
216 }
217 });
218 }
219 Print(3, "nodes:", sNodes);
220 Print(3, "inputs:", sInputs);
221 }
222 }
223 // recompute outputs
224 for(std::set<int>::iterator it = sOutputs.begin(); it != sOutputs.end();) {
225 if(!sNodes.count(*it)) {
226 it = sOutputs.erase(it);
227 } else {
228 it++;
229 }
230 }
231 Print(3, "new outputs:", sOutputs);
232 }
233 */
234 // ensure outputs of both partitions do not reach each other's inputs at the same time
235 for(auto const &entry: mSubNtk2Io) {
236 if(!pNtk->IsReachable(sOutputs, std::get<1>(entry.second))) {
237 continue;
238 }
239 if(!pNtk->IsReachable(std::get<3>(entry.second), sInputs)) {
240 continue;
241 }
242 // if(nVerbose) {
243 // std::cout << "POTENTIAL LOOPS" << std::endl;
244 // }
245 return NULL;
246 }
247 assert(int_size(sNodes) <= nPartitionSize);
248 assert(int_size(sNodes) >= nPartitionSizeMin);
249 // extract by inputs, internals, and outputs (no checks needed in ntk side)
250 std::vector<int> vInputs(sInputs.begin(), sInputs.end());
251 std::vector<int> vOutputs(sOutputs.begin(), sOutputs.end());
252 Ntk *pSubNtk = pNtk->Extract(sNodes, vInputs, vOutputs);
253 // return subntk to be modified, while remember IOs
254 for(int id: sNodes) {
255 sBlocked.insert(id);
256 }
257 mSubNtk2Io.emplace(pSubNtk, std::make_tuple(std::move(sNodes), std::move(vInputs), std::vector<bool>(vInputs.size()), std::move(vOutputs)));
258 return pSubNtk;
259 }
260
261 /* }}} */
262
263 /* {{{ Constructors */
264
265 template <typename Ntk>
267 nVerbose(pPar->nPartitionerVerbose),
268 nPartitionSize(pPar->nPartitionSize),
269 nPartitionSizeMin(pPar->nPartitionSizeMin) {
270 }
271
272 template <typename Ntk>
274 pNtk = pNtk_;
275 assert(mSubNtk2Io.empty());
276 assert(sBlocked.empty());
277 vFailed.clear();
278 }
279
280 /* }}} */
281
282 /* {{{ APIs */
283
284 template <typename Ntk>
286 // pick a center node from candidates that do not belong to any other ongoing partitions
287 vFailed.resize(pNtk->GetNumNodes());
288 std::mt19937 rng(iSeed);
289 std::vector<int> vInts = pNtk->GetInts();
290 std::shuffle(vInts.begin(), vInts.end(), rng);
291 for(int i = 0; i < int_size(vInts); i++) {
292 int id = vInts[i];
293 if(vFailed[id]) {
294 continue;
295 }
296 if(!sBlocked.count(id)) {
297 Print(0, "try partitioning with node", id, "(", i, "/", int_size(vInts), ")");
298 Ntk *pSubNtk = ExtractDisjoint(id);
299 if(pSubNtk) {
300 return pSubNtk;
301 }
302 }
303 vFailed[id] = true;
304 }
305 return NULL;
306 }
307
308 template <typename Ntk>
309 void Partitioner<Ntk>::Insert(Ntk *pSubNtk) {
310 for(int i: std::get<0>(mSubNtk2Io[pSubNtk])) {
311 sBlocked.erase(i);
312 }
313 std::pair<std::vector<int>, std::vector<bool>> vNewSignals = pNtk->Insert(pSubNtk, std::get<1>(mSubNtk2Io[pSubNtk]), std::get<2>(mSubNtk2Io[pSubNtk]), std::get<3>(mSubNtk2Io[pSubNtk]));
314 std::vector<int> &vOldOutputs = std::get<3>(mSubNtk2Io[pSubNtk]);
315 std::vector<int> &vNewOutputs = vNewSignals.first;
316 std::vector<bool> &vNewCompls = vNewSignals.second;
317 // need to remap updated outputs that are used as inputs in other partitions
318 std::map<int, int> mOutput2Idx;
319 for(int idx = 0; idx < int_size(vOldOutputs); idx++) {
320 mOutput2Idx[vOldOutputs[idx]] = idx;
321 }
322 for(auto &entry: mSubNtk2Io) {
323 if(entry.first != pSubNtk) {
324 std::vector<int> &vInputs = std::get<1>(entry.second);
325 std::vector<bool> &vCompls = std::get<2>(entry.second);
326 for(int i = 0; i < int_size(vInputs); i++) {
327 if(mOutput2Idx.count(vInputs[i])) {
328 int idx = mOutput2Idx[vInputs[i]];
329 vInputs[i] = vNewOutputs[idx];
330 vCompls[i] = vCompls[i] ^ vNewCompls[idx];
331 }
332 }
333 }
334 }
335 delete pSubNtk;
336 mSubNtk2Io.erase(pSubNtk);
337 vFailed.clear(); // clear, there isn't really a way to track
338 }
339
340 /* }}} */
341
342}
343
#define ABC_NAMESPACE_CXX_HEADER_START
#define ABC_NAMESPACE_CXX_HEADER_END
void AssignNetwork(Ntk *pNtk)
Partitioner(Parameter const *pPar)
void Insert(Ntk *pSubNtk)
Ntk * Extract(int iSeed)
Definition rrr.h:16
void PrintNext(std::ostream &os, T t)
Definition rrrUtils.h:218
#define assert(ex)
Definition util_old.h:213