ABC: A System for Sequential Synthesis and Verification
 
Loading...
Searching...
No Matches
rrrScheduler.h
Go to the documentation of this file.
1#pragma once
2
3#include <queue>
4#include <random>
5
6#ifdef ABC_USE_PTHREADS
7#include <thread>
8#include <mutex>
9#include <condition_variable>
10#endif
11
12#include "rrrParameter.h"
13#include "rrrUtils.h"
14#include "rrrAbc.h"
15
17
18namespace rrr {
19
20 template <typename Ntk, typename Opt, typename Par>
21 class Scheduler {
22 private:
23 // aliases
24 static constexpr char *pCompress2rs = "balance -l; resub -K 6 -l; rewrite -l; resub -K 6 -N 2 -l; refactor -l; resub -K 8 -l; balance -l; resub -K 8 -N 2 -l; rewrite -l; resub -K 10 -l; rewrite -z -l; resub -K 10 -N 2 -l; balance -l; resub -K 12 -l; refactor -z -l; resub -K 12 -N 2 -l; rewrite -z -l; balance -l";
25
26 // job
27 struct Job;
28 struct CompareJobPointers;
29
30 // pointer to network
31 Ntk *pNtk;
32
33 // parameters
34 int nVerbose;
35 int iSeed;
36 int nFlow;
37 int nJobs;
38 bool fMultiThreading;
39 bool fPartitioning;
40 bool fDeterministic;
41 int nParallelPartitions;
42 bool fOptOnInsert;
43 seconds nTimeout;
44 std::function<double(Ntk *)> CostFunction;
45
46 // data
47 int nCreatedJobs;
48 int nFinishedJobs;
49 time_point timeStart;
50 Par par;
51 std::queue<Job *> qPendingJobs;
52 Opt *pOpt; // used only in case of single thread execution
53 std::vector<std::string> vStatsSummaryKeys;
54 std::map<std::string, int> mStatsSummary;
55 std::vector<std::string> vTimesSummaryKeys;
56 std::map<std::string, double> mTimesSummary;
57#ifdef ABC_USE_PTHREADS
58 bool fTerminate;
59 std::vector<std::thread> vThreads;
60 std::priority_queue<Job *, std::vector<Job *>, CompareJobPointers> qFinishedJobs;
61 std::mutex mutexAbc;
62 std::mutex mutexPendingJobs;
63 std::mutex mutexFinishedJobs;
64 std::mutex mutexPrint;
65 std::condition_variable condPendingJobs;
66 std::condition_variable condFinishedJobs;
67#endif
68
69 // print
70 template <typename... Args>
71 void Print(int nVerboseLevel, std::string prefix, Args... args);
72
73 // time
74 seconds GetRemainingTime() const;
75 double GetElapsedTime() const;
76
77 // abc
78 void CallAbc(Ntk *pNtk_, std::string Command);
79
80 // run jobs
81 void RunJob(Opt &opt, Job *pJob);
82
83 // manage jobs
84 Job *CreateJob(Ntk *pNtk_, int iSeed_, double cost);
85 void OnJobEnd(std::function<void(Job *pJob)> const &func);
86
87 // thread
88#ifdef ABC_USE_PTHREADS
89 void Thread(Parameter const *pPar);
90#endif
91
92 // summary
93 template <typename T>
94 void AddToSummary(std::vector<std::string> &keys, std::map<std::string, T> &m, summary<T> const &result) const;
95
96 public:
97 // constructors
98 Scheduler(Ntk *pNtk, Parameter const *pPar);
100
101 // run
102 void Run();
103 };
104
105 /* {{{ Job */
106
107 template <typename Ntk, typename Opt, typename Par>
108 struct Scheduler<Ntk, Opt, Par>::Job {
109 // data
110 int id;
111 Ntk *pNtk;
112 int iSeed;
114 std::string prefix;
115 double duration;
118
119 // constructor
120 Job(int id, Ntk *pNtk, int iSeed, double cost) :
121 id(id),
122 pNtk(pNtk),
123 iSeed(iSeed),
124 costInitial(cost) {
125 std::stringstream ss;
126 PrintNext(ss, "job", id, ":");
127 prefix = ss.str() + " ";
128 }
129 };
130
131 template <typename Ntk, typename Opt, typename Par>
132 struct Scheduler<Ntk, Opt, Par>::CompareJobPointers {
133 // smaller id comes first in priority_queue
134 bool operator()(Job const *lhs, Job const *rhs) const {
135 return lhs->id > rhs->id;
136 }
137 };
138
139 /* }}} */
140
141 /* {{{ Print */
142
143 template <typename Ntk, typename Opt, typename Par>
144 template<typename... Args>
145 inline void Scheduler<Ntk, Opt, Par>::Print(int nVerboseLevel, std::string prefix, Args... args) {
146 if(nVerbose <= nVerboseLevel) {
147 return;
148 }
149#ifdef ABC_USE_PTHREADS
150 if(fMultiThreading) {
151 {
152 std::unique_lock<std::mutex> l(mutexPrint);
153 std::cout << prefix;
154 PrintNext(std::cout, args...);
155 std::cout << std::endl;
156 }
157 return;
158 }
159#endif
160 std::cout << prefix;
161 PrintNext(std::cout, args...);
162 std::cout << std::endl;
163 }
164
165 /* }}} */
166
167 /* {{{ Time */
168
169 template <typename Ntk, typename Opt, typename Par>
170 inline seconds Scheduler<Ntk, Opt, Par>::GetRemainingTime() const {
171 if(nTimeout == 0) {
172 return 0;
173 }
174 time_point timeCurrent = GetCurrentTime();
175 seconds nRemainingTime = nTimeout - DurationInSeconds(timeStart, timeCurrent);
176 if(nRemainingTime == 0) { // avoid glitch
177 return -1;
178 }
179 return nRemainingTime;
180 }
181
182 template <typename Ntk, typename Opt, typename Par>
183 inline double Scheduler<Ntk, Opt, Par>::GetElapsedTime() const {
184 time_point timeCurrent = GetCurrentTime();
185 return Duration(timeStart, timeCurrent);
186 }
187
188 /* }}} */
189
190 /* {{{ Abc */
191
192 template <typename Ntk, typename Opt, typename Par>
193 inline void Scheduler<Ntk, Opt, Par>::CallAbc(Ntk *pNtk_, std::string Command) {
194#ifdef ABC_USE_PTHREADS
195 if(fMultiThreading) {
196 {
197 std::unique_lock<std::mutex> l(mutexAbc);
198 Abc9Execute(pNtk_, Command);
199 }
200 return;
201 }
202#endif
203 Abc9Execute(pNtk_, Command);
204 }
205
206 /* }}} */
207
208 /* {{{ Run jobs */
209
210 template <typename Ntk, typename Opt, typename Par>
211 void Scheduler<Ntk, Opt, Par>::RunJob(Opt &opt, Job *pJob) {
212 time_point timeStartLocal = GetCurrentTime();
213 opt.AssignNetwork(pJob->pNtk, !fPartitioning); // reuse backend if restarting
214 opt.SetPrintLine([&](std::string str) {
215 Print(-1, pJob->prefix, str);
216 });
217 // start flow
218 switch(nFlow) {
219 case 0:
220 opt.Run(pJob->iSeed, GetRemainingTime());
221 break;
222 case 1: { // transtoch
223 std::mt19937 rng(pJob->iSeed);
224 double cost = pJob->costInitial;
225 double costBest = cost;
226 Ntk best(*(pJob->pNtk));
227 for(int i = 0; i < 10; i++) {
228 if(GetRemainingTime() < 0) {
229 break;
230 }
231 if(i != 0) {
232 CallAbc(pJob->pNtk, "&if -K 6; &mfs; &st");
233 cost = CostFunction(pJob->pNtk);
234 Print(1, pJob->prefix, "hop", i, ":", "cost", "=", cost);
235 }
236 for(int j = 0; true; j++) {
237 if(GetRemainingTime() < 0) {
238 break;
239 }
240 opt.Run(rng(), GetRemainingTime());
241 CallAbc(pJob->pNtk, "&dc2");
242 double costNew = CostFunction(pJob->pNtk);
243 Print(1, pJob->prefix, "ite", j, ":", "cost", "=", costNew);
244 if(costNew < cost) {
245 cost = costNew;
246 } else {
247 break;
248 }
249 }
250 if(cost < costBest) {
251 costBest = cost;
252 best = *(pJob->pNtk);
253 i = 0;
254 }
255 }
256 *(pJob->pNtk) = best;
257 break;
258 }
259 case 2: { // deep
260 std::mt19937 rng(pJob->iSeed);
261 int n = 0;
262 double cost = pJob->costInitial;
263 Ntk best(*(pJob->pNtk));
264 for(int i = 0; i < 1000000; i++) {
265 if(GetRemainingTime() < 0) {
266 break;
267 }
268 // deepsyn
269 int fUseTwo = 0;
270 unsigned Rand = rng();
271 int fDch = Rand & 1;
272 //int fCom = (Rand >> 1) & 3;
273 int fCom = (Rand >> 1) & 1;
274 int fFx = (Rand >> 2) & 1;
275 int KLut = fUseTwo ? 2 + (i % 5) : 3 + (i % 4);
276 std::string pComp;
277 if ( fCom == 3 )
278 pComp = std::string("; &put; ") + pCompress2rs + "; " + pCompress2rs + "; " + pCompress2rs + "; &get";
279 else if ( fCom == 2 )
280 pComp = std::string("; &put; ") + pCompress2rs + "; " + pCompress2rs + "; &get";
281 else if ( fCom == 1 )
282 pComp = std::string("; &put; ") + pCompress2rs + "; &get";
283 else if ( fCom == 0 )
284 pComp = "; &dc2";
285 std::string Command = "&dch";
286 if(fDch)
287 Command += " -f";
288 Command += "; &if -a -K " + std::to_string(KLut) + "; &mfs -e -W 20 -L 20";
289 if(fFx)
290 Command += "; &fx; &st";
291 Command += pComp;
292 CallAbc(pJob->pNtk, Command);
293 Print(1, pJob->prefix, "ite", i, ":", "cost", "=", CostFunction(pJob->pNtk));
294 // rrr
295 for(int j = 0; j < n; j++) {
296 if(GetRemainingTime() < 0) {
297 break;
298 }
299 opt.Run(rng(), GetRemainingTime());
300 if(rng() & 1) {
301 CallAbc(pJob->pNtk, "&dc2");
302 } else {
303 CallAbc(pJob->pNtk, std::string("&put; ") + pCompress2rs + "; &get");
304 }
305 Print(1, pJob->prefix, "rrr", j, ":", "cost", "=", CostFunction(pJob->pNtk));
306 }
307 // eval
308 double costNew = CostFunction(pJob->pNtk);
309 if(costNew < cost) {
310 cost = costNew;
311 best = *(pJob->pNtk);
312 } else {
313 n++;
314 }
315 }
316 *(pJob->pNtk) = best;
317 break;
318 }
319 case 3:
320 opt.Run(pJob->iSeed, GetRemainingTime());
321 CallAbc(pJob->pNtk, std::string("&put; ") + pCompress2rs + "; dc2; &get");
322 break;
323 default:
324 assert(0);
325 }
326 time_point timeEndLocal = GetCurrentTime();
327 pJob->duration = Duration(timeStartLocal, timeEndLocal);
328 pJob->stats = opt.GetStatsSummary();
329 pJob->times = opt.GetTimesSummary();
330 opt.ResetSummary();
331 }
332
333 /* }}} */
334
335 /* {{{ Manage jobs */
336
337 template <typename Ntk, typename Opt, typename Par>
338 typename Scheduler<Ntk, Opt, Par>::Job *Scheduler<Ntk, Opt, Par>::CreateJob(Ntk *pNtk_, int iSeed_, double cost) {
339 Job *pJob = new Job(nCreatedJobs++, pNtk_, iSeed_, cost);
340#ifdef ABC_USE_PTHREADS
341 if(fMultiThreading) {
342 {
343 std::unique_lock<std::mutex> l(mutexPendingJobs);
344 qPendingJobs.push(pJob);
345 condPendingJobs.notify_one();
346 }
347 return pJob;
348 }
349#endif
350 qPendingJobs.push(pJob);
351 return pJob;
352 }
353
354 template <typename Ntk, typename Opt, typename Par>
355 void Scheduler<Ntk, Opt, Par>::OnJobEnd(std::function<void(Job *pJob)> const &func) {
356#ifdef ABC_USE_PTHREADS
357 if(fMultiThreading) {
358 Job *pJob = NULL;
359 {
360 std::unique_lock<std::mutex> l(mutexFinishedJobs);
361 while(qFinishedJobs.empty() || (fDeterministic && qFinishedJobs.top()->id != nFinishedJobs)) {
362 condFinishedJobs.wait(l);
363 }
364 pJob = qFinishedJobs.top();
365 qFinishedJobs.pop();
366 }
367 assert(pJob != NULL);
368 func(pJob);
369 AddToSummary(vStatsSummaryKeys, mStatsSummary, pJob->stats);
370 AddToSummary(vTimesSummaryKeys, mTimesSummary, pJob->times);
371 delete pJob;
372 nFinishedJobs++;
373 return;
374 }
375#endif
376 // if single thread
377 assert(!qPendingJobs.empty());
378 Job *pJob = qPendingJobs.front();
379 qPendingJobs.pop();
380 RunJob(*pOpt, pJob);
381 func(pJob);
382 AddToSummary(vStatsSummaryKeys, mStatsSummary, pJob->stats);
383 AddToSummary(vTimesSummaryKeys, mTimesSummary, pJob->times);
384 delete pJob;
385 nFinishedJobs++;
386 }
387
388 /* }}} */
389
390 /* {{{ Thread */
391
392#ifdef ABC_USE_PTHREADS
393 template <typename Ntk, typename Opt, typename Par>
395 Opt opt(pPar, CostFunction);
396 while(true) {
397 Job *pJob = NULL;
398 {
399 std::unique_lock<std::mutex> l(mutexPendingJobs);
400 while(!fTerminate && qPendingJobs.empty()) {
401 condPendingJobs.wait(l);
402 }
403 if(fTerminate) {
404 assert(qPendingJobs.empty());
405 return;
406 }
407 pJob = qPendingJobs.front();
408 qPendingJobs.pop();
409 }
410 assert(pJob != NULL);
411 RunJob(opt, pJob);
412 {
413 std::unique_lock<std::mutex> l(mutexFinishedJobs);
414 qFinishedJobs.push(pJob);
415 condFinishedJobs.notify_one();
416 }
417 }
418 }
419#endif
420
421 /* }}} */
422
423 /* {{{ Summary */
424
425 template <typename Ntk, typename Opt, typename Par>
426 template <typename T>
427 void Scheduler<Ntk, Opt, Par>::AddToSummary(std::vector<std::string> &keys, std::map<std::string, T> &m, summary<T> const &result) const {
428 std::vector<std::string>::iterator it = keys.begin();
429 for(auto const &entry: result) {
430 if(m.count(entry.first)) {
431 m[entry.first] += entry.second;
432 it = std::find(it, keys.end(), entry.first);
433 assert(it != keys.end());
434 it++;
435 } else {
436 m[entry.first] = entry.second;
437 it = keys.insert(it, entry.first);
438 it++;
439 }
440 }
441 }
442
443 /* }}} */
444
445 /* {{{ Constructors */
446
447 template <typename Ntk, typename Opt, typename Par>
449 pNtk(pNtk),
450 nVerbose(pPar->nSchedulerVerbose),
451 iSeed(pPar->iSeed),
452 nFlow(pPar->nSchedulerFlow),
453 nJobs(pPar->nJobs),
454 fMultiThreading(pPar->nThreads > 1),
455 fPartitioning(pPar->nPartitionSize > 0),
456 fDeterministic(pPar->fDeterministic),
457 nParallelPartitions(pPar->nParallelPartitions),
458 fOptOnInsert(pPar->fOptOnInsert),
459 nTimeout(pPar->nTimeout),
460 nCreatedJobs(0),
461 nFinishedJobs(0),
462 par(pPar),
463 pOpt(NULL) {
464 // prepare cost function
465 CostFunction = [](Ntk *pNtk) {
466 int nTwoInputSize = 0;
467 pNtk->ForEachInt([&](int id) {
468 nTwoInputSize += pNtk->GetNumFanins(id) - 1;
469 });
470 return nTwoInputSize;
471 };
472#ifdef ABC_USE_PTHREADS
473 fTerminate = false;
474 if(fMultiThreading) {
475 vThreads.reserve(pPar->nThreads);
476 for(int i = 0; i < pPar->nThreads; i++) {
477 vThreads.emplace_back(std::bind(&Scheduler::Thread, this, pPar));
478 }
479 return;
480 }
481#endif
482 assert(!fMultiThreading);
483 pOpt = new Opt(pPar, CostFunction);
484 }
485
486 template <typename Ntk, typename Opt, typename Par>
488#ifdef ABC_USE_PTHREADS
489 if(fMultiThreading) {
490 {
491 std::unique_lock<std::mutex> l(mutexPendingJobs);
492 fTerminate = true;
493 condPendingJobs.notify_all();
494 }
495 for(std::thread &t: vThreads) {
496 t.join();
497 }
498 return;
499 }
500#endif
501 delete pOpt;
502 }
503
504 /* }}} */
505
506 /* {{{ Run */
507
508 template <typename Ntk, typename Opt, typename Par>
510 timeStart = GetCurrentTime();
511 double costStart = CostFunction(pNtk);
512 if(fPartitioning) {
513 fDeterministic = false; // it is deterministic anyways as we wait until all jobs finish each round
514 pNtk->Sweep();
515 par.AssignNetwork(pNtk);
516 while(nCreatedJobs < nJobs) {
517 assert(nParallelPartitions > 0);
518 if(nCreatedJobs < nFinishedJobs + nParallelPartitions) {
519 Ntk *pSubNtk = par.Extract(iSeed + nCreatedJobs);
520 if(pSubNtk) {
521 Job *pJob = CreateJob(pSubNtk, iSeed + nCreatedJobs, CostFunction(pSubNtk));
522 Print(1, pJob->prefix, "created ", ":", "i/o", "=", pJob->pNtk->GetNumPis(), "/", pJob->pNtk->GetNumPos(), ",", "node", "=", pJob->pNtk->GetNumInts(), ",", "level", "=", pJob->pNtk->GetNumLevels(), ",", "cost", "=", pJob->costInitial);
523 continue;
524 }
525 }
526 if(nCreatedJobs == nFinishedJobs) {
527 PrintWarning("failed to partition");
528 break;
529 }
530 while(nFinishedJobs < nCreatedJobs) {
531 OnJobEnd([&](Job *pJob) {
532 double cost = CostFunction(pJob->pNtk);
533 Print(1, pJob->prefix, "finished", ":", "i/o", "=", pJob->pNtk->GetNumPis(), "/", pJob->pNtk->GetNumPos(), ",", "node", "=", pJob->pNtk->GetNumInts(), ",", "level", "=", pJob->pNtk->GetNumLevels(), ",", "cost", "=", cost);
534 Print(0, "", "job", pJob->id, "(", nFinishedJobs + 1, "/", nJobs, ")", ":", "i/o", "=", pJob->pNtk->GetNumPis(), "/", pJob->pNtk->GetNumPos(), ",", "node", "=", pJob->pNtk->GetNumInts(), ",", "level", "=", pJob->pNtk->GetNumLevels(), ",", "cost", "=", cost, "(", 100 * (cost - pJob->costInitial) / pJob->costInitial, "%", ")", ",", "duration", "=", pJob->duration, "s", ",", "elapsed", "=", GetElapsedTime(), "s");
535 par.Insert(pJob->pNtk);
536 });
537 }
538 if(fOptOnInsert) {
539 time_point timeStartLocal = GetCurrentTime();
540 CallAbc(pNtk, std::string("&put; ") + pCompress2rs + "; dc2; &get");
541 time_point timeEndLocal = GetCurrentTime();
542 par.AssignNetwork(pNtk);
543 double cost = CostFunction(pNtk);
544 Print(0, "", "c2rs; dc2", ":", std::string(34, ' '), "node", "=", pNtk->GetNumInts(), ",", "level", "=", pNtk->GetNumLevels(), ",", "cost", "=", cost, "(", 100 * (cost - costStart) / costStart, "%", ")", ",", "duration", "=", Duration(timeStartLocal, timeEndLocal), "s", ",", "elapsed", "=", GetElapsedTime(), "s");
545 }
546 }
547 while(nFinishedJobs < nCreatedJobs) {
548 OnJobEnd([&](Job *pJob) {
549 double cost = CostFunction(pJob->pNtk);
550 Print(1, pJob->prefix, "finished", ":", "i/o", "=", pJob->pNtk->GetNumPis(), "/", pJob->pNtk->GetNumPos(), ",", "node", "=", pJob->pNtk->GetNumInts(), ",", "level", "=", pJob->pNtk->GetNumLevels(), ",", "cost", "=", CostFunction(pJob->pNtk));
551 Print(0, "", "job", pJob->id, "(", nFinishedJobs + 1, "/", nJobs, ")", ":", "i/o", "=", pJob->pNtk->GetNumPis(), "/", pJob->pNtk->GetNumPos(), ",", "node", "=", pJob->pNtk->GetNumInts(), ",", "level", "=", pJob->pNtk->GetNumLevels(), ",", "cost", "=", cost, "(", 100 * (cost - pJob->costInitial) / pJob->costInitial, "%", ")", ",", "duration", "=", pJob->duration, "s", ",", "elapsed", "=", GetElapsedTime(), "s");
552 par.Insert(pJob->pNtk);
553 });
554 }
555 if(fOptOnInsert) {
556 CallAbc(pNtk, std::string("&put; ") + pCompress2rs + "; dc2; &get");
557 par.AssignNetwork(pNtk);
558 }
559 } else if(nJobs > 1) {
560 double costBest = costStart;
561 for(int i = 0; i < nJobs; i++) {
562 Ntk *pCopy = new Ntk(*pNtk);
563 CreateJob(pCopy, iSeed + i, costBest);
564 }
565 for(int i = 0; i < nJobs; i++) {
566 OnJobEnd([&](Job *pJob) {
567 double cost = CostFunction(pJob->pNtk);
568 Print(0, "", "job", pJob->id, "(", nFinishedJobs + 1, "/", nJobs, ")", ":", "node", "=", pJob->pNtk->GetNumInts(), ",", "level", "=", pJob->pNtk->GetNumLevels(), ",", "cost", "=", cost, "(", 100 * (cost - pJob->costInitial) / pJob->costInitial, "%", ")", ",", "duration", "=", pJob->duration, "s", ",", "elapsed", "=", GetElapsedTime(), "s");
569 if(cost < costBest) {
570 costBest = cost;
571 *pNtk = *(pJob->pNtk);
572 }
573 delete pJob->pNtk;
574 });
575 }
576 } else {
577 CreateJob(pNtk, iSeed, costStart);
578 OnJobEnd([&](Job *pJob) {
579 double cost = CostFunction(pJob->pNtk);
580 Print(0, "", "job", pJob->id, "(", nFinishedJobs + 1, "/", nJobs, ")", ":", "node", "=", pJob->pNtk->GetNumInts(), ",", "level", "=", pJob->pNtk->GetNumLevels(), ",", "cost", "=", cost, "(", 100 * (cost - pJob->costInitial) / pJob->costInitial, "%", ")", ",", "duration", "=", pJob->duration, "s", ",", "elapsed", "=", GetElapsedTime(), "s");
581 });
582 }
583 double cost = CostFunction(pNtk);
584 double duration = GetElapsedTime();
585 Print(0, "\n", "stats summary", ":");
586 for(std::string key: vStatsSummaryKeys) {
587 Print(0, "\t", SW{30, true}, key, ":", SW{10}, mStatsSummary[key]);
588 }
589 Print(0, "", "runtime summary", ":");
590 for(std::string key: vTimesSummaryKeys) {
591 Print(0, "\t", SW{30, true}, key, ":", mTimesSummary[key], "s", "(", 100 * mTimesSummary[key] / duration, "%", ")");
592 }
593 Print(0, "", "end", ":", "cost", "=", cost, "(", 100 * (cost - costStart) / costStart, "%", ")", ",", "time", "=", duration, "s");
594 }
595
596 /* }}} */
597
598}
599
#define ABC_NAMESPACE_CXX_HEADER_START
#define ABC_NAMESPACE_CXX_HEADER_END
Scheduler(Ntk *pNtk, Parameter const *pPar)
keys
Definition main.h:10
enum keys key
Definition main.h:25
Definition rrr.h:16
int64_t seconds
Definition rrrTypes.h:61
void Abc9Execute(Ntk *pNtk, std::string Command)
Definition rrrAbc.h:69
std::vector< std::pair< std::string, T > > summary
Definition rrrTypes.h:66
void PrintNext(std::ostream &os, T t)
Definition rrrUtils.h:218
std::chrono::time_point< clock_type > time_point
Definition rrrTypes.h:63
struct opt opt
Definition options.h:226
Definition options.h:228
bool operator()(Job const *lhs, Job const *rhs) const
summary< double > times
summary< int > stats
Job(int id, Ntk *pNtk, int iSeed, double cost)
#define assert(ex)
Definition util_old.h:213