update rrr

This commit is contained in:
MyskYko 2025-03-05 14:44:12 -08:00
parent b9b8ff47e3
commit 8005405ed7
18 changed files with 2448 additions and 571 deletions

View File

@ -1808,7 +1808,7 @@ extern Gia_Man_t * Gia_ManTransductionBdd( Gia_Man_t * pGia, int nType,
extern Gia_Man_t * Gia_ManTransductionTt( Gia_Man_t * pGia, int nType, int fMspf, int nRandom, int nSortType, int nPiShuffle, int nParameter, int fLevel, Gia_Man_t * pExdc, int fNewLine, int nVerbose );
/*=== giaRrr.cpp ===========================================================*/
extern Gia_Man_t * Gia_ManRrr( Gia_Man_t *pGia, int iSeed, int nWords, int nTimeout, int nSchedulerVerbose, int nOptimizerVerbose, int nAnalyzerVerbose, int nSimulatorVerbose, int nSatSolverVerbose, int fUseBddCspf, int fUseBddMspf, int nConflictLimit, int nSortType, int nOptimizerFlow, int nSchedulerFlow );
extern Gia_Man_t * Gia_ManRrr( Gia_Man_t *pGia, int iSeed, int nWords, int nTimeout, int nSchedulerVerbose, int nPartitionerVerbose, int nOptimizerVerbose, int nAnalyzerVerbose, int nSimulatorVerbose, int nSatSolverVerbose, int fUseBddCspf, int fUseBddMspf, int nConflictLimit, int nSortType, int nOptimizerFlow, int nSchedulerFlow, int nDistance, int nRestarts, int nThreads, int nWindowSize, int fDeterministic );
/*=== giaCTas.c ===========================================================*/
typedef struct Tas_Man_t_ Tas_Man_t;

View File

@ -5,14 +5,15 @@
ABC_NAMESPACE_IMPL_START
Gia_Man_t *Gia_ManRrr(Gia_Man_t *pGia, int iSeed, int nWords, int nTimeout, int nSchedulerVerbose, int nOptimizerVerbose, int nAnalyzerVerbose, int nSimulatorVerbose, int nSatSolverVerbose, int fUseBddCspf, int fUseBddMspf, int nConflictLimit, int nSortType, int nOptimizerFlow, int nSchedulerFlow) {
Gia_Man_t *Gia_ManRrr(Gia_Man_t *pGia, int iSeed, int nWords, int nTimeout, int nSchedulerVerbose, int nPartitionerVerbose, int nOptimizerVerbose, int nAnalyzerVerbose, int nSimulatorVerbose, int nSatSolverVerbose, int fUseBddCspf, int fUseBddMspf, int nConflictLimit, int nSortType, int nOptimizerFlow, int nSchedulerFlow, int nDistance, int nRestarts, int nThreads, int nWindowSize, int fDeterministic) {
rrr::AndNetwork ntk;
ntk.Read<Gia_Man_t>(pGia, rrr::GiaReader<rrr::AndNetwork>);
ntk.Read(pGia, rrr::GiaReader<rrr::AndNetwork>);
rrr::Parameter Par;
Par.iSeed = iSeed;
Par.nWords = nWords;
Par.nTimeout = nTimeout;
Par.nSchedulerVerbose = nSchedulerVerbose;
Par.nPartitionerVerbose = nPartitionerVerbose;
Par.nOptimizerVerbose = nOptimizerVerbose;
Par.nAnalyzerVerbose = nAnalyzerVerbose;
Par.nSimulatorVerbose = nSimulatorVerbose;
@ -23,6 +24,11 @@ Gia_Man_t *Gia_ManRrr(Gia_Man_t *pGia, int iSeed, int nWords, int nTimeout, int
Par.nSortType = nSortType;
Par.nOptimizerFlow = nOptimizerFlow;
Par.nSchedulerFlow = nSchedulerFlow;
Par.nDistance = nDistance;
Par.nRestarts = nRestarts;
Par.nThreads = nThreads;
Par.nWindowSize = nWindowSize;
Par.fDeterministic = fDeterministic;
rrr::Perform(&ntk, &Par);
Gia_Man_t *pNew = rrr::CreateGia(&ntk);
return pNew;

View File

@ -45457,9 +45457,9 @@ int Abc_CommandAbc9Rrr( Abc_Frame_t * pAbc, int argc, char ** argv )
{
Gia_Man_t *pNew;
int c;
int iSeed = 0, nWords = 10, nTimeout = 0, nSchedulerVerbose = 1, nOptimizerVerbose = 0, nAnalyzerVerbose = 0, nSimulatorVerbose = 0, nSatSolverVerbose = 0, fUseBddCspf = 0, fUseBddMspf = 0, nConflictLimit = 0, nSortType = 12, nOptimizerFlow = 0, nSchedulerFlow = 0;
int iSeed = 0, nWords = 10, nTimeout = 0, nSchedulerVerbose = 1, nPartitionerVerbose = 0, nOptimizerVerbose = 0, nAnalyzerVerbose = 0, nSimulatorVerbose = 0, nSatSolverVerbose = 0, fUseBddCspf = 0, fUseBddMspf = 0, nConflictLimit = 0, nSortType = 12, nOptimizerFlow = 0, nSchedulerFlow = 0, nDistance = 0, nRestarts = 0, nThreads = 1, nWindowSize = 0, fDeterministic = 1;
Extra_UtilGetoptReset();
while ( ( c = Extra_UtilGetopt( argc, argv, "XYRWTCGSOAPQabh" ) ) != EOF )
while ( ( c = Extra_UtilGetopt( argc, argv, "XYNJKDRWTCGVPOAQSabdh" ) ) != EOF )
{
switch ( c )
{
@ -45471,6 +45471,22 @@ int Abc_CommandAbc9Rrr( Abc_Frame_t * pAbc, int argc, char ** argv )
nSchedulerFlow = atoi(argv[globalUtilOptind]);
globalUtilOptind++;
break;
case 'N':
nRestarts = atoi(argv[globalUtilOptind]);
globalUtilOptind++;
break;
case 'J':
nThreads = atoi(argv[globalUtilOptind]);
globalUtilOptind++;
break;
case 'K':
nWindowSize = atoi(argv[globalUtilOptind]);
globalUtilOptind++;
break;
case 'D':
nDistance = atoi(argv[globalUtilOptind]);
globalUtilOptind++;
break;
case 'R':
iSeed = atoi(argv[globalUtilOptind]);
globalUtilOptind++;
@ -45491,10 +45507,14 @@ int Abc_CommandAbc9Rrr( Abc_Frame_t * pAbc, int argc, char ** argv )
nSortType = atoi(argv[globalUtilOptind]);
globalUtilOptind++;
break;
case 'S':
case 'V':
nSchedulerVerbose = atoi(argv[globalUtilOptind]);
globalUtilOptind++;
break;
case 'P':
nPartitionerVerbose = atoi(argv[globalUtilOptind]);
globalUtilOptind++;
break;
case 'O':
nOptimizerVerbose = atoi(argv[globalUtilOptind]);
globalUtilOptind++;
@ -45503,11 +45523,11 @@ int Abc_CommandAbc9Rrr( Abc_Frame_t * pAbc, int argc, char ** argv )
nAnalyzerVerbose = atoi(argv[globalUtilOptind]);
globalUtilOptind++;
break;
case 'P':
case 'Q':
nSimulatorVerbose = atoi(argv[globalUtilOptind]);
globalUtilOptind++;
break;
case 'Q':
case 'S':
nSatSolverVerbose = atoi(argv[globalUtilOptind]);
globalUtilOptind++;
break;
@ -45517,6 +45537,9 @@ int Abc_CommandAbc9Rrr( Abc_Frame_t * pAbc, int argc, char ** argv )
case 'b':
fUseBddMspf ^= 1;
break;
case 'd':
fDeterministic ^= 1;
break;
case 'h':
goto usage;
default:
@ -45535,14 +45558,14 @@ int Abc_CommandAbc9Rrr( Abc_Frame_t * pAbc, int argc, char ** argv )
return 1;
}
pNew = Gia_ManRrr( pAbc->pGia, iSeed, nWords, nTimeout, nSchedulerVerbose, nOptimizerVerbose, nAnalyzerVerbose, nSimulatorVerbose, nSatSolverVerbose, fUseBddCspf, fUseBddMspf, nConflictLimit, nSortType, nOptimizerFlow, nSchedulerFlow );
pNew = Gia_ManRrr( pAbc->pGia, iSeed, nWords, nTimeout, nSchedulerVerbose, nPartitionerVerbose, nOptimizerVerbose, nAnalyzerVerbose, nSimulatorVerbose, nSatSolverVerbose, fUseBddCspf, fUseBddMspf, nConflictLimit, nSortType, nOptimizerFlow, nSchedulerFlow, nDistance, nRestarts, nThreads, nWindowSize, fDeterministic );
Abc_FrameUpdateGia( pAbc, pNew );
return 0;
usage:
Abc_Print( -2, "usage: rrr [-XYRWTCGSOAPQ num] [-abh]\n" );
Abc_Print( -2, "usage: rrr [-XYNJKDRWTCGVPOAQS num] [-abdh]\n" );
Abc_Print( -2, "\t perform optimization\n" );
Abc_Print( -2, "\t-X num : method [default = %d]\n", nOptimizerFlow );
Abc_Print( -2, "\t 0: single-add resub\n" );
@ -45552,18 +45575,24 @@ usage:
Abc_Print( -2, "\t 0: apply method once\n" );
Abc_Print( -2, "\t 1: iterate like transtoch\n" );
Abc_Print( -2, "\t 2: iterate like deepsyn\n" );
Abc_Print( -2, "\t-N num : number of restarts or windows [default = %d]\n", nRestarts );
Abc_Print( -2, "\t-J num : number of threads [default = %d]\n", nThreads );
Abc_Print( -2, "\t-K num : window size (0 = no partitioning) [default = %d]\n", nWindowSize );
Abc_Print( -2, "\t-D num : distance between nodes (0 = no limit) [default = %d]\n", nDistance );
Abc_Print( -2, "\t-R num : random number generator seed [default = %d]\n", iSeed );
Abc_Print( -2, "\t-W num : number of simulation words [default = %d]\n", nWords );
Abc_Print( -2, "\t-T num : timeout in seconds (0 = no timeout) [default = %d]\n", nTimeout );
Abc_Print( -2, "\t-C num : conflict limit [default = %d]\n", nConflictLimit );
Abc_Print( -2, "\t-C num : conflict limit (0 = no limit) [default = %d]\n", nConflictLimit );
Abc_Print( -2, "\t-G num : fanin cost function [default = %d]\n", nSortType );
Abc_Print( -2, "\t-S num : scheduler verbosity level [default = %d]\n", nSchedulerVerbose );
Abc_Print( -2, "\t-V num : scheduler verbosity level [default = %d]\n", nSchedulerVerbose );
Abc_Print( -2, "\t-P num : partitioner verbosity level [default = %d]\n", nPartitionerVerbose );
Abc_Print( -2, "\t-O num : optimizer verbosity level [default = %d]\n", nOptimizerVerbose );
Abc_Print( -2, "\t-A num : analyzer verbosity level [default = %d]\n", nAnalyzerVerbose );
Abc_Print( -2, "\t-P num : simulator verbosity level [default = %d]\n", nSimulatorVerbose );
Abc_Print( -2, "\t-Q num : SAT solver verbosity level [default = %d]\n", nSatSolverVerbose );
Abc_Print( -2, "\t-Q num : simulator verbosity level [default = %d]\n", nSimulatorVerbose );
Abc_Print( -2, "\t-S num : SAT solver verbosity level [default = %d]\n", nSatSolverVerbose );
Abc_Print( -2, "\t-a : use BDD-based analyzer (CSPF) [default = %s]\n", fUseBddCspf? "yes": "no" );
Abc_Print( -2, "\t-b : use BDD-based analyzer (MSPF) [default = %s]\n", fUseBddMspf? "yes": "no" );
Abc_Print( -2, "\t-d : ensure deterministic execution [default = %s]\n", fDeterministic? "yes": "no" );
Abc_Print( -2, "\t-h : print the command usage\n");
return 1;
}

View File

@ -1,15 +1,11 @@
#pragma once
#include <cassert>
#include "rrrParameter.h"
#include "rrrTypes.h"
#include "rrrAndNetwork.h"
#include "rrrScheduler.h"
#include "rrrOptimizer.h"
#include "rrrAnalyzer.h"
#include "rrrBddAnalyzer.h"
#include "rrrBddMspfAnalyzer.h"
#include "rrrAnalyzer.h"
#include "rrrSatSolver.h"
#include "rrrSimulator.h"

View File

@ -1,11 +1,11 @@
#pragma once
#include <string>
#include "aig/gia/gia.h"
#include "base/main/main.h"
#include "base/cmd/cmd.h"
#include "rrrUtils.h"
ABC_NAMESPACE_CXX_HEADER_START
namespace rrr {

View File

@ -1,8 +1,7 @@
#pragma once
#include <iostream>
#include "rrrParameter.h"
#include "rrrUtils.h"
ABC_NAMESPACE_CXX_HEADER_START
@ -23,7 +22,7 @@ namespace rrr {
public:
// constructors
Analyzer(Ntk *pNtk, Parameter const *pPar);
Analyzer(Parameter const *pPar);
void UpdateNetwork(Ntk *pNtk_, bool fSame);
// checks
@ -34,11 +33,11 @@ namespace rrr {
/* {{{ Constructors */
template <typename Ntk, typename Sim, typename Sol>
Analyzer<Ntk, Sim, Sol>::Analyzer(Ntk *pNtk, Parameter const *pPar) :
pNtk(pNtk),
Analyzer<Ntk, Sim, Sol>::Analyzer(Parameter const *pPar) :
pNtk(NULL),
nVerbose(pPar->nAnalyzerVerbose),
sim(pNtk, pPar),
sol(pNtk, pPar) {
sim(pPar),
sol(pPar) {
}
template <typename Ntk, typename Sim, typename Sol>

View File

@ -1,17 +1,12 @@
#pragma once
#include <iostream>
#include <vector>
#include <utility>
#include <list>
#include <set>
#include <initializer_list>
#include <string>
#include <functional>
#include <map>
#include <algorithm>
#include <limits>
#include "rrrParameter.h"
#include "rrrTypes.h"
#include "rrrUtils.h"
ABC_NAMESPACE_CXX_HEADER_START
@ -57,8 +52,9 @@ namespace rrr {
// other private functions
int CreateNode();
void SortInts(itr it);
void StartTraversal();
unsigned StartTraversal(int n = 1);
void EndTraversal();
void ForEachTfiRec(int id, std::function<void(int)> const &f);
void TakenAction(Action const &action) const;
public:
@ -71,8 +67,8 @@ namespace rrr {
void Clear();
void Reserve(int nReserve);
int AddPi();
int AddPo(int id, bool c);
int AddAnd(int id0, int id1, bool c0, bool c1);
int AddPo(int id, bool c);
template <typename Ntk, typename Reader>
void Read(Ntk *pFrom, Reader &reader);
@ -84,6 +80,7 @@ namespace rrr {
int GetNumPos() const;
int GetConst0() const;
int GetPi(int idx) const;
int GetPo(int idx) const;
std::vector<int> GetPis() const;
std::vector<int> GetInts() const;
std::vector<int> GetPisInts() const;
@ -104,17 +101,31 @@ namespace rrr {
bool GetCompl(int id, int idx) const;
int FindFanin(int id, int fi) const;
bool IsReconvergent(int id);
std::vector<int> GetNeighbors(int id, bool fPis, int nHops);
template <template <typename...> typename Container, typename ... Ts, template <typename...> typename Container2, typename ... Ts2>
bool IsReachable(Container<Ts...> const &srcs, Container2<Ts2...> const &dsts);
template <template <typename...> typename Container, typename ... Ts, template <typename...> typename Container2, typename ... Ts2>
std::vector<int> GetInners(Container<Ts...> const &srcs, Container2<Ts2...> const &dsts);
// network traversal
void ForEachPi(std::function<void(int)> const &func) const;
void ForEachInt(std::function<void(int)> const &func) const;
void ForEachIntReverse(std::function<void(int)> const &func) const;
void ForEachPiInt(std::function<void(int)> const &func) const;
void ForEachPo(std::function<void(int)> const &func) const;
void ForEachPoDriver(std::function<void(int, bool)> const &func) const;
void ForEachFanin(int id, std::function<void(int, bool)> const &func) const;
void ForEachFaninIdx(int id, std::function<void(int, int, bool)> const &func) const; // func(fi, c, index of fi in fanin list of id)
void ForEachFanout(int id, bool fPos, std::function<void(int, bool)> const &func) const;
void ForEachFanoutRidx(int id, bool fPos, std::function<void(int, bool, int)> const &func) const; // func(fo, c, index of id in fanin list of fo)
template <typename Func>
void ForEachPoDriver(Func const &func) const;
template <typename Func>
void ForEachFanin(int id, Func const &func) const;
template <typename Func>
void ForEachFaninIdx(int id, Func const &func) const; // func(index of fi in fanin list of id, fi[, c])
template <typename Func>
void ForEachFanout(int id, bool fPos, Func const &func) const;
template <typename Func>
void ForEachFanoutRidx(int id, bool fPos, Func const &func) const; // func(fo[, c], index of id in fanin list of fo)
void ForEachTfi(int id, bool fPis, std::function<void(int)> const &func);
template <template <typename...> typename Container, typename ... Ts>
void ForEachTfiEnd(int id, Container<Ts...> const &ends, std::function<void(int)> const &func);
void ForEachTfo(int id, bool fPos, std::function<void(int)> const &func);
void ForEachTfoReverse(int id, bool fPos, std::function<void(int)> const &func);
void ForEachTfoUpdate(int id, bool fPos, std::function<bool(int)> const &func);
@ -123,19 +134,25 @@ namespace rrr {
template <template <typename...> typename Container, typename ... Ts>
void ForEachTfosUpdate(Container<Ts...> const &ids, bool fPos, std::function<bool(int)> const &func);
// Actions
// extraction
template <template <typename...> typename Container, typename ... Ts>
AndNetwork *Extract(Container<Ts...> const &ids, std::vector<int> const &vInputs, std::vector<int> const &vOutputs);
// actions
void RemoveFanin(int id, int idx);
void RemoveUnused(int id, bool fRecursive = false);
void RemoveUnused(int id, bool fRecursive = false, bool fSweeping = false);
void RemoveBuffer(int id);
void RemoveConst(int id);
void AddFanin(int id, int fi, bool c);
void TrivialCollapse(int id);
void TrivialDecompose(int id);
void SortFanins(int id, std::function<bool(int, bool, int, bool)> const &cost);
template <typename Func>
void SortFanins(int id, Func const &cost);
std::pair<std::vector<int>, std::vector<bool>> Insert(AndNetwork *pNtk, std::vector<int> const &vInputs, std::vector<bool> const &vCompls, std::vector<int> const &vOutputs);
// Network cleanup
void Propagate(int id = -1); // all nodes unless specified
void Sweep(bool fPropagate);
void Sweep(bool fPropagate = true);
// save & load
int Save(int slot = -1); // slot is assigned automatically unless specified
@ -153,12 +170,12 @@ namespace rrr {
// TODO: reuse already allocated but dead nodes? or perform garbage collection?
vvFaninEdges.emplace_back();
vRefs.push_back(0);
assert(nNodes != std::numeric_limits<int>::max());
assert(!check_int_max(nNodes));
return nNodes++;
}
void AndNetwork::SortInts(itr it) {
ForEachFanin(*it, [&](int fi, bool c) {
ForEachFanin(*it, [&](int fi) {
itr it2 = std::find(it, lInts.end(), fi);
if(it2 != lInts.end()) {
lInts.erase(it2);
@ -168,18 +185,38 @@ namespace rrr {
});
}
inline void AndNetwork::StartTraversal() {
inline unsigned AndNetwork::StartTraversal(int n) {
assert(!fLockTrav);
fLockTrav = true;
do {
for(int i = 0; i < n; i++) {
iTrav++;
if(iTrav == 0) {
vTrav.clear();
break;
}
}
} while(iTrav == 0);
vTrav.resize(nNodes);
iTrav++;
assert(iTrav != 0); //TODO: handle this overflow
return iTrav - n + 1;
}
inline void AndNetwork::EndTraversal() {
assert(fLockTrav);
fLockTrav = false;
}
void AndNetwork::ForEachTfiRec(int id, std::function<void(int)> const &func) {
for(int fi_edge: vvFaninEdges[id]) {
int fi = Edge2Node(fi_edge);
if(vTrav[fi] == iTrav) {
continue;
}
func(fi);
vTrav[fi] = iTrav;
ForEachTfiRec(fi, func);
}
}
inline void AndNetwork::TakenAction(Action const &action) const {
for(Callback const &callback: vCallbacks) {
@ -259,7 +296,7 @@ namespace rrr {
vPis.push_back(nNodes);
vvFaninEdges.emplace_back();
vRefs.push_back(0);
assert(nNodes != std::numeric_limits<int>::max());
assert(!check_int_max(nNodes));
return nNodes++;
}
@ -273,7 +310,7 @@ namespace rrr {
vRefs[id1]++;
vvFaninEdges.emplace_back(std::initializer_list<int>({Node2Edge(id0, c0), Node2Edge(id1, c1)}));
vRefs.push_back(0);
assert(nNodes != std::numeric_limits<int>::max());
assert(!check_int_max(nNodes));
return nNodes++;
}
@ -283,7 +320,7 @@ namespace rrr {
vRefs[id]++;
vvFaninEdges.emplace_back(std::initializer_list<int>({Node2Edge(id, c)}));
vRefs.push_back(0);
assert(nNodes != std::numeric_limits<int>::max());
assert(!check_int_max(nNodes));
return nNodes++;
}
@ -306,18 +343,15 @@ namespace rrr {
}
inline int AndNetwork::GetNumPis() const {
assert(vPis.size() <= (std::vector<int>::size_type)std::numeric_limits<int>::max());
return vPis.size();
return int_size(vPis);
}
inline int AndNetwork::GetNumInts() const {
assert(lInts.size() <= (std::vector<int>::size_type)std::numeric_limits<int>::max());
return lInts.size();
return int_size(lInts);
}
inline int AndNetwork::GetNumPos() const {
assert(vPos.size() <= (std::vector<int>::size_type)std::numeric_limits<int>::max());
return vPos.size();
return int_size(vPos);
}
inline int AndNetwork::GetConst0() const {
@ -328,6 +362,10 @@ namespace rrr {
return vPis[idx];
}
inline int AndNetwork::GetPo(int idx) const {
return vPos[idx];
}
inline std::vector<int> AndNetwork::GetPis() const {
return vPis;
}
@ -381,39 +419,38 @@ namespace rrr {
return false;
}
int AndNetwork::GetPiIndex(int id) const {
inline int AndNetwork::GetPiIndex(int id) const {
assert(IsPi(id));
assert(vPis.size() <= (std::vector<int>::size_type)std::numeric_limits<int>::max());
assert(check_int_size(vPis));
std::vector<int>::const_iterator it = std::find(vPis.begin(), vPis.end(), id);
assert(it != vPis.end());
return std::distance(vPis.begin(), it);
}
int AndNetwork::GetIntIndex(int id) const {
inline int AndNetwork::GetIntIndex(int id) const {
assert(check_int_size(lInts));
int index = 0;
citr it = lInts.begin();
for(; it != lInts.end(); it++) {
if(*it == id) {
break;
}
assert(index < (std::vector<int>::size_type)std::numeric_limits<int>::max());
index++;
}
assert(it != lInts.end());
return index;
}
int AndNetwork::GetPoIndex(int id) const {
inline int AndNetwork::GetPoIndex(int id) const {
assert(IsPo(id));
assert(vPos.size() <= (std::vector<int>::size_type)std::numeric_limits<int>::max());
assert(check_int_size(vPos));
std::vector<int>::const_iterator it = std::find(vPos.begin(), vPos.end(), id);
assert(it != vPos.end());
return std::distance(vPos.begin(), it);
}
inline int AndNetwork::GetNumFanins(int id) const {
//assert(vvFaninEdges[id].size() <= (std::vector<int>::size_type)std::numeric_limits<int>::max());
return vvFaninEdges[id].size();
return int_size(vvFaninEdges[id]);
}
inline int AndNetwork::GetNumFanouts(int id) const {
@ -441,16 +478,14 @@ namespace rrr {
if(GetNumFanouts(id) <= 1) {
return false;
}
StartTraversal();
unsigned iTravStart = iTrav;
ForEachFanout(id, false, [&](int fo, bool c) {
vTrav[fo] = iTrav;
iTrav++;
assert(iTrav != 0); //TODO: handle this overflow
unsigned iTravStart = StartTraversal(GetNumFanouts(id));
int idx = 0;
ForEachFanout(id, false, [&](int fo) {
vTrav[fo] = iTravStart + idx;
idx++;
});
iTrav--;
if(iTrav <= iTravStart) {
// less than one fanouts excluding POs
if(idx <= 1) {
// less than two fanouts excluding POs
EndTraversal();
return false;
}
@ -475,6 +510,161 @@ namespace rrr {
return false;
}
inline std::vector<int> AndNetwork::GetNeighbors(int id, bool fPis, int nHops) {
StartTraversal();
vTrav[id] = iTrav;
std::vector<int> vPrevs, vNexts;
vNexts.push_back(id);
for(int i = 0; i < nHops; i++) {
vPrevs.swap(vNexts);
for(int id: vPrevs) {
ForEachFanin(id, [&](int fi) {
if(vTrav[fi] != iTrav) {
vNexts.push_back(fi);
vTrav[fi] = iTrav;
}
});
ForEachFanout(id, false, [&](int fo) {
if(vTrav[fo] != iTrav) {
vNexts.push_back(fo);
vTrav[fo] = iTrav;
}
});
}
vPrevs.clear();
}
vTrav[id] = 0;
std::vector<int> v;
if(fPis) {
ForEachPiInt([&](int id) {
if(vTrav[id] == iTrav) {
v.push_back(id);
}
});
} else {
ForEachInt([&](int id) {
if(vTrav[id] == iTrav) {
v.push_back(id);
}
});
}
EndTraversal();
return v;
}
template <template <typename...> typename Container, typename ... Ts, template <typename...> typename Container2, typename ... Ts2>
inline bool AndNetwork::IsReachable(Container<Ts...> const &srcs, Container2<Ts2...> const &dsts) {
if(srcs.empty() || dsts.empty()) {
return false;
}
// mark destinations
unsigned iTravStart = StartTraversal(2);
for(int id: dsts) {
vTrav[id] = iTravStart;
}
// mark sources
for(int id: srcs) {
if(vTrav[id] == iTravStart) {
EndTraversal();
return true;
}
vTrav[id] = iTrav;
}
// find the first source
citr it = lInts.begin();
while(vTrav[*it] != iTrav && it != lInts.end()) {
it++;
}
// check if sources are reachable to destinations
for(; it != lInts.end(); it++) {
if(vTrav[*it] == iTrav) {
continue;
}
for(int fi_edge: vvFaninEdges[*it]) {
if(vTrav[Edge2Node(fi_edge)] == iTrav) {
if(vTrav[*it] == iTravStart) {
EndTraversal();
return true;
}
vTrav[*it] = iTrav;
break;
}
}
}
for(int po: vPos) {
if(vTrav[po] == iTrav) {
continue;
}
if(vTrav[GetFanin(po, 0)] == iTrav) {
if(vTrav[po] == iTravStart) {
EndTraversal();
return true;
}
vTrav[po] = iTrav;
}
}
EndTraversal();
return false;
}
template <template <typename...> typename Container, typename ... Ts, template <typename...> typename Container2, typename ... Ts2>
inline std::vector<int> AndNetwork::GetInners(Container<Ts...> const &srcs, Container2<Ts2...> const &dsts) {
// this includes sources and destinations that are connected
if(srcs.empty() || dsts.empty()) {
return std::vector<int>();
}
unsigned iTravStart = StartTraversal(4);
unsigned iDst = iTravStart;
unsigned iTfo = iTravStart + 1;
unsigned iInner = iTravStart + 2;
// mark destinations (to prevent nodes between destinations to sources being included)
for(int id: dsts) {
vTrav[id] = iDst;
}
// mark TFOs of sources until destinations, which will be marekd as inner
for(int id: srcs) {
if(vTrav[id] == iDst) {
vTrav[id] = iInner;
} else {
vTrav[id] = iTfo;
}
}
citr it = lInts.begin();
while(vTrav[*it] != iTfo && it != lInts.end()) {
it++;
}
for(; it != lInts.end(); it++) {
if(vTrav[*it] >= iTfo) { // TFO or inner
continue;
}
for(int fi_edge: vvFaninEdges[*it]) {
if(vTrav[Edge2Node(fi_edge)] == iTfo) {
if(vTrav[*it] == iDst) {
vTrav[*it] = iInner;
} else {
vTrav[*it] = iTfo;
}
break;
}
}
}
// traverse TFIs of connected destinations
std::vector<int> vInners;
for(int id: dsts) {
if(vTrav[id] == iInner) {
vInners.push_back(id);
vTrav[id] = iTrav;
ForEachTfiRec(id, [&](int fi) {
if(vTrav[fi] == iTfo || vTrav[fi] == iInner) {
vInners.push_back(fi);
}
});
}
}
EndTraversal();
return vInners;
}
/* }}} */
/* {{{ Network traversal */
@ -497,49 +687,89 @@ namespace rrr {
}
}
inline void AndNetwork::ForEachPiInt(std::function<void(int)> const &func) const {
for(int pi: vPis) {
func(pi);
}
for(int id: lInts) {
func(id);
}
}
inline void AndNetwork::ForEachPo(std::function<void(int)> const &func) const {
for(int po: vPos) {
func(po);
}
}
inline void AndNetwork::ForEachPoDriver(std::function<void(int, bool)> const &func) const {
template <typename Func>
inline void AndNetwork::ForEachPoDriver(Func const &func) const {
static_assert(is_invokable<Func, int>::value || is_invokable<Func, int, bool>::value, "for each edge function format error");
for(int po: vPos) {
func(GetFanin(po, 0), GetCompl(po, 0));
}
}
inline void AndNetwork::ForEachFanin(int id, std::function<void(int, bool)> const &func) const {
for(int fi_edge: vvFaninEdges[id]) {
func(Edge2Node(fi_edge), EdgeIsCompl(fi_edge));
if constexpr(is_invokable<Func, int>::value) {
func(GetFanin(po, 0));
} else if constexpr(is_invokable<Func, int, bool>::value) {
func(GetFanin(po, 0), GetCompl(po, 0));
}
}
}
inline void AndNetwork::ForEachFaninIdx(int id, std::function<void(int, int, bool)> const &func) const {
template <typename Func>
inline void AndNetwork::ForEachFanin(int id, Func const &func) const {
static_assert(is_invokable<Func, int>::value || is_invokable<Func, int, bool>::value, "for each edge function format error");
for(int fi_edge: vvFaninEdges[id]) {
if constexpr(is_invokable<Func, int>::value) {
func(Edge2Node(fi_edge));
} else if constexpr(is_invokable<Func, int, bool>::value) {
func(Edge2Node(fi_edge), EdgeIsCompl(fi_edge));
}
}
}
template <typename Func>
inline void AndNetwork::ForEachFaninIdx(int id, Func const &func) const {
static_assert(is_invokable<Func, int, int>::value || is_invokable<Func, int, int, bool>::value, "for each edge function format error");
for(int idx = 0; idx < GetNumFanins(id); idx++) {
func(idx, GetFanin(id, idx), GetCompl(id, idx));
if constexpr(is_invokable<Func, int, int>::value) {
func(idx, GetFanin(id, idx));
} else if constexpr(is_invokable<Func, int, int, bool>::value) {
func(idx, GetFanin(id, idx), GetCompl(id, idx));
}
}
}
inline void AndNetwork::ForEachFanout(int id, bool fPos, std::function<void(int, bool)> const &func) const {
template <typename Func>
inline void AndNetwork::ForEachFanout(int id, bool fPos, Func const &func) const {
static_assert(is_invokable<Func, int>::value || is_invokable<Func, int, bool>::value, "for each edge function format error");
if(vRefs[id] == 0) {
return;
}
citr it = std::find(lInts.begin(), lInts.end(), id);
assert(it != lInts.end());
it++;
citr it = lInts.begin();
if(IsInt(id)) {
it = std::find(it, lInts.end(), id);
assert(it != lInts.end());
it++;
}
int nRefs = vRefs[id];
for(; nRefs != 0 && it != lInts.end(); it++) {
int idx = FindFanin(*it, id);
if(idx >= 0) {
func(*it, GetCompl(*it, idx));
if constexpr(is_invokable<Func, int>::value) {
func(*it);
} else if constexpr(is_invokable<Func, int, bool>::value) {
func(*it, GetCompl(*it, idx));
}
nRefs--;
}
}
if(fPos && nRefs != 0) {
for(int po: vPos) {
if(GetFanin(po, 0) == id) {
func(po, GetCompl(po, 0));
if constexpr(is_invokable<Func, int>::value) {
func(po);
} else if constexpr(is_invokable<Func, int, bool>::value) {
func(po, GetCompl(po, 0));
}
nRefs--;
if(nRefs == 0) {
break;
@ -549,26 +779,39 @@ namespace rrr {
}
assert(!fPos || nRefs == 0);
}
inline void AndNetwork::ForEachFanoutRidx(int id, bool fPos, std::function<void(int, bool, int)> const &func) const {
template <typename Func>
inline void AndNetwork::ForEachFanoutRidx(int id, bool fPos, Func const &func) const {
static_assert(is_invokable<Func, int, int>::value || is_invokable<Func, int, bool, int>::value, "for each edge function format error");
if(vRefs[id] == 0) {
return;
}
citr it = std::find(lInts.begin(), lInts.end(), id);
assert(it != lInts.end());
it++;
citr it = lInts.begin();
if(IsInt(id)) {
it = std::find(it, lInts.end(), id);
assert(it != lInts.end());
it++;
}
int nRefs = vRefs[id];
for(; nRefs != 0 && it != lInts.end(); it++) {
int idx = FindFanin(*it, id);
if(idx >= 0) {
func(*it, GetCompl(*it, idx), idx);
if constexpr(is_invokable<Func, int, int>::value) {
func(*it, idx);
} else if constexpr(is_invokable<Func, int, bool, int>::value) {
func(*it, GetCompl(*it, idx), idx);
}
nRefs--;
}
}
if(fPos && nRefs != 0) {
for(int po: vPos) {
if(GetFanin(po, 0) == id) {
func(po, GetCompl(po, 0), 0);
if constexpr(is_invokable<Func, int, int>::value) {
func(po, 0);
} else if constexpr(is_invokable<Func, int, bool, int>::value) {
func(po, GetCompl(po, 0), 0);
}
nRefs--;
if(nRefs == 0) {
break;
@ -578,7 +821,30 @@ namespace rrr {
}
assert(!fPos || nRefs == 0);
}
inline void AndNetwork::ForEachTfi(int id, bool fPis, std::function<void(int)> const &func) {
// this does not include id itself
StartTraversal();
if(!fPis) {
for(int pi: vPis) {
vTrav[pi] = iTrav;
}
}
ForEachTfiRec(id, func);
EndTraversal();
}
template <template <typename...> typename Container, typename ... Ts>
inline void AndNetwork::ForEachTfiEnd(int id, Container<Ts...> const &ends, std::function<void(int)> const &func) {
// this does not include id itself
StartTraversal();
for(int end: ends) {
vTrav[end] = iTrav;
}
ForEachTfiRec(id, func);
EndTraversal();
}
inline void AndNetwork::ForEachTfo(int id, bool fPos, std::function<void(int)> const &func) {
// this does not include id itself
if(vRefs[id] == 0) {
@ -763,6 +1029,44 @@ namespace rrr {
EndTraversal();
}
/* }}} */
/* {{{ Extraction */
template <template <typename...> typename Container, typename ... Ts>
AndNetwork *AndNetwork::Extract(Container<Ts...> const &ids, std::vector<int> const &vInputs, std::vector<int> const &vOutputs) {
AndNetwork *pNtk = new AndNetwork;
pNtk->Reserve(int_size(vInputs) + int_size(ids) + int_size(vOutputs));
std::map<int, int> m;
m[GetConst0()] = pNtk->GetConst0();
for(int id: vInputs) {
m[id] = pNtk->AddPi();
}
StartTraversal();
for(int id: ids) {
vTrav[id] = iTrav;
}
ForEachInt([&](int id) {
if(vTrav[id] == iTrav) {
m[id] = pNtk->CreateNode();
pNtk->lInts.push_back(m[id]);
pNtk->sInts.insert(m[id]);
pNtk->vvFaninEdges[m[id]].resize(GetNumFanins(id));
ForEachFaninIdx(id, [&](int idx, int fi, bool c) {
assert(m.count(fi));
pNtk->vvFaninEdges[m[id]][idx] = pNtk->Node2Edge(m[fi], c);
pNtk->vRefs[m[fi]]++;
});
}
});
EndTraversal();
for(int id: vOutputs) {
assert(m.count(id));
pNtk->AddPo(m[id], false);
}
return pNtk;
}
/* }}} */
/* {{{ Actions */
@ -781,24 +1085,26 @@ namespace rrr {
TakenAction(action);
}
void AndNetwork::RemoveUnused(int id, bool fRecursive) {
void AndNetwork::RemoveUnused(int id, bool fRecursive, bool fSweeping) {
assert(vRefs[id] == 0);
Action action;
action.type = REMOVE_UNUSED;
action.id = id;
ForEachFanin(id, [&](int fi, bool c) {
ForEachFanin(id, [&](int fi) {
action.vFanins.push_back(fi);
vRefs[fi]--;
});
vvFaninEdges[id].clear();
itr it = std::find(lInts.begin(), lInts.end(), id);
lInts.erase(it);
if(!fSweeping) {
itr it = std::find(lInts.begin(), lInts.end(), id);
lInts.erase(it);
}
sInts.erase(id);
TakenAction(action);
if(fRecursive) {
for(int fi: action.vFanins) {
if(vRefs[fi] == 0) {
RemoveUnused(fi, true);
if(vRefs[fi] == 0 && IsInt(fi)) {
RemoveUnused(fi, fRecursive, fSweeping);
}
}
}
@ -885,7 +1191,7 @@ namespace rrr {
});
// remove node
vRefs[id] = 0;
ForEachFanin(id, [&](int fi, bool c) {
ForEachFanin(id, [&](int fi) {
vRefs[fi]--;
action.vFanins.push_back(fi);
});
@ -904,7 +1210,7 @@ namespace rrr {
Action action;
action.type = ADD_FANIN;
action.id = id;
action.idx = vvFaninEdges[id].size();
action.idx = GetNumFanins(id);
action.fi = fi;
action.c = c;
itr it = std::find(lInts.begin(), lInts.end(), id);
@ -934,7 +1240,7 @@ namespace rrr {
std::vector<int>::iterator it = vvFaninEdges[id].begin() + idx;
it = vvFaninEdges[id].erase(it);
vvFaninEdges[id].insert(it, vvFaninEdges[fi].begin(), vvFaninEdges[fi].end());
ForEachFanin(fi, [&](int fi, bool c) {
ForEachFanin(fi, [&](int fi) {
action.vFanins.push_back(fi);
});
// remove collapsed fanin
@ -954,7 +1260,7 @@ namespace rrr {
Action action;
action.type = TRIVIAL_DECOMPOSE;
action.id = id;
action.idx = vvFaninEdges[id].size() - 2;
action.idx = GetNumFanins(id) - 2;
int new_fi = CreateNode();
action.fi = new_fi;
int fi_edge1 = vvFaninEdges[id].back();
@ -974,10 +1280,16 @@ namespace rrr {
}
}
void AndNetwork::SortFanins(int id, std::function<bool(int, bool, int, bool)> const &comp) {
template <typename Func>
void AndNetwork::SortFanins(int id, Func const &comp) {
static_assert(is_invokable<Func, int, int>::value || is_invokable<Func, int, bool, int, bool>::value, "fanin cost function format error");
std::vector<int> vFaninEdges = vvFaninEdges[id];
std::sort(vvFaninEdges[id].begin(), vvFaninEdges[id].end(), [&](int i, int j) {
return comp(Edge2Node(i), EdgeIsCompl(i), Edge2Node(j), EdgeIsCompl(j));
if constexpr(is_invokable<Func, int, int>::value) {
return comp(Edge2Node(i), Edge2Node(j));
} else if constexpr(is_invokable<Func, int, bool, int, bool>::value) {
return comp(Edge2Node(i), EdgeIsCompl(i), Edge2Node(j), EdgeIsCompl(j));
}
});
if(vFaninEdges == vvFaninEdges[id]) {
return;
@ -985,7 +1297,7 @@ namespace rrr {
Action action;
action.type = SORT_FANINS;
action.id = id;
assert(vFaninEdges.size() <= (std::vector<int>::size_type)std::numeric_limits<int>::max());
assert(check_int_size(vFaninEdges));
for(int fanin_edge: vvFaninEdges[id]) {
std::vector<int>::const_iterator it = std::find(vFaninEdges.begin(), vFaninEdges.end(), fanin_edge);
action.vIndices.push_back(std::distance(vFaninEdges.cbegin(), it));
@ -993,6 +1305,79 @@ namespace rrr {
TakenAction(action);
}
std::pair<std::vector<int>, std::vector<bool>> AndNetwork::Insert(AndNetwork *pNtk, std::vector<int> const &vInputs, std::vector<bool> const &vCompls, std::vector<int> const &vOutputs) {
Reserve(nNodes + pNtk->GetNumInts());
std::map<int, std::pair<int, bool>> m;
m[pNtk->GetConst0()] = std::make_pair(GetConst0(), false);
assert(pNtk->GetNumPis() == int_size(vInputs));
assert(vInputs.size() == vCompls.size());
for(int i = 0; i < pNtk->GetNumPis(); i++) {
assert(IsInt(vInputs[i]) || IsPi(vInputs[i]));
m[pNtk->GetPi(i)] = std::make_pair(vInputs[i], vCompls[i]);
}
pNtk->ForEachInt([&](int id) {
int id2 = CreateNode();
lInts.push_back(id2);
sInts.insert(id2);
vvFaninEdges[id2].resize(pNtk->GetNumFanins(id));
pNtk->ForEachFaninIdx(id, [&](int idx, int fi, bool c) {
assert(m.count(fi));
vvFaninEdges[id2][idx] = Node2Edge(m[fi].first, c ^ m[fi].second);
vRefs[m[fi].first]++;
});
m[id] = std::make_pair(id2, false);
});
assert(pNtk->GetNumPos() == int_size(vOutputs));
std::vector<int> vNewOutputs(pNtk->GetNumPos());
std::vector<bool> vNewCompls(pNtk->GetNumPos());
for(int i = 0; i < pNtk->GetNumPos(); i++) {
int id = vOutputs[i];
int po = pNtk->GetPo(i);
assert(m.count(pNtk->GetFanin(po, 0)));
int fi = m[pNtk->GetFanin(po, 0)].first;
bool c = pNtk->GetCompl(po, 0) ^ m[pNtk->GetFanin(po, 0)].second;
assert(id != fi);
vNewOutputs[i] = fi;
vNewCompls[i] = c;
// remove if substitution would lead to duplication with the same polarity
ForEachFanoutRidx(id, false, [&](int fo, bool foc, int idx) {
int idx2 = FindFanin(fo, fi);
if(idx2 != -1 && GetCompl(fo, idx2) == (c ^ foc)) {
RemoveFanin(fo, idx);
}
});
ForEachFanoutRidx(id, true, [&](int fo, bool foc, int idx) {
int idx2 = FindFanin(fo, fi);
if(idx2 != -1) { // substitute with const-0 in case of duplication
assert(GetCompl(fo, idx2) != (c ^ foc)); // of a different polarity
vRefs[GetConst0()]++;
vvFaninEdges[fo][idx] = Node2Edge(GetConst0(), 0);
} else { // otherwise, substitute with fanin
vvFaninEdges[fo][idx] = Node2Edge(fi, c ^ foc);
vRefs[fi]++;
// sort internal nodes
itr it = std::find(lInts.begin(), lInts.end(), id);
itr it2 = std::find(it, lInts.end(), fi);
if(it2 != lInts.end()) {
lInts.erase(it2);
it2 = lInts.insert(it, fi);
SortInts(it2);
}
}
});
vRefs[id] = 0;
}
Action action;
action.type = INSERT;
action.vFanins = vInputs;
action.vFanouts = vOutputs;
TakenAction(action);
for(int id: vOutputs) {
RemoveUnused(id, true);
}
return std::make_pair(std::move(vNewOutputs), std::move(vNewCompls));
}
/* }}} */
/* {{{ Network cleanup */
@ -1037,7 +1422,7 @@ namespace rrr {
}
for(ritr it = lInts.rbegin(); it != lInts.rend();) {
if(vRefs[*it] == 0) {
RemoveUnused(*it);
RemoveUnused(*it, false, true);
it = ritr(lInts.erase(--it.base()));
} else {
it++;
@ -1053,10 +1438,11 @@ namespace rrr {
Action action;
action.type = SAVE;
if(slot < 0) {
slot = vBackups.size();
slot = int_size(vBackups);
vBackups.push_back(*this);
assert(check_int_size(vBackups));
} else {
assert(slot < vBackups.size());
assert(slot < int_size(vBackups));
vBackups[slot] = *this;
}
action.idx = slot;
@ -1065,7 +1451,8 @@ namespace rrr {
}
void AndNetwork::Load(int slot) {
assert(slot < vBackups.size());
assert(slot >= 0);
assert(slot < int_size(vBackups));
Action action;
action.type = LOAD;
action.idx = slot;
@ -1077,7 +1464,7 @@ namespace rrr {
assert(!vBackups.empty());
Action action;
action.type = POP_BACK;
action.idx = vBackups.size() - 1;
action.idx = int_size(vBackups) - 1;
vBackups.pop_back();
TakenAction(action);
}
@ -1091,41 +1478,19 @@ namespace rrr {
}
void AndNetwork::Print() const {
std::cout << "pi: ";
std::string delim = "";
ForEachPi([&](int id) {
std::cout << delim << id;
delim = ", ";
});
std::cout << std::endl;
std::cout << "inputs: " << vPis << std::endl;
ForEachInt([&](int id) {
std::cout << "node " << id << ": ";
delim = "";
ForEachFanin(id, [&](int fi, bool c) {
std::cout << delim;
if(c) {
std::cout << "!";
}
std::cout << fi;
delim = ", ";
});
PrintComplementedEdges(std::bind(&AndNetwork::ForEachFanin<std::function<void(int, bool)>>, this, id, std::placeholders::_1));
std::cout << " (ref = " << vRefs[id] << ")";
std::cout << std::endl;
});
std::cout << "po: ";
delim = "";
ForEachPoDriver([&](int fi, bool c) {
std::cout << delim;
if(c) {
std::cout << "!";
}
std::cout << fi;
delim = ", ";
});
std::cout << "outputs: ";
PrintComplementedEdges(std::bind(&AndNetwork::ForEachPoDriver<std::function<void(int, bool)>>, this, std::placeholders::_1));
std::cout << std::endl;
}
/* }}} Misc end */
/* }}} */
}

View File

@ -1,12 +1,8 @@
#pragma once
#include <iostream>
#include <vector>
#include <aig/gia/giaNewBdd.h>
#include "rrrParameter.h"
#include "rrrTypes.h"
#include "rrrUtils.h"
#include "rrrBddManager.h"
ABC_NAMESPACE_CXX_HEADER_START
@ -73,7 +69,7 @@ namespace rrr {
public:
// constructors
BddAnalyzer();
BddAnalyzer(Ntk *pNtk, Parameter const *pPar);
BddAnalyzer(Parameter const *pPar);
~BddAnalyzer();
void UpdateNetwork(Ntk *pNtk_, bool fSame);
@ -320,7 +316,7 @@ namespace rrr {
SimulateNode(id, vFs);
DecRef(x);
if(!pBdd->LitIsEq(x, vFs[id])) {
pNtk->ForEachFanout(id, false, [&](int fo, bool c) {
pNtk->ForEachFanout(id, false, [&](int fo) {
vUpdates[fo] = true;
vCUpdates[fo] = true;
});
@ -345,7 +341,7 @@ namespace rrr {
}
lit x = pBdd->Const1();
IncRef(x);
pNtk->ForEachFanoutRidx(id, true, [&](int fo, bool c, int idx) {
pNtk->ForEachFanoutRidx(id, true, [&](int fo, int idx) {
Assign(x, pBdd->And(x, vvCs[fo][idx]));
});
if(pBdd->LitIsEq(vGs[id], x)) {
@ -374,7 +370,7 @@ namespace rrr {
for(int idx = 0; idx < nFanins; idx++) {
lit x = pBdd->Const1();
IncRef(x);
for(unsigned idx2 = idx + 1; idx2 < nFanins; idx2++) {
for(int idx2 = idx + 1; idx2 < nFanins; idx2++) {
int fi = pNtk->GetFanin(id, idx2);
bool c = pNtk->GetCompl(id, idx2);
Assign(x, pBdd->And(x, pBdd->LitNotCond(vFs[fi], c)));
@ -439,7 +435,7 @@ namespace rrr {
template <typename Ntk>
void BddAnalyzer<Ntk>::Save(int slot) {
if(slot >= vBackups.size()) {
if(slot >= int_size(vBackups)) {
vBackups.resize(slot + 1);
}
vBackups[slot].target = target;
@ -453,7 +449,7 @@ namespace rrr {
template <typename Ntk>
void BddAnalyzer<Ntk>::Load(int slot) {
assert(slot < vBackups.size());
assert(slot < int_size(vBackups));
target = vBackups[slot].target;
CopyVec(vFs, vBackups[slot].vFs);
CopyVec(vGs, vBackups[slot].vGs);
@ -486,41 +482,12 @@ namespace rrr {
}
template <typename Ntk>
BddAnalyzer<Ntk>::BddAnalyzer(Ntk *pNtk, Parameter const *pPar) :
pNtk(pNtk),
BddAnalyzer<Ntk>::BddAnalyzer(Parameter const *pPar) :
pNtk(NULL),
nVerbose(pPar->nAnalyzerVerbose),
pBdd(NULL),
target(-1),
fResim(false) {
NewBdd::Param Par;
Par.nObjsMaxLog = 25;
Par.nCacheMaxLog = 20;
Par.fCountOnes = true;
Par.nGbc = 1;
Par.nReo = 4000;
pBdd = new NewBdd::Man(pNtk->GetNumPis(), Par);
Allocate();
Assign(vFs[0], pBdd->Const0());
int idx = 0;
pNtk->ForEachPi([&](int id) {
Assign(vFs[id], pBdd->IthVar(idx));
idx++;
});
pNtk->ForEachInt([&](int id) {
vUpdates[id] = true;
});
Simulate();
pBdd->Reorder();
pBdd->TurnOffReo();
pNtk->ForEachInt([&](int id) {
vvCs[id].resize(pNtk->GetNumFanins(id), LitMax);
});
pNtk->ForEachPo([&](int id) {
vvCs[id].resize(1, LitMax);
Assign(vvCs[id][0], pBdd->Const0());
int fi = pNtk->GetFanin(id, 0);
vGUpdates[fi] = true;
});
pNtk->AddCallback(std::bind(&BddAnalyzer<Ntk>::ActionCallback, this, std::placeholders::_1));
}
template <typename Ntk>
@ -540,7 +507,7 @@ namespace rrr {
vCUpdates.clear();
// alloc
bool fUseReo = false;
if(pBdd->GetNumVars() != pNtk->GetNumPis()) {
if(!pBdd || pBdd->GetNumVars() != pNtk->GetNumPis()) {
// need to reset manager
delete pBdd;
NewBdd::Param Par;

848
src/opt/rrr/rrrBddManager.h Normal file
View File

@ -0,0 +1,848 @@
#pragma once
#include <cstdlib>
#include <limits>
#include <vector>
#include <iostream>
#include <iomanip>
#include <cmath>
ABC_NAMESPACE_CXX_HEADER_START
namespace rrr {
namespace NewBdd {
typedef unsigned short var;
typedef int bvar;
typedef unsigned lit;
typedef unsigned short ref;
typedef unsigned long long size;
typedef unsigned edge;
typedef unsigned uniq;
typedef unsigned cac;
static inline var VarMax() { return std::numeric_limits<var>::max(); }
static inline bvar BvarMax() { return std::numeric_limits<bvar>::max(); }
static inline lit LitMax() { return std::numeric_limits<lit>::max(); }
static inline ref RefMax() { return std::numeric_limits<ref>::max(); }
static inline size SizeMax() { return std::numeric_limits<size>::max(); }
static inline uniq UniqHash(lit Arg0, lit Arg1) { return Arg0 + 4256249 * Arg1; }
static inline cac CacHash(lit Arg0, lit Arg1) { return Arg0 + 4256249 * Arg1; }
static inline void fatal_error(const char* message) {
std::cerr << message << std::endl;
std::abort();
}
class Cache {
private:
cac nSize;
cac nMax;
cac Mask;
size nLookups;
size nHits;
size nThold;
double HitRate;
int nVerbose;
std::vector<lit> vCache;
public:
Cache(int nCacheSizeLog, int nCacheMaxLog, int nVerbose): nVerbose(nVerbose) {
if(nCacheMaxLog < nCacheSizeLog)
fatal_error("nCacheMax must not be smaller than nCacheSize");
nMax = (cac)1 << nCacheMaxLog;
if(!(nMax << 1))
fatal_error("Memout (nCacheMax) in init");
nSize = (cac)1 << nCacheSizeLog;
if(nVerbose)
std::cout << "Allocating " << nSize << " cache entries" << std::endl;
vCache.resize(nSize * 3);
Mask = nSize - 1;
nLookups = 0;
nHits = 0;
nThold = (nSize == nMax)? SizeMax(): nSize;
HitRate = 1;
}
~Cache() {
if(nVerbose)
std::cout << "Free " << nSize << " cache entries" << std::endl;
}
inline lit Lookup(lit x, lit y) {
nLookups++;
if(nLookups > nThold) {
double NewHitRate = (double)nHits / nLookups;
if(nVerbose >= 2)
std::cout << "Cache Hits: " << std::setw(10) << nHits << ", "
<< "Lookups: " << std::setw(10) << nLookups << ", "
<< "Rate: " << std::setw(10) << NewHitRate
<< std::endl;
if(NewHitRate > HitRate)
Resize();
if(nSize == nMax)
nThold = SizeMax();
else {
nThold <<= 1;
if(!nThold)
nThold = SizeMax();
}
HitRate = NewHitRate;
}
cac i = (CacHash(x, y) & Mask) * 3;
if(vCache[i] == x && vCache[i + 1] == y) {
if(nVerbose >= 3)
std::cout << "Cache hit: "
<< "x = " << std::setw(10) << x << ", "
<< "y = " << std::setw(10) << y << ", "
<< "z = " << std::setw(10) << vCache[i + 2] << ", "
<< "hash = " << std::hex << (CacHash(x, y) & Mask) << std::dec
<< std::endl;
nHits++;
return vCache[i + 2];
}
return LitMax();
}
inline void Insert(lit x, lit y, lit z) {
cac i = (CacHash(x, y) & Mask) * 3;
vCache[i] = x;
vCache[i + 1] = y;
vCache[i + 2] = z;
if(nVerbose >= 3)
std::cout << "Cache ent: "
<< "x = " << std::setw(10) << x << ", "
<< "y = " << std::setw(10) << y << ", "
<< "z = " << std::setw(10) << z << ", "
<< "hash = " << std::hex << (CacHash(x, y) & Mask) << std::dec
<< std::endl;
}
inline void Clear() {
std::fill(vCache.begin(), vCache.end(), 0);
}
void Resize() {
cac nSizeOld = nSize;
nSize <<= 1;
if(nVerbose >= 2)
std::cout << "Reallocating " << nSize << " cache entries" << std::endl;
vCache.resize(nSize * 3);
Mask = nSize - 1;
for(cac j = 0; j < nSizeOld; j++) {
cac i = j * 3;
if(vCache[i] || vCache[i + 1]) {
cac hash = (CacHash(vCache[i], vCache[i + 1]) & Mask) * 3;
vCache[hash] = vCache[i];
vCache[hash + 1] = vCache[i + 1];
vCache[hash + 2] = vCache[i + 2];
if(nVerbose >= 3)
std::cout << "Cache mov: "
<< "x = " << std::setw(10) << vCache[i] << ", "
<< "y = " << std::setw(10) << vCache[i + 1] << ", "
<< "z = " << std::setw(10) << vCache[i + 2] << ", "
<< "hash = " << std::hex << (CacHash(vCache[i], vCache[i + 1]) & Mask) << std::dec
<< std::endl;
}
}
}
};
struct Param {
int nObjsAllocLog;
int nObjsMaxLog;
int nUniqueSizeLog;
double UniqueDensity;
int nCacheSizeLog;
int nCacheMaxLog;
int nCacheVerbose;
bool fCountOnes;
int nGbc;
bvar nReo;
double MaxGrowth;
bool fReoVerbose;
int nVerbose;
std::vector<var> *pVar2Level;
Param() {
nObjsAllocLog = 20;
nObjsMaxLog = 25;
nUniqueSizeLog = 10;
UniqueDensity = 4;
nCacheSizeLog = 15;
nCacheMaxLog = 20;
nCacheVerbose = 0;
fCountOnes = false;
nGbc = 0;
nReo = BvarMax();
MaxGrowth = 1.2;
fReoVerbose = false;
nVerbose = 0;
pVar2Level = NULL;
}
};
class Man {
private:
var nVars;
bvar nObjs;
bvar nObjsAlloc;
bvar nObjsMax;
bvar RemovedHead;
int nGbc;
bvar nReo;
double MaxGrowth;
bool fReoVerbose;
int nVerbose;
std::vector<var> vVars;
std::vector<var> Var2Level;
std::vector<var> Level2Var;
std::vector<lit> vObjs;
std::vector<bvar> vNexts;
std::vector<bool> vMarks;
std::vector<ref> vRefs;
std::vector<edge> vEdges;
std::vector<double> vOneCounts;
std::vector<uniq> vUniqueMasks;
std::vector<bvar> vUniqueCounts;
std::vector<bvar> vUniqueTholds;
std::vector<std::vector<bvar> > vvUnique;
Cache *cache;
public:
inline lit Bvar2Lit(bvar a) const { return (lit)a << 1; }
inline lit Bvar2Lit(bvar a, bool c) const { return ((lit)a << 1) ^ (lit)c; }
inline bvar Lit2Bvar(lit x) const { return (bvar)(x >> 1); }
inline var VarOfBvar(bvar a) const { return vVars[a]; }
inline lit ThenOfBvar(bvar a) const { return vObjs[Bvar2Lit(a)]; }
inline lit ElseOfBvar(bvar a) const { return vObjs[Bvar2Lit(a, true)]; }
inline ref RefOfBvar(bvar a) const { return vRefs[a]; }
inline lit Const0() const { return (lit)0; }
inline lit Const1() const { return (lit)1; }
inline bool IsConst0(lit x) const { return x == Const0(); }
inline bool IsConst1(lit x) const { return x == Const1(); }
inline lit IthVar(var v) const { return Bvar2Lit((bvar)v + 1); }
inline lit LitRegular(lit x) const { return x & ~(lit)1; }
inline lit LitIrregular(lit x) const { return x | (lit)1; }
inline lit LitNot(lit x) const { return x ^ (lit)1; }
inline lit LitNotCond(lit x, bool c) const { return x ^ (lit)c; }
inline bool LitIsCompl(lit x) const { return x & (lit)1; }
inline bool LitIsEq(lit x, lit y) const { return x == y; }
inline var Var(lit x) const { return vVars[Lit2Bvar(x)]; }
inline var Level(lit x) const { return Var2Level[Var(x)]; }
inline lit Then(lit x) const { return LitNotCond(vObjs[LitRegular(x)], LitIsCompl(x)); }
inline lit Else(lit x) const { return LitNotCond(vObjs[LitIrregular(x)], LitIsCompl(x)); }
inline ref Ref(lit x) const { return vRefs[Lit2Bvar(x)]; }
inline double OneCount(lit x) const {
if(vOneCounts.empty())
fatal_error("fCountOnes was not set");
if(LitIsCompl(x))
return std::pow(2.0, nVars) - vOneCounts[Lit2Bvar(x)];
return vOneCounts[Lit2Bvar(x)];
}
public:
inline void IncRef(lit x) { if(!vRefs.empty() && Ref(x) != RefMax()) vRefs[Lit2Bvar(x)]++; }
inline void DecRef(lit x) { if(!vRefs.empty() && Ref(x) != RefMax()) vRefs[Lit2Bvar(x)]--; }
private:
inline bool Mark(lit x) const { return vMarks[Lit2Bvar(x)]; }
inline edge Edge(lit x) const { return vEdges[Lit2Bvar(x)]; }
inline void SetMark(lit x) { vMarks[Lit2Bvar(x)] = true; }
inline void ResetMark(lit x) { vMarks[Lit2Bvar(x)] = false; }
inline void IncEdge(lit x) { vEdges[Lit2Bvar(x)]++; }
inline void DecEdge(lit x) { vEdges[Lit2Bvar(x)]--; }
inline bool MarkOfBvar(bvar a) const { return vMarks[a]; }
inline edge EdgeOfBvar(bvar a) const { return vEdges[a]; }
inline void SetVarOfBvar(bvar a, var v) { vVars[a] = v; }
inline void SetThenOfBvar(bvar a, lit x) { vObjs[Bvar2Lit(a)] = x; }
inline void SetElseOfBvar(bvar a, lit x) { vObjs[Bvar2Lit(a, true)] = x; }
inline void SetMarkOfBvar(bvar a) { vMarks[a] = true; }
inline void ResetMarkOfBvar(bvar a) { vMarks[a] = false; }
inline void RemoveBvar(bvar a) {
var v = VarOfBvar(a);
SetVarOfBvar(a, VarMax());
std::vector<bvar>::iterator q = vvUnique[v].begin() + (UniqHash(ThenOfBvar(a), ElseOfBvar(a)) & vUniqueMasks[v]);
for(; *q; q = vNexts.begin() + *q)
if(*q == a)
break;
bvar next = vNexts[*q];
vNexts[*q] = RemovedHead;
RemovedHead = *q;
*q = next;
vUniqueCounts[v]--;
}
private:
void SetMark_rec(lit x) {
if(x < 2 || Mark(x))
return;
SetMark(x);
SetMark_rec(Then(x));
SetMark_rec(Else(x));
}
void ResetMark_rec(lit x) {
if(x < 2 || !Mark(x))
return;
ResetMark(x);
ResetMark_rec(Then(x));
ResetMark_rec(Else(x));
}
bvar CountNodes_rec(lit x) {
if(x < 2 || Mark(x))
return 0;
SetMark(x);
return 1 + CountNodes_rec(Then(x)) + CountNodes_rec(Else(x));
}
void CountEdges_rec(lit x) {
if(x < 2)
return;
IncEdge(x);
if(Mark(x))
return;
SetMark(x);
CountEdges_rec(Then(x));
CountEdges_rec(Else(x));
}
void CountEdges() {
vEdges.resize(nObjsAlloc);
for(bvar a = (bvar)nVars + 1; a < nObjs; a++)
if(RefOfBvar(a))
CountEdges_rec(Bvar2Lit(a));
for(bvar a = 1; a <= (bvar)nVars; a++)
vEdges[a]++;
for(bvar a = (bvar)nVars + 1; a < nObjs; a++)
if(RefOfBvar(a))
ResetMark_rec(Bvar2Lit(a));
}
public:
bool Resize() {
if(nObjsAlloc == nObjsMax)
return false;
lit nObjsAllocLit = (lit)nObjsAlloc << 1;
if(nObjsAllocLit > (lit)BvarMax())
nObjsAlloc = BvarMax();
else
nObjsAlloc = (bvar)nObjsAllocLit;
if(nVerbose >= 2)
std::cout << "Reallocating " << nObjsAlloc << " nodes" << std::endl;
vVars.resize(nObjsAlloc);
vObjs.resize((lit)nObjsAlloc * 2);
vNexts.resize(nObjsAlloc);
vMarks.resize(nObjsAlloc);
if(!vRefs.empty())
vRefs.resize(nObjsAlloc);
if(!vEdges.empty())
vEdges.resize(nObjsAlloc);
if(!vOneCounts.empty())
vOneCounts.resize(nObjsAlloc);
return true;
}
void ResizeUnique(var v) {
uniq nUniqueSize, nUniqueSizeOld;
nUniqueSize = nUniqueSizeOld = vvUnique[v].size();
nUniqueSize <<= 1;
if(!nUniqueSize) {
vUniqueTholds[v] = BvarMax();
return;
}
if(nVerbose >= 2)
std::cout << "Reallocating " << nUniqueSize << " unique table entries for Var " << v << std::endl;
vvUnique[v].resize(nUniqueSize);
vUniqueMasks[v] = nUniqueSize - 1;
for(uniq i = 0; i < nUniqueSizeOld; i++) {
std::vector<bvar>::iterator q, tail, tail1, tail2;
q = tail1 = vvUnique[v].begin() + i;
tail2 = q + nUniqueSizeOld;
while(*q) {
uniq hash = UniqHash(ThenOfBvar(*q), ElseOfBvar(*q)) & vUniqueMasks[v];
if(hash == i)
tail = tail1;
else
tail = tail2;
if(tail != q)
*tail = *q, *q = 0;
q = vNexts.begin() + *tail;
if(tail == tail1)
tail1 = q;
else
tail2 = q;
}
}
vUniqueTholds[v] <<= 1;
if((lit)vUniqueTholds[v] > (lit)BvarMax())
vUniqueTholds[v] = BvarMax();
}
bool Gbc() {
if(nVerbose >= 2)
std::cout << "Garbage collect" << std::endl;
if(!vEdges.empty()) {
for(bvar a = (bvar)nVars + 1; a < nObjs; a++)
if(!EdgeOfBvar(a) && VarOfBvar(a) != VarMax())
RemoveBvar(a);
} else {
for(bvar a = (bvar)nVars + 1; a < nObjs; a++)
if(RefOfBvar(a))
SetMark_rec(Bvar2Lit(a));
for(bvar a = (bvar)nVars + 1; a < nObjs; a++)
if(!MarkOfBvar(a) && VarOfBvar(a) != VarMax())
RemoveBvar(a);
for(bvar a = (bvar)nVars + 1; a < nObjs; a++)
if(RefOfBvar(a))
ResetMark_rec(Bvar2Lit(a));
}
cache->Clear();
return RemovedHead;
}
private:
inline lit UniqueCreateInt(var v, lit x1, lit x0) {
std::vector<bvar>::iterator p, q;
p = q = vvUnique[v].begin() + (UniqHash(x1, x0) & vUniqueMasks[v]);
for(; *q; q = vNexts.begin() + *q)
if(VarOfBvar(*q) == v && ThenOfBvar(*q) == x1 && ElseOfBvar(*q) == x0)
return Bvar2Lit(*q);
bvar next = *p;
if(nObjs < nObjsAlloc)
*p = nObjs++;
else if(RemovedHead)
*p = RemovedHead, RemovedHead = vNexts[*p];
else
return LitMax();
SetVarOfBvar(*p, v);
SetThenOfBvar(*p, x1);
SetElseOfBvar(*p, x0);
vNexts[*p] = next;
if(!vOneCounts.empty())
vOneCounts[*p] = OneCount(x1) / 2 + OneCount(x0) / 2;
if(nVerbose >= 3) {
std::cout << "Create node " << std::setw(10) << *p << ": "
<< "Var = " << std::setw(6) << v << ", "
<< "Then = " << std::setw(10) << x1 << ", "
<< "Else = " << std::setw(10) << x0;
if(!vOneCounts.empty())
std::cout << ", Ones = " << std::setw(10) << vOneCounts[*q];
std::cout << std::endl;
}
vUniqueCounts[v]++;
if(vUniqueCounts[v] > vUniqueTholds[v]) {
bvar a = *p;
ResizeUnique(v);
return Bvar2Lit(a);
}
return Bvar2Lit(*p);
}
inline lit UniqueCreate(var v, lit x1, lit x0) {
if(x1 == x0)
return x1;
lit x;
while(true) {
if(!LitIsCompl(x0))
x = UniqueCreateInt(v, x1, x0);
else
x = UniqueCreateInt(v, LitNot(x1), LitNot(x0));
if(x == LitMax()) {
bool fRemoved = false;
if(nGbc > 1)
fRemoved = Gbc();
if(!Resize() && !fRemoved && (nGbc != 1 || !Gbc()))
fatal_error("Memout (node)");
} else
break;
}
return LitIsCompl(x0)? LitNot(x): x;
}
lit And_rec(lit x, lit y) {
if(x == 0 || y == 1)
return x;
if(x == 1 || y == 0)
return y;
if(Lit2Bvar(x) == Lit2Bvar(y))
return (x == y)? x: 0;
if(x > y)
std::swap(x, y);
lit z = cache->Lookup(x, y);
if(z != LitMax())
return z;
var v;
lit x0, x1, y0, y1;
if(Level(x) < Level(y))
v = Var(x), x1 = Then(x), x0 = Else(x), y0 = y1 = y;
else if(Level(x) > Level(y))
v = Var(y), x0 = x1 = x, y1 = Then(y), y0 = Else(y);
else
v = Var(x), x1 = Then(x), x0 = Else(x), y1 = Then(y), y0 = Else(y);
lit z1 = And_rec(x1, y1);
IncRef(z1);
lit z0 = And_rec(x0, y0);
IncRef(z0);
z = UniqueCreate(v, z1, z0);
DecRef(z1);
DecRef(z0);
cache->Insert(x, y, z);
return z;
}
private:
bvar Swap(var i) {
var v1 = Level2Var[i];
var v2 = Level2Var[i + 1];
bvar f = 0;
bvar diff = 0;
for(std::vector<bvar>::iterator p = vvUnique[v1].begin(); p != vvUnique[v1].end(); p++) {
std::vector<bvar>::iterator q = p;
while(*q) {
if(!EdgeOfBvar(*q)) {
SetVarOfBvar(*q, VarMax());
bvar next = vNexts[*q];
vNexts[*q] = RemovedHead;
RemovedHead = *q;
*q = next;
vUniqueCounts[v1]--;
continue;
}
lit f1 = ThenOfBvar(*q);
lit f0 = ElseOfBvar(*q);
if(Var(f1) == v2 || Var(f0) == v2) {
DecEdge(f1);
if(Var(f1) == v2 && !Edge(f1))
DecEdge(Then(f1)), DecEdge(Else(f1)), diff--;
DecEdge(f0);
if(Var(f0) == v2 && !Edge(f0))
DecEdge(Then(f0)), DecEdge(Else(f0)), diff--;
bvar next = vNexts[*q];
vNexts[*q] = f;
f = *q;
*q = next;
vUniqueCounts[v1]--;
continue;
}
q = vNexts.begin() + *q;
}
}
while(f) {
lit f1 = ThenOfBvar(f);
lit f0 = ElseOfBvar(f);
lit f00, f01, f10, f11;
if(Var(f1) == v2)
f11 = Then(f1), f10 = Else(f1);
else
f10 = f11 = f1;
if(Var(f0) == v2)
f01 = Then(f0), f00 = Else(f0);
else
f00 = f01 = f0;
if(f11 == f01)
f1 = f11;
else {
f1 = UniqueCreate(v1, f11, f01);
if(!Edge(f1))
IncEdge(f11), IncEdge(f01), diff++;
}
IncEdge(f1);
IncRef(f1);
if(f10 == f00)
f0 = f10;
else {
f0 = UniqueCreate(v1, f10, f00);
if(!Edge(f0))
IncEdge(f10), IncEdge(f00), diff++;
}
IncEdge(f0);
DecRef(f1);
SetVarOfBvar(f, v2);
SetThenOfBvar(f, f1);
SetElseOfBvar(f, f0);
std::vector<bvar>::iterator q = vvUnique[v2].begin() + (UniqHash(f1, f0) & vUniqueMasks[v2]);
lit next = vNexts[f];
vNexts[f] = *q;
*q = f;
vUniqueCounts[v2]++;
f = next;
}
Var2Level[v1] = i + 1;
Var2Level[v2] = i;
Level2Var[i] = v2;
Level2Var[i + 1] = v1;
return diff;
}
void Sift() {
bvar count = CountNodes();
std::vector<var> sift_order(nVars);
for(var v = 0; v < nVars; v++)
sift_order[v] = v;
for(var i = 0; i < nVars; i++) {
var max_j = i;
for(var j = i + 1; j < nVars; j++)
if(vUniqueCounts[sift_order[j]] > vUniqueCounts[sift_order[max_j]])
max_j = j;
if(max_j != i)
std::swap(sift_order[max_j], sift_order[i]);
}
for(var v = 0; v < nVars; v++) {
bvar lev = Var2Level[sift_order[v]];
bool UpFirst = lev < (bvar)(nVars / 2);
bvar min_lev = lev;
bvar min_diff = 0;
bvar diff = 0;
bvar thold = count * (MaxGrowth - 1);
if(fReoVerbose)
std::cout << "Sift " << sift_order[v] << " : Level = " << lev << " Count = " << count << " Thold = " << thold << std::endl;
if(UpFirst) {
lev--;
for(; lev >= 0; lev--) {
diff += Swap(lev);
if(fReoVerbose)
std::cout << "\tSwap " << lev << " : Diff = " << diff << " Thold = " << thold << std::endl;
if(diff < min_diff)
min_lev = lev, min_diff = diff, thold = (count + diff) * (MaxGrowth - 1);
else if(diff > thold) {
lev--;
break;
}
}
lev++;
}
for(; lev < (bvar)nVars - 1; lev++) {
diff += Swap(lev);
if(fReoVerbose)
std::cout << "\tSwap " << lev << " : Diff = " << diff << " Thold = " << thold << std::endl;
if(diff <= min_diff)
min_lev = lev + 1, min_diff = diff, thold = (count + diff) * (MaxGrowth - 1);
else if(diff > thold) {
lev++;
break;
}
}
lev--;
if(UpFirst) {
for(; lev >= min_lev; lev--) {
diff += Swap(lev);
if(fReoVerbose)
std::cout << "\tSwap " << lev << " : Diff = " << diff << " Thold = " << thold << std::endl;
}
} else {
for(; lev >= 0; lev--) {
diff += Swap(lev);
if(fReoVerbose)
std::cout << "\tSwap " << lev << " : Diff = " << diff << " Thold = " << thold << std::endl;
if(diff <= min_diff)
min_lev = lev, min_diff = diff, thold = (count + diff) * (MaxGrowth - 1);
else if(diff > thold) {
lev--;
break;
}
}
lev++;
for(; lev < min_lev; lev++) {
diff += Swap(lev);
if(fReoVerbose)
std::cout << "\tSwap " << lev << " : Diff = " << diff << " Thold = " << thold << std::endl;
}
}
count += min_diff;
if(fReoVerbose)
std::cout << "Sifted " << sift_order[v] << " : Level = " << min_lev << " Count = " << count << " Thold = " << thold << std::endl;
}
}
public:
Man(int nVars_, Param p) {
nVerbose = p.nVerbose;
// parameter sanity check
if(p.nObjsMaxLog < p.nObjsAllocLog)
fatal_error("nObjsMax must not be smaller than nObjsAlloc");
if(nVars_ >= (int)VarMax())
fatal_error("Memout (nVars) in init");
nVars = nVars_;
lit nObjsMaxLit = (lit)1 << p.nObjsMaxLog;
if(!nObjsMaxLit)
fatal_error("Memout (nObjsMax) in init");
if(nObjsMaxLit > (lit)BvarMax())
nObjsMax = BvarMax();
else
nObjsMax = (bvar)nObjsMaxLit;
lit nObjsAllocLit = (lit)1 << p.nObjsAllocLog;
if(!nObjsAllocLit)
fatal_error("Memout (nObjsAlloc) in init");
if(nObjsAllocLit > (lit)BvarMax())
nObjsAlloc = BvarMax();
else
nObjsAlloc = (bvar)nObjsAllocLit;
if(nObjsAlloc <= (bvar)nVars)
fatal_error("nObjsAlloc must be larger than nVars");
uniq nUniqueSize = (uniq)1 << p.nUniqueSizeLog;
if(!nUniqueSize)
fatal_error("Memout (nUniqueSize) in init");
// allocation
if(nVerbose)
std::cout << "Allocating " << nObjsAlloc << " nodes and " << nVars << " x " << nUniqueSize << " unique table entries" << std::endl;
vVars.resize(nObjsAlloc);
vObjs.resize((lit)nObjsAlloc * 2);
vNexts.resize(nObjsAlloc);
vMarks.resize(nObjsAlloc);
vvUnique.resize(nVars);
vUniqueMasks.resize(nVars);
vUniqueCounts.resize(nVars);
vUniqueTholds.resize(nVars);
for(var v = 0; v < nVars; v++) {
vvUnique[v].resize(nUniqueSize);
vUniqueMasks[v] = nUniqueSize - 1;
if((lit)(nUniqueSize * p.UniqueDensity) > (lit)BvarMax())
vUniqueTholds[v] = BvarMax();
else
vUniqueTholds[v] = (bvar)(nUniqueSize * p.UniqueDensity);
}
if(p.fCountOnes) {
if(nVars > 1023)
fatal_error("nVars must be less than 1024 to count ones");
vOneCounts.resize(nObjsAlloc);
}
// set up cache
cache = new Cache(p.nCacheSizeLog, p.nCacheMaxLog, p.nCacheVerbose);
// create nodes for variables
nObjs = 1;
vVars[0] = VarMax();
for(var v = 0; v < nVars; v++)
UniqueCreateInt(v, 1, 0);
// set up variable order
Var2Level.resize(nVars);
Level2Var.resize(nVars);
for(var v = 0; v < nVars; v++) {
if(p.pVar2Level)
Var2Level[v] = (*p.pVar2Level)[v];
else
Var2Level[v] = v;
Level2Var[Var2Level[v]] = v;
}
// set other parameters
RemovedHead = 0;
nGbc = p.nGbc;
nReo = p.nReo;
MaxGrowth = p.MaxGrowth;
fReoVerbose = p.fReoVerbose;
if(nGbc || nReo != BvarMax())
vRefs.resize(nObjsAlloc);
}
~Man() {
if(nVerbose) {
std::cout << "Free " << nObjsAlloc << " nodes (" << nObjs << " live nodes)" << std::endl;
std::cout << "Free {";
std::string delim;
for(var v = 0; v < nVars; v++) {
std::cout << delim << vvUnique[v].size();
delim = ", ";
}
std::cout << "} unique table entries" << std::endl;
if(!vRefs.empty())
std::cout << "Free " << vRefs.size() << " refs" << std::endl;
}
delete cache;
}
void Reorder() {
if(nVerbose >= 2)
std::cout << "Reorder" << std::endl;
int nGbc_ = nGbc;
nGbc = 0;
CountEdges();
Sift();
vEdges.clear();
cache->Clear();
nGbc = nGbc_;
}
inline lit And(lit x, lit y) {
if(nObjs > nReo) {
Reorder();
while(nReo < nObjs) {
nReo <<= 1;
if((lit)nReo > (lit)BvarMax())
nReo = BvarMax();
}
}
return And_rec(x, y);
}
inline lit Or(lit x, lit y) {
return LitNot(And(LitNot(x), LitNot(y)));
}
public:
void SetRef(std::vector<lit> const &vLits) {
vRefs.clear();
vRefs.resize(nObjsAlloc);
for(size_t i = 0; i < vLits.size(); i++)
IncRef(vLits[i]);
}
void RemoveRefIfUnused() {
if(!nGbc && nReo == BvarMax())
vRefs.clear();
}
void TurnOnReo(int nReo_ = 0, std::vector<lit> const *vLits = NULL) {
if(nReo_)
nReo = nReo_;
else
nReo = nObjs << 1;
if((lit)nReo > (lit)BvarMax())
nReo = BvarMax();
if(vRefs.empty()) {
if(vLits)
SetRef(*vLits);
else
vRefs.resize(nObjsAlloc);
}
}
void TurnOffReo() {
nReo = BvarMax();
}
var GetNumVars() const {
return nVars;
}
void GetOrdering(std::vector<int> &Var2Level_) {
Var2Level_.resize(nVars);
for(var v = 0; v < nVars; v++)
Var2Level_[v] = Var2Level[v];
}
bvar CountNodes() {
bvar count = 1;
if(!vEdges.empty()) {
for(bvar a = 1; a < nObjs; a++)
if(EdgeOfBvar(a))
count++;
return count;
}
for(bvar a = 1; a <= (bvar)nVars; a++) {
count++;
SetMarkOfBvar(a);
}
for(bvar a = (bvar)nVars + 1; a < nObjs; a++)
if(RefOfBvar(a))
count += CountNodes_rec(Bvar2Lit(a));
for(bvar a = 1; a <= (bvar)nVars; a++)
ResetMarkOfBvar(a);
for(bvar a = (bvar)nVars + 1; a < nObjs; a++)
if(RefOfBvar(a))
ResetMark_rec(Bvar2Lit(a));
return count;
}
bvar CountNodes(std::vector<lit> const &vLits) {
bvar count = 1;
for(size_t i = 0; i < vLits.size(); i++)
count += CountNodes_rec(vLits[i]);
for(size_t i = 0; i < vLits.size(); i++)
ResetMark_rec(vLits[i]);
return count;
}
void PrintStats() {
bvar nRemoved = 0;
bvar a = RemovedHead;
while(a)
a = vNexts[a], nRemoved++;
bvar nLive = 1;
for(var v = 0; v < nVars; v++)
nLive += vUniqueCounts[v];
std::cout << "ref: " << std::setw(10) << (vRefs.empty()? 0: CountNodes()) << ", "
<< "used: " << std::setw(10) << nObjs << ", "
<< "live: " << std::setw(10) << nLive << ", "
<< "dead: " << std::setw(10) << nRemoved << ", "
<< "alloc: " << std::setw(10) << nObjsAlloc
<< std::endl;
}
};
}
}
ABC_NAMESPACE_CXX_HEADER_END

View File

@ -1,12 +1,8 @@
#pragma once
#include <iostream>
#include <vector>
#include <aig/gia/giaNewBdd.h>
#include "rrrParameter.h"
#include "rrrTypes.h"
#include "rrrUtils.h"
#include "rrrBddManager.h"
ABC_NAMESPACE_CXX_HEADER_START
@ -75,7 +71,7 @@ namespace rrr {
public:
// constructors
BddMspfAnalyzer();
BddMspfAnalyzer(Ntk *pNtk, Parameter const *pPar);
BddMspfAnalyzer(Parameter const *pPar);
~BddMspfAnalyzer();
void UpdateNetwork(Ntk *pNtk_, bool fSame);
@ -256,6 +252,9 @@ namespace rrr {
Assign(vGs[action.fi], pBdd->Or(pBdd->LitNot(x), vGs[action.id]));
DecRef(x);
}
} else {
// otherwise mark the node for future update
vCUpdates[action.id] = true;
}
vvCs[action.id].resize(action.idx + 1, LitMax);
Assign(vvCs[action.id][action.idx], vGs[action.fi]);
@ -333,7 +332,7 @@ namespace rrr {
pNtk->ForEachInt([&](int id) {
if(vUpdates[id]) {
if(SimulateNode(id, vFs)) {
pNtk->ForEachFanout(id, false, [&](int fo, bool c) {
pNtk->ForEachFanout(id, false, [&](int fo) {
vUpdates[fo] = true;
vCUpdates[fo] = true;
});
@ -357,7 +356,7 @@ namespace rrr {
});
lit x = pBdd->Const1();
IncRef(x);
pNtk->ForEachPoDriver([&](int fi, bool c) {
pNtk->ForEachPoDriver([&](int fi) {
lit y = Xor(vFs[fi], v[fi]);
IncRef(y);
Assign(x, pBdd->And(x, pBdd->LitNot(y)));
@ -385,7 +384,7 @@ namespace rrr {
}
lit x = pBdd->Const1();
IncRef(x);
pNtk->ForEachFanoutRidx(id, true, [&](int fo, bool c, int idx) {
pNtk->ForEachFanoutRidx(id, true, [&](int fo, int idx) {
Assign(x, pBdd->And(x, vvCs[fo][idx]));
});
if(pBdd->LitIsEq(vGs[id], x)) {
@ -533,7 +532,7 @@ namespace rrr {
template <typename Ntk>
void BddMspfAnalyzer<Ntk>::Save(int slot) {
if(slot >= vBackups.size()) {
if(slot >= int_size(vBackups)) {
vBackups.resize(slot + 1);
}
CopyVec(vBackups[slot].vFs, vFs);
@ -548,7 +547,7 @@ namespace rrr {
template <typename Ntk>
void BddMspfAnalyzer<Ntk>::Load(int slot) {
assert(slot < vBackups.size());
assert(slot < int_size(vBackups));
CopyVec(vFs, vBackups[slot].vFs);
CopyVec(vGs, vBackups[slot].vGs);
CopyVecVec(vvCs, vBackups[slot].vvCs);
@ -580,40 +579,11 @@ namespace rrr {
}
template <typename Ntk>
BddMspfAnalyzer<Ntk>::BddMspfAnalyzer(Ntk *pNtk, Parameter const *pPar) :
pNtk(pNtk),
BddMspfAnalyzer<Ntk>::BddMspfAnalyzer(Parameter const *pPar) :
pNtk(NULL),
nVerbose(pPar->nAnalyzerVerbose),
pBdd(NULL),
fUpdate(false) {
NewBdd::Param Par;
Par.nObjsMaxLog = 25;
Par.nCacheMaxLog = 20;
Par.fCountOnes = true;
Par.nGbc = 1;
Par.nReo = 4000;
pBdd = new NewBdd::Man(pNtk->GetNumPis(), Par);
Allocate();
Assign(vFs[0], pBdd->Const0());
int idx = 0;
pNtk->ForEachPi([&](int id) {
Assign(vFs[id], pBdd->IthVar(idx));
idx++;
});
pNtk->ForEachInt([&](int id) {
vUpdates[id] = true;
});
Simulate();
pBdd->Reorder();
pBdd->TurnOffReo();
pNtk->ForEachInt([&](int id) {
vvCs[id].resize(pNtk->GetNumFanins(id), LitMax);
});
pNtk->ForEachPo([&](int id) {
vvCs[id].resize(1, LitMax);
Assign(vvCs[id][0], pBdd->Const0());
int fi = pNtk->GetFanin(id, 0);
vGUpdates[fi] = true;
});
pNtk->AddCallback(std::bind(&BddMspfAnalyzer<Ntk>::ActionCallback, this, std::placeholders::_1));
}
template <typename Ntk>
@ -633,7 +603,7 @@ namespace rrr {
vVisits.clear();
// alloc
bool fUseReo = false;
if(pBdd->GetNumVars() != pNtk->GetNumPis()) {
if(!pBdd || pBdd->GetNumVars() != pNtk->GetNumPis()) {
// need to reset manager
delete pBdd;
NewBdd::Param Par;

View File

@ -1,14 +1,12 @@
#pragma once
#include <vector>
#include <map>
#include <iterator>
#include <random>
#include <numeric>
#include <limits>
#include "rrrParameter.h"
#include "rrrTypes.h"
#include "rrrUtils.h"
ABC_NAMESPACE_CXX_HEADER_START
@ -31,10 +29,12 @@ namespace rrr {
std::function<double(Ntk *)> CostFunction;
int nSortType;
int nFlow;
int nDistance;
bool fCompatible;
seconds nTimeout; // assigned upon Run
// data
Ana *pAna;
Ana ana;
std::mt19937 rng;
std::vector<int> vTmp;
std::map<int, std::set<int>> mapNewFanins;
@ -46,7 +46,7 @@ namespace rrr {
// marks
int target;
std::vector<bool> vMarks;
std::vector<bool> vTfoMarks;
// callback
void ActionCallback(Action const &action);
@ -61,13 +61,14 @@ namespace rrr {
void SetRandPiOrder();
void SetRandCosts();
void SortFanins(int id);
void SortFanins();
// reduce fanin
bool ReduceFanin(int id, bool fRemoveUnused = false);
bool ReduceFaninOneRandom(int id, bool fRemoveUnused = false);
// reduce fanins
bool ReduceFanins(int id, bool fRemoveUnused = false);
bool ReduceFaninsOneRandom(int id, bool fRemoveUnused = false);
// reduce
void Reduce();
bool Reduce();
void ReduceRandom();
// remove redundancy
@ -88,13 +89,13 @@ namespace rrr {
public:
// constructors
Optimizer(Ntk *pNtk, Parameter const *pPar, std::function<double(Ntk *)> CostFunction);
~Optimizer();
void UpdateNetwork(Ntk *pNtk_, bool fSame);
Optimizer(Parameter const *pPar, std::function<double(Ntk *)> CostFunction);
void UpdateNetwork(Ntk *pNtk_, bool fSame = false);
// run
void Run(seconds nTimeout_ = 0);
void Randomize();
void ResetSeed(int iSeed);
void Randomize(int iSeed);
};
@ -154,11 +155,11 @@ namespace rrr {
return;
}
target = id;
vMarks.clear();
vMarks.resize(pNtk->GetNumNodes());
vMarks[id] = true;
vTfoMarks.clear();
vTfoMarks.resize(pNtk->GetNumNodes());
vTfoMarks[id] = true;
pNtk->ForEachTfo(id, false, [&](int fo) {
vMarks[fo] = true;
vTfoMarks[fo] = true;
});
}
@ -183,8 +184,7 @@ namespace rrr {
template <typename Ntk, typename Ana>
inline void Optimizer<Ntk, Ana>::SetRandPiOrder() {
assert(vRandPiOrder.size() <= (std::vector<int>::size_type)std::numeric_limits<int>::max());
if((int)vRandPiOrder.size() != pNtk->GetNumPis()) {
if(int_size(vRandPiOrder) != pNtk->GetNumPis()) {
vRandPiOrder.clear();
vRandPiOrder.resize(pNtk->GetNumPis());
std::iota(vRandPiOrder.begin(), vRandPiOrder.end(), 0);
@ -195,8 +195,7 @@ namespace rrr {
template <typename Ntk, typename Ana>
inline void Optimizer<Ntk, Ana>::SetRandCosts() {
std::uniform_real_distribution<> dis(std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max());
assert(vRandCosts.size() <= (std::vector<int>::size_type)std::numeric_limits<int>::max());
while((int)vRandCosts.size() < pNtk->GetNumNodes()) {
while(int_size(vRandCosts) < pNtk->GetNumNodes()) {
vRandCosts.push_back(dis(rng));
}
}
@ -207,12 +206,12 @@ namespace rrr {
case 0: // no sorting
break;
case 1: // prioritize internals
pNtk->SortFanins(id, [&](int i, bool ci, int j, bool cj) {
pNtk->SortFanins(id, [&](int i, int j) {
return !pNtk->IsPi(i) && pNtk->IsPi(j);
});
break;
case 2: // prioritize internals with (reversely) sorted PIs
pNtk->SortFanins(id, [&](int i, bool ci, int j, bool cj) {
pNtk->SortFanins(id, [&](int i, int j) {
if(pNtk->IsPi(i) && pNtk->IsPi(j)) {
return pNtk->GetPiIndex(i) > pNtk->GetPiIndex(j);
}
@ -221,7 +220,7 @@ namespace rrr {
break;
case 3: // prioritize internals with random PI order
SetRandPiOrder();
pNtk->SortFanins(id, [&](int i, bool ci, int j, bool cj) {
pNtk->SortFanins(id, [&](int i, int j) {
if(pNtk->IsPi(i) && pNtk->IsPi(j)) {
return vRandPiOrder[pNtk->GetPiIndex(i)] > vRandPiOrder[pNtk->GetPiIndex(j)];
}
@ -229,12 +228,12 @@ namespace rrr {
});
break;
case 4: // smaller fanout takes larger cost
pNtk->SortFanins(id, [&](int i, bool ci, int j, bool cj) {
pNtk->SortFanins(id, [&](int i, int j) {
return pNtk->GetNumFanouts(i) < pNtk->GetNumFanouts(j);
});
break;
case 5: // fanout + PI
pNtk->SortFanins(id, [&](int i, bool ci, int j, bool cj) {
pNtk->SortFanins(id, [&](int i, int j) {
if(pNtk->IsPi(i) && !pNtk->IsPi(j)) {
return false;
}
@ -245,7 +244,7 @@ namespace rrr {
});
break;
case 6: // fanout + sorted PI
pNtk->SortFanins(id, [&](int i, bool ci, int j, bool cj) {
pNtk->SortFanins(id, [&](int i, int j) {
if(pNtk->IsPi(i) && pNtk->IsPi(j)) {
return pNtk->GetPiIndex(i) > pNtk->GetPiIndex(j);
}
@ -260,7 +259,7 @@ namespace rrr {
break;
case 7: // fanout + random PI
SetRandPiOrder();
pNtk->SortFanins(id, [&](int i, bool ci, int j, bool cj) {
pNtk->SortFanins(id, [&](int i, int j) {
if(pNtk->IsPi(i) && pNtk->IsPi(j)) {
return vRandPiOrder[pNtk->GetPiIndex(i)] > vRandPiOrder[pNtk->GetPiIndex(j)];
}
@ -274,7 +273,7 @@ namespace rrr {
});
break;
case 8: // reverse topological order + PI
pNtk->SortFanins(id, [&](int i, bool ci, int j, bool cj) {
pNtk->SortFanins(id, [&](int i, int j) {
if(pNtk->IsPi(i) && pNtk->IsPi(j)) {
return false;
}
@ -288,7 +287,7 @@ namespace rrr {
});
break;
case 9: // reverse topological order + sorted PI
pNtk->SortFanins(id, [&](int i, bool ci, int j, bool cj) {
pNtk->SortFanins(id, [&](int i, int j) {
if(pNtk->IsPi(i) && pNtk->IsPi(j)) {
return pNtk->GetPiIndex(i) > pNtk->GetPiIndex(j);
}
@ -303,7 +302,7 @@ namespace rrr {
break;
case 10: // reverse topological order + random PI
SetRandPiOrder();
pNtk->SortFanins(id, [&](int i, bool ci, int j, bool cj) {
pNtk->SortFanins(id, [&](int i, int j) {
if(pNtk->IsPi(i) && pNtk->IsPi(j)) {
return vRandPiOrder[pNtk->GetPiIndex(i)] > vRandPiOrder[pNtk->GetPiIndex(j)];
}
@ -317,7 +316,7 @@ namespace rrr {
});
break;
case 11: // topo + fanout + PI
pNtk->SortFanins(id, [&](int i, bool ci, int j, bool cj) {
pNtk->SortFanins(id, [&](int i, int j) {
if(pNtk->IsPi(i) && !pNtk->IsPi(j)) {
return false;
}
@ -337,7 +336,7 @@ namespace rrr {
});
break;
case 12: // topo + fanout + sorted PI
pNtk->SortFanins(id, [&](int i, bool ci, int j, bool cj) {
pNtk->SortFanins(id, [&](int i, int j) {
if(pNtk->IsPi(i) && pNtk->IsPi(j)) {
return pNtk->GetPiIndex(i) > pNtk->GetPiIndex(j);
}
@ -358,7 +357,7 @@ namespace rrr {
break;
case 13: // topo + fanout + random PI
SetRandPiOrder();
pNtk->SortFanins(id, [&](int i, bool ci, int j, bool cj) {
pNtk->SortFanins(id, [&](int i, int j) {
if(pNtk->IsPi(i) && pNtk->IsPi(j)) {
return vRandPiOrder[pNtk->GetPiIndex(i)] > vRandPiOrder[pNtk->GetPiIndex(j)];
}
@ -379,13 +378,13 @@ namespace rrr {
break;
case 14: // random order
SetRandCosts();
pNtk->SortFanins(id, [&](int i, bool ci, int j, bool cj) {
pNtk->SortFanins(id, [&](int i, int j) {
return vRandCosts[i] > vRandCosts[j];
});
break;
case 15: // random + PI
SetRandCosts();
pNtk->SortFanins(id, [&](int i, bool ci, int j, bool cj) {
pNtk->SortFanins(id, [&](int i, int j) {
if(pNtk->IsPi(i) && !pNtk->IsPi(j)) {
return false;
}
@ -397,7 +396,7 @@ namespace rrr {
break;
case 16: // random + fanout
SetRandCosts();
pNtk->SortFanins(id, [&](int i, bool ci, int j, bool cj) {
pNtk->SortFanins(id, [&](int i, int j) {
if(pNtk->GetNumFanouts(i) > pNtk->GetNumFanouts(j)) {
return false;
}
@ -409,7 +408,7 @@ namespace rrr {
break;
case 17: // random + fanout + PI
SetRandCosts();
pNtk->SortFanins(id, [&](int i, bool ci, int j, bool cj) {
pNtk->SortFanins(id, [&](int i, int j) {
if(pNtk->IsPi(i) && !pNtk->IsPi(j)) {
return false;
}
@ -430,14 +429,20 @@ namespace rrr {
}
}
template <typename Ntk, typename Ana>
inline void Optimizer<Ntk, Ana>::SortFanins() {
pNtk->ForEachInt([&](int id) {
SortFanins(id);
});
}
/* }}} */
/* {{{ Reduce fanin */
/* {{{ Reduce fanins */
template <typename Ntk, typename Ana>
inline bool Optimizer<Ntk, Ana>::ReduceFanin(int id, bool fRemoveUnused) {
inline bool Optimizer<Ntk, Ana>::ReduceFanins(int id, bool fRemoveUnused) {
assert(pNtk->GetNumFanouts(id) > 0);
SortFanins(id);
bool fRemoved = false;
for(int idx = 0; idx < pNtk->GetNumFanins(id); idx++) {
// skip fanins that were just added
@ -448,7 +453,7 @@ namespace rrr {
}
}
// reduce
if(pAna->CheckRedundancy(id, idx)) {
if(ana.CheckRedundancy(id, idx)) {
int fi = pNtk->GetFanin(id, idx);
pNtk->RemoveFanin(id, idx);
fRemoved = true;
@ -461,8 +466,9 @@ namespace rrr {
return fRemoved;
}
/*
template <typename Ntk, typename Ana>
inline bool Optimizer<Ntk, Ana>::ReduceFaninOneRandom(int id, bool fRemoveUnused) {
inline bool Optimizer<Ntk, Ana>::ReduceFaninsOneRandom(int id, bool fRemoveUnused) {
assert(pNtk->GetNumFanouts(id) > 0);
// generate random order
vTmp.resize(pNtk->GetNumFanins(id));
@ -477,7 +483,7 @@ namespace rrr {
}
}
// reduce
if(pAna->CheckRedundancy(id, idx)) {
if(ana.CheckRedundancy(id, idx)) {
int fi = pNtk->GetFanin(id, idx);
pNtk->RemoveFanin(id, idx);
if(fRemoveUnused && pNtk->GetNumFanouts(fi) == 0) {
@ -488,6 +494,7 @@ namespace rrr {
}
return false;
}
*/
// TODO: add a method to minimize the size of fanins (check singles, pairs, trios, and so on)?
@ -496,7 +503,8 @@ namespace rrr {
/* {{{ Reduce */
template <typename Ntk, typename Ana>
void Optimizer<Ntk, Ana>::Reduce() {
bool Optimizer<Ntk, Ana>::Reduce() {
bool fReduced = false;
std::vector<int> vInts = pNtk->GetInts();
for(critr it = vInts.rbegin(); it != vInts.rend(); it++) {
if(!pNtk->IsInt(*it)) {
@ -506,21 +514,15 @@ namespace rrr {
pNtk->RemoveUnused(*it);
continue;
}
ReduceFanin(*it);
fReduced |= ReduceFanins(*it);
if(pNtk->GetNumFanins(*it) <= 1) {
pNtk->Propagate(*it);
}
/*
if(pNtk->GetNumFanins(*it) == 1) {
pNtk->RemoveBuffer(*it);
}
if(pNtk->GetNumFanins(*it) == 0) {
pNtk->RemoveConst(*it);
}
*/
}
return fReduced;
}
/*
template <typename Ntk, typename Ana>
void Optimizer<Ntk, Ana>::ReduceRandom() {
pNtk->Sweep(false);
@ -534,12 +536,13 @@ namespace rrr {
pNtk->RemoveUnused(*it);
continue;
}
ReduceFanin(*it, true);
ReduceFanins(*it, true);
if(pNtk->GetNumFanins(*it) <= 1) {
pNtk->Propagate(*it);
}
}
}
*/
/* }}} */
@ -547,6 +550,12 @@ namespace rrr {
template <typename Ntk, typename Ana>
void Optimizer<Ntk, Ana>::RemoveRedundancy() {
if(fCompatible) {
while(Reduce()) {
SortFanins();
}
return;
}
std::vector<int> vInts = pNtk->GetInts();
for(critr it = vInts.rbegin(); it != vInts.rend();) {
if(!pNtk->IsInt(*it)) {
@ -558,7 +567,8 @@ namespace rrr {
it++;
continue;
}
bool fReduced = ReduceFanin(*it);
SortFanins(*it);
bool fReduced = ReduceFanins(*it);
if(pNtk->GetNumFanins(*it) <= 1) {
pNtk->Propagate(*it);
}
@ -570,6 +580,7 @@ namespace rrr {
}
}
/*
template <typename Ntk, typename Ana>
void Optimizer<Ntk, Ana>::RemoveRedundancyRandom() {
pNtk->Sweep(false);
@ -585,7 +596,7 @@ namespace rrr {
it++;
continue;
}
bool fReduced = ReduceFaninOneRandom(*it, true);
bool fReduced = ReduceFaninsOneRandom(*it, true);
if(pNtk->GetNumFanins(*it) <= 1) {
pNtk->Propagate(*it);
}
@ -597,6 +608,7 @@ namespace rrr {
}
}
}
*/
/* }}} */
@ -606,20 +618,20 @@ namespace rrr {
template <typename T>
T Optimizer<Ntk, Ana>::SingleAdd(int id, T begin, T end) {
MarkTfo(id);
pNtk->ForEachFanin(id, [&](int fi, bool c) {
vMarks[fi] = true;
pNtk->ForEachFanin(id, [&](int fi) {
vTfoMarks[fi] = true;
});
T it = begin;
for(; it != end; it++) {
if(!pNtk->IsInt(*it) && !pNtk->IsPi(*it)) {
continue;
}
if(vMarks[*it]) {
if(vTfoMarks[*it]) {
continue;
}
if(pAna->CheckFeasibility(id, *it, false)) {
if(ana.CheckFeasibility(id, *it, false)) {
pNtk->AddFanin(id, *it, false);
} else if(pNtk->UseComplementedEdges() && pAna->CheckFeasibility(id, *it, true)) {
} else if(pNtk->UseComplementedEdges() && ana.CheckFeasibility(id, *it, true)) {
pNtk->AddFanin(id, *it, true);
} else {
continue;
@ -627,8 +639,8 @@ namespace rrr {
mapNewFanins[id].insert(*it);
break;
}
pNtk->ForEachFanin(id, [&](int fi, bool c) {
vMarks[fi] = false;
pNtk->ForEachFanin(id, [&](int fi) {
vTfoMarks[fi] = false;
});
return it;
}
@ -636,20 +648,20 @@ namespace rrr {
template <typename Ntk, typename Ana>
int Optimizer<Ntk, Ana>::MultiAdd(int id, std::vector<int> const &vCands, int nMax) {
MarkTfo(id);
pNtk->ForEachFanin(id, [&](int fi, bool c) {
vMarks[fi] = true;
pNtk->ForEachFanin(id, [&](int fi) {
vTfoMarks[fi] = true;
});
int nAdded = 0;
for(int cand: vCands) {
if(!pNtk->IsInt(cand) && !pNtk->IsPi(cand)) {
continue;
}
if(vMarks[cand]) {
if(vTfoMarks[cand]) {
continue;
}
if(pAna->CheckFeasibility(id, cand, false)) {
if(ana.CheckFeasibility(id, cand, false)) {
pNtk->AddFanin(id, cand, false);
} else if(pNtk->UseComplementedEdges() && pAna->CheckFeasibility(id, cand, true)) {
} else if(pNtk->UseComplementedEdges() && ana.CheckFeasibility(id, cand, true)) {
pNtk->AddFanin(id, cand, true);
} else {
continue;
@ -660,8 +672,8 @@ namespace rrr {
break;
}
}
pNtk->ForEachFanin(id, [&](int fi, bool c) {
vMarks[fi] = false;
pNtk->ForEachFanin(id, [&](int fi) {
vTfoMarks[fi] = false;
});
return nAdded;
}
@ -715,6 +727,10 @@ namespace rrr {
}
if(pNtk->IsInt(id)) {
pNtk->TrivialDecompose(id);
SortFanins();
if(fCompatible) {
RemoveRedundancy();
}
}
if(fGreedy) {
pNtk->PopBack();
@ -781,21 +797,16 @@ namespace rrr {
/* {{{ Constructors */
template <typename Ntk, typename Ana>
Optimizer<Ntk, Ana>::Optimizer(Ntk *pNtk, Parameter const *pPar, std::function<double(Ntk *)> CostFunction) :
pNtk(pNtk),
Optimizer<Ntk, Ana>::Optimizer(Parameter const *pPar, std::function<double(Ntk *)> CostFunction) :
pNtk(NULL),
nVerbose(pPar->nOptimizerVerbose),
CostFunction(CostFunction),
nSortType(pPar->nSortType),
nFlow(pPar->nOptimizerFlow),
nDistance(pPar->nDistance),
fCompatible(pPar->fUseBddCspf),
ana(pPar),
target(-1) {
pNtk->AddCallback(std::bind(&Optimizer<Ntk, Ana>::ActionCallback, this, std::placeholders::_1));
pAna = new Ana(pNtk, pPar);
rng.seed(pPar->iSeed);
}
template <typename Ntk, typename Ana>
Optimizer<Ntk, Ana>::~Optimizer() {
delete pAna;
}
template <typename Ntk, typename Ana>
@ -803,7 +814,7 @@ namespace rrr {
pNtk = pNtk_;
target = -1;
pNtk->AddCallback(std::bind(&Optimizer<Ntk, Ana>::ActionCallback, this, std::placeholders::_1));
pAna->UpdateNetwork(pNtk, fSame);
ana.UpdateNetwork(pNtk, fSame);
}
/* }}} */
@ -818,14 +829,24 @@ namespace rrr {
case 0:
RemoveRedundancy();
ApplyReverseTopologically([&](int id) {
std::vector<int> vCands = pNtk->GetPisInts();
std::vector<int> vCands;
if(nDistance) {
vCands = pNtk->GetNeighbors(id, true, nDistance);
} else {
vCands = pNtk->GetPisInts();
}
SingleResub(id, vCands);
});
break;
case 1:
RemoveRedundancy();
ApplyReverseTopologically([&](int id) {
std::vector<int> vCands = pNtk->GetInts();
std::vector<int> vCands;
if(nDistance) {
vCands = pNtk->GetNeighbors(id, true, nDistance);
} else {
vCands = pNtk->GetPisInts();
}
MultiResub(id, vCands);
});
break;
@ -834,11 +855,22 @@ namespace rrr {
double dCost = CostFunction(pNtk);
while(true) {
ApplyReverseTopologically([&](int id) {
std::vector<int> vCands = pNtk->GetPisInts();
std::vector<int> vCands;
if(nDistance) {
vCands = pNtk->GetNeighbors(id, true, nDistance);
} else {
vCands = pNtk->GetPisInts();
}
SingleResub(id, vCands);
});
ApplyReverseTopologically([&](int id) {
std::vector<int> vCands = pNtk->GetInts();
std::vector<int> vCands;
if(nDistance) {
vCands = pNtk->GetNeighbors(id, true, nDistance);
} else {
vCands = pNtk->GetPisInts();
// vCands = pNtk->GetInts();
}
MultiResub(id, vCands);
});
double dNewCost = CostFunction(pNtk);
@ -856,12 +888,18 @@ namespace rrr {
}
template <typename Ntk, typename Ana>
void Optimizer<Ntk, Ana>::Randomize() {
nSortType = rng() % 18;
void Optimizer<Ntk, Ana>::ResetSeed(int iSeed) {
rng.seed(iSeed);
vRandPiOrder.clear();
vRandCosts.clear();
}
template <typename Ntk, typename Ana>
void Optimizer<Ntk, Ana>::Randomize(int iSeed) {
ResetSeed(iSeed);
nSortType = rng() % 18;
}
/* }}} */
}

View File

@ -9,6 +9,7 @@ namespace rrr {
int nWords = 10;
int nTimeout = 0;
int nSchedulerVerbose = 1;
int nPartitionerVerbose = 0;
int nOptimizerVerbose = 0;
int nAnalyzerVerbose = 0;
int nSimulatorVerbose = 0;
@ -16,9 +17,14 @@ namespace rrr {
bool fUseBddCspf = false;
bool fUseBddMspf = false;
int nConflictLimit = 0;
int nSortType = 0;
int nSortType = 12;
int nOptimizerFlow = 0;
int nSchedulerFlow = 0;
int nDistance = 0;
int nRestarts = 0;
int nThreads = 1;
int nWindowSize = 0;
bool fDeterministic = true;
};
}

View File

@ -0,0 +1,323 @@
#pragma once
#include <utility>
#include <map>
#include <tuple>
#include <random>
#include "rrrParameter.h"
#include "rrrUtils.h"
ABC_NAMESPACE_CXX_HEADER_START
namespace rrr {
template <typename Ntk>
class Partitioner {
private:
// pointer to network
Ntk *pNtk;
// parameters
int nVerbose;
int nWindowSize;
// data
std::map<Ntk *, std::tuple<std::set<int>, std::vector<int>, std::vector<bool>, std::vector<int>>> mSubNtk2Io;
std::set<int> sBlocked;
// subroutines
Ntk *ExtractDisjoint(int id);
public:
// constructors
Partitioner(Parameter const *pPar);
void UpdateNetwork(Ntk *pNtk);
// APIs
Ntk *Extract(int iSeed);
void Insert(Ntk *pSubNtk);
};
/* {{{ Subroutines */
template <typename Ntk>
Ntk *Partitioner<Ntk>::ExtractDisjoint(int id) {
// collect neighbor
assert(!sBlocked.count(id));
if(nVerbose) {
std::cout << "extracting with a center node " << id << std::endl;
}
int nRadius = 2;
std::vector<int> vNodes = pNtk->GetNeighbors(id, false, nRadius);
std::vector<int> vNodesNew = pNtk->GetNeighbors(id, false, nRadius + 1);
// gradually increase radius until it hits window size limit
while(int_size(vNodesNew) < nWindowSize) {
if(int_size(vNodes) == int_size(vNodesNew)) { // already maximum
break;
}
vNodes = vNodesNew;
nRadius++;
vNodesNew = pNtk->GetNeighbors(id, false, nRadius + 1);
}
std::set<int> sNodes(vNodes.begin(), vNodes.end());
sNodes.insert(id);
if(nVerbose) {
std::cout << "neighbors: " << sNodes << std::endl;
}
// remove nodes that are already blocked
for(std::set<int>::iterator it = sNodes.begin(); it != sNodes.end();) {
if(sBlocked.count(*it)) {
it = sNodes.erase(it);
} else {
it++;
}
}
if(nVerbose) {
std::cout << "disjoint neighbors: " << sNodes << std::endl;
}
// get tentative window IO
std::set<int> sInputs, sOutputs;
for(int id: sNodes) {
pNtk->ForEachFanin(id, [&](int fi) {
if(!sNodes.count(fi)) {
sInputs.insert(fi);
}
});
bool fOutput = false;
pNtk->ForEachFanout(id, true, [&](int fo) {
if(!sNodes.count(fo)) {
fOutput = true;
}
});
if(fOutput) {
sOutputs.insert(id);
}
}
if(nVerbose) {
std::cout << "\tinputs: " << sInputs << std::endl;
std::cout << "\toutputs: " << sOutputs << std::endl;
}
// prevent potential loops while ensuring disjointness
// first by including inner nodes
std::set<int> sFanouts;
for(int id: sOutputs) {
pNtk->ForEachFanout(id, false, [&](int fo) {
if(!sNodes.count(fo)) {
sFanouts.insert(fo);
}
});
}
std::vector<int> vInners = pNtk->GetInners(sFanouts, sInputs);
while(!vInners.empty()) {
if(nVerbose) {
std::cout << "inners: " << vInners << std::endl;
}
if(int_size(sNodes) + int_size(vInners) > 2 * nWindowSize) {
// TODO: parametrize
break;
}
bool fOverlap = false;
for(int i: vInners) {
if(sBlocked.count(i)) {
fOverlap = true;
break;
}
}
if(fOverlap) {
break;
}
sNodes.insert(vInners.begin(), vInners.end());
if(nVerbose) {
std::cout << "new neighbors: " << sNodes << std::endl;
}
sInputs.clear();
sOutputs.clear();
for(int id: sNodes) {
pNtk->ForEachFanin(id, [&](int fi) {
if(!sNodes.count(fi)) {
sInputs.insert(fi);
}
});
bool fOutput = false;
pNtk->ForEachFanout(id, true, [&](int fo) {
if(!sNodes.count(fo)) {
fOutput = true;
}
});
if(fOutput) {
sOutputs.insert(id);
}
}
if(nVerbose) {
std::cout << "\tnew inputs: " << sInputs << std::endl;
std::cout << "\tnew outputs: " << sOutputs << std::endl;
}
sFanouts.clear();
for(int id: sOutputs) {
pNtk->ForEachFanout(id, false, [&](int fo) {
if(!sNodes.count(fo)) {
sFanouts.insert(fo);
}
});
}
vInners = pNtk->GetInners(sFanouts, sInputs);
}
if(!vInners.empty()) {
// fall back method by removing TFI of outputs reachable to inputs
for(int id: sOutputs) {
if(!sNodes.count(id)) { // already removed
continue;
}
sFanouts.clear();
pNtk->ForEachFanout(id, false, [&](int fo) {
if(!sNodes.count(fo)) {
sFanouts.insert(fo);
}
});
if(pNtk->IsReachable(sFanouts, sInputs)) {
if(nVerbose) {
std::cout << id << " is reachable to inputs" << std::endl;
}
sNodes.erase(id);
pNtk->ForEachTfiEnd(id, sInputs, [&](int fi) {
int r = sNodes.erase(fi);
assert(r);
});
if(nVerbose) {
std::cout << "new neighbors: " << sNodes << std::endl;
}
if(sNodes.empty()) {
if(nVerbose) {
std::cout << "IS EMPTY" << std::endl;
}
return NULL;
}
// recompute inputs
sInputs.clear();
for(int id: sNodes) {
pNtk->ForEachFanin(id, [&](int fi) {
if(!sNodes.count(fi)) {
sInputs.insert(fi);
}
});
}
if(nVerbose) {
std::cout << "\tnew inputs: " << sInputs << std::endl;
}
}
}
// recompute outputs
for(std::set<int>::iterator it = sOutputs.begin(); it != sOutputs.end();) {
if(!sNodes.count(*it)) {
it = sOutputs.erase(it);
} else {
it++;
}
}
if(nVerbose) {
std::cout << "\tnew outputs: " << sOutputs << std::endl;
}
}
// ensure outputs of both windows do not reach each other's inputs at the same time
for(auto const &entry: mSubNtk2Io) {
if(!pNtk->IsReachable(sOutputs, std::get<1>(entry.second))) {
continue;
}
if(!pNtk->IsReachable(std::get<3>(entry.second), sInputs)) {
continue;
}
if(nVerbose) {
std::cout << "POTENTIAL LOOPS" << std::endl;
}
return NULL;
}
if(int_size(sNodes) < nWindowSize / 2) {
// too small
// TODO: fix this parameterized
return NULL;
}
// extract by inputs, internals, and outputs (no checks needed in ntk side)
std::vector<int> vInputs(sInputs.begin(), sInputs.end());
std::vector<int> vOutputs(sOutputs.begin(), sOutputs.end());
Ntk *pSubNtk = pNtk->Extract(sNodes, vInputs, vOutputs);
// return subntk to be modified, while remember IOs
for(int i: sNodes) {
sBlocked.insert(i);
}
mSubNtk2Io.emplace(pSubNtk, std::make_tuple(std::move(sNodes), std::move(vInputs), std::vector<bool>(vInputs.size()), std::move(vOutputs)));
return pSubNtk;
}
/* }}} */
/* {{{ Constructors */
template <typename Ntk>
Partitioner<Ntk>::Partitioner(Parameter const *pPar) :
nVerbose(pPar->nPartitionerVerbose),
nWindowSize(pPar->nWindowSize) {
}
template <typename Ntk>
void Partitioner<Ntk>::UpdateNetwork(Ntk *pNtk_) {
pNtk = pNtk_;
}
/* }}} */
/* {{{ APIs */
template <typename Ntk>
Ntk *Partitioner<Ntk>::Extract(int iSeed) {
// pick a center node from candidates that do not belong to any other ongoing windows
std::mt19937 rng(iSeed);
std::vector<int> vInts = pNtk->GetInts();
std::shuffle(vInts.begin(), vInts.end(), rng);
for(int id: vInts) {
if(!sBlocked.count(id)) {
Ntk *pSubNtk = ExtractDisjoint(id);
if(pSubNtk) {
return pSubNtk;
}
}
}
return NULL;
}
template <typename Ntk>
void Partitioner<Ntk>::Insert(Ntk *pSubNtk) {
for(int i: std::get<0>(mSubNtk2Io[pSubNtk])) {
sBlocked.erase(i);
}
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]));
std::vector<int> &vOldOutputs = std::get<3>(mSubNtk2Io[pSubNtk]);
std::vector<int> &vNewOutputs = vNewSignals.first;
std::vector<bool> &vNewCompls = vNewSignals.second;
// need to remap updated outputs that are used as inputs in other windows
std::map<int, int> mOutput2Idx;
for(int idx = 0; idx < int_size(vOldOutputs); idx++) {
mOutput2Idx[vOldOutputs[idx]] = idx;
}
for(auto &entry: mSubNtk2Io) {
if(entry.first != pSubNtk) {
std::vector<int> &vInputs = std::get<1>(entry.second);
std::vector<bool> &vCompls = std::get<2>(entry.second);
for(int i = 0; i < int_size(vInputs); i++) {
if(mOutput2Idx.count(vInputs[i])) {
int idx = mOutput2Idx[vInputs[i]];
vInputs[i] = vNewOutputs[idx];
vCompls[i] = vCompls[i] ^ vNewCompls[idx];
}
}
}
}
delete pSubNtk;
mSubNtk2Io.erase(pSubNtk);
}
/* }}} */
}
ABC_NAMESPACE_CXX_HEADER_END

View File

@ -1,13 +1,9 @@
#pragma once
#include <iostream>
#include <iomanip>
#include <vector>
#include <sat/bsat/satSolver.h>
#include "rrrParameter.h"
#include "rrrTypes.h"
#include "rrrUtils.h"
ABC_NAMESPACE_CXX_HEADER_START
@ -47,7 +43,7 @@ namespace rrr {
public:
// constructors
SatSolver(Ntk *pNtk, Parameter const *pPar);
SatSolver(Parameter const *pPar);
~SatSolver();
void UpdateNetwork(Ntk *pNtk_, bool fSame);
@ -190,7 +186,7 @@ namespace rrr {
}
// store po vars (NOTE: it's not a lit)
vLits.clear();
pNtk->ForEachPoDriver([&](int fi, bool c) {
pNtk->ForEachPoDriver([&](int fi) {
vLits.push_back(v[fi]);
});
// encode an inverted copy
@ -207,7 +203,7 @@ namespace rrr {
}
int idx = 0;
int n = 0;
pNtk->ForEachPoDriver([&](int fi, bool c) {
pNtk->ForEachPoDriver([&](int fi) {
assert(fi != id);
if(v[fi] != vLits[idx]) {
int x = sat_solver_addvar(p);
@ -256,8 +252,8 @@ namespace rrr {
/* {{{ Constructors */
template <typename Ntk>
SatSolver<Ntk>::SatSolver(Ntk *pNtk, Parameter const *pPar) :
pNtk(pNtk),
SatSolver<Ntk>::SatSolver(Parameter const *pPar) :
pNtk(NULL),
nVerbose(pPar->nSatSolverVerbose),
nConflictLimit(pPar->nConflictLimit),
pSat(sat_solver_new()),
@ -267,7 +263,6 @@ namespace rrr {
nCalls(0),
nSats(0),
nUnsats(0) {
pNtk->AddCallback(std::bind(&SatSolver<Ntk>::ActionCallback, this, std::placeholders::_1));
}
template <typename Ntk>
@ -278,6 +273,7 @@ namespace rrr {
template <typename Ntk>
void SatSolver<Ntk>::UpdateNetwork(Ntk *pNtk_, bool fSame) {
(void)fSame;
pNtk = pNtk_;
status = false;
target = -1;

View File

@ -1,12 +1,17 @@
#pragma once
#include <iostream>
#include <iomanip>
#include <queue>
#include <random>
#include "rrrParameter.h"
#include "rrrTypes.h"
#ifdef ABC_USE_PTHREADS
#include <thread>
#include <mutex>
#include <condition_variable>
#endif
#include "rrrParameter.h"
#include "rrrUtils.h"
#include "rrrPartitioner.h"
#include "rrrAbc.h"
ABC_NAMESPACE_CXX_HEADER_START
@ -16,87 +21,147 @@ namespace rrr {
template <typename Ntk, typename Opt>
class Scheduler {
private:
// job
struct Job;
struct CompareJobPointers;
// pointer to network
Ntk *pNtk;
// parameters
int nVerbose;
int iSeed;
int nFlow;
// copy of parameter (maybe updated during the run)
Parameter Par;
int nRestarts;
bool fMultiThreading;
bool fPartitioning;
bool fDeterministic;
seconds nTimeout;
std::function<double(Ntk *)> CostFunction;
// data
int nJobs;
int nFinishedJobs;
time_point start;
Partitioner<Ntk> par;
std::queue<Job *> qPendingJobs;
Opt *pOpt; // used only in case of single thread execution
#ifdef ABC_USE_PTHREADS
bool fTerminate;
std::vector<std::thread> vThreads;
std::priority_queue<Job *, std::vector<Job *>, CompareJobPointers> qFinishedJobs;
std::mutex mutexAbc;
std::mutex mutexPendingJobs;
std::mutex mutexFinishedJobs;
std::condition_variable condPendingJobs;
std::condition_variable condFinishedJobs;
#endif
// time
seconds GetRemainingTime();
seconds GetRemainingTime() const;
// abc
void CallAbc(Ntk *pNtk_, std::string Command);
// run jobs
void RunJob(Opt &opt, Job const *pJob);
// manage jobs
void CreateJob(Ntk *pNtk_, int iSeed_);
void OnJobEnd(std::function<void(Job *pJob)> const &func);
// thread
#ifdef ABC_USE_PTHREADS
void Thread(Parameter const *pPar);
#endif
public:
// constructor
// constructors
Scheduler(Ntk *pNtk, Parameter const *pPar);
~Scheduler();
// run
void Run();
};
/* {{{ time */
/* {{{ Job */
template <typename Ntk, typename Opt>
struct Scheduler<Ntk, Opt>::Job {
// data
int id;
Ntk *pNtk;
int iSeed;
// constructor
Job(int id, Ntk *pNtk, int iSeed) :
id(id),
pNtk(pNtk),
iSeed(iSeed) {
}
};
template <typename Ntk, typename Opt>
seconds Scheduler<Ntk, Opt>::GetRemainingTime() {
if(Par.nTimeout == 0) {
struct Scheduler<Ntk, Opt>::CompareJobPointers {
// smaller id comes first in priority_queue
bool operator()(Job const *lhs, Job const *rhs) const {
return lhs->id > rhs->id;
}
};
/* }}} */
/* {{{ Time */
template <typename Ntk, typename Opt>
seconds Scheduler<Ntk, Opt>::GetRemainingTime() const {
if(nTimeout == 0) {
return 0;
}
time_point current = GetCurrentTime();
seconds nTimeout = Par.nTimeout - DurationInSeconds(start, current);
if(nTimeout == 0) { // avoid glitch
seconds nRemainingTime = nTimeout - DurationInSeconds(start, current);
if(nRemainingTime == 0) { // avoid glitch
return -1;
}
return nTimeout;
return nRemainingTime;
}
/* }}} */
/* {{{ Constructor */
/* {{{ Abc */
template <typename Ntk, typename Opt>
Scheduler<Ntk, Opt>::Scheduler(Ntk *pNtk, Parameter const *pPar) :
pNtk(pNtk),
nVerbose(pPar->nSchedulerVerbose),
nFlow(pPar->nSchedulerFlow),
Par(*pPar) {
// TODO: allocations and other preparations should be done here
inline void Scheduler<Ntk, Opt>::CallAbc(Ntk *pNtk_, std::string Command) {
#ifdef ABC_USE_PTHREADS
if(fMultiThreading) {
{
std::unique_lock<std::mutex> l(mutexAbc);
Abc9Execute(pNtk_, Command);
}
return;
}
#endif
Abc9Execute(pNtk_, Command);
}
/* }}} */
/* {{{ Run jobs */
/* {{{ Run */
// TODO: have multiplie optimizers running on different windows/partitions
// TODO: run ABC on those windows or even on the entire network, maybe as a separate class
template <typename Ntk, typename Opt>
void Scheduler<Ntk, Opt>::Run() {
start = GetCurrentTime();
// prepare cost function
std::function<double(Ntk *)> CostFunction;
CostFunction = [](Ntk *pNtk) {
int nTwoInputSize = 0;
pNtk->ForEachInt([&](int id) {
nTwoInputSize += pNtk->GetNumFanins(id) - 1;
});
return nTwoInputSize;
};
void Scheduler<Ntk, Opt>::RunJob(Opt &opt, Job const *pJob) {
opt.UpdateNetwork(pJob->pNtk);
// start flow
Opt opt(pNtk, &Par, CostFunction);
switch(nFlow) {
case 0:
opt.ResetSeed(pJob->iSeed);
opt.Run(GetRemainingTime());
break;
case 1: { // transtoch
double dCost = CostFunction(pNtk);
std::mt19937 rng(pJob->iSeed);
double dCost = CostFunction(pJob->pNtk);
double dBestCost = dCost;
Ntk best(*pNtk);
Ntk best(*(pJob->pNtk));
if(nVerbose) {
std::cout << "start: cost = " << dCost << std::endl;
}
@ -105,9 +170,9 @@ namespace rrr {
break;
}
if(i != 0) {
Abc9Execute(pNtk, "&if -K 6; &mfs; &st");
dCost = CostFunction(pNtk);
opt.UpdateNetwork(pNtk, true);
CallAbc(pJob->pNtk, "&if -K 6; &mfs; &st");
dCost = CostFunction(pJob->pNtk);
opt.UpdateNetwork(pJob->pNtk, true);
if(nVerbose) {
std::cout << "hop " << std::setw(3) << i << ": cost = " << dCost << std::endl;
}
@ -116,37 +181,37 @@ namespace rrr {
if(GetRemainingTime() < 0) {
break;
}
opt.Randomize();
opt.Randomize(rng());
opt.Run(GetRemainingTime());
Abc9Execute(pNtk, "&dc2");
double dNewCost = CostFunction(pNtk);
CallAbc(pJob->pNtk, "&dc2");
double dNewCost = CostFunction(pJob->pNtk);
if(nVerbose) {
std::cout << "\tite " << std::setw(3) << j << ": cost = " << dNewCost << std::endl;
}
if(dNewCost < dCost) {
dCost = dNewCost;
opt.UpdateNetwork(pNtk, true);
opt.UpdateNetwork(pJob->pNtk, true);
} else {
break;
}
}
if(dCost < dBestCost) {
dBestCost = dCost;
best = *pNtk;
best = *(pJob->pNtk);
i = 0;
}
}
*pNtk = best;
*(pJob->pNtk) = best;
if(nVerbose) {
std::cout << "end: cost = " << dBestCost << std::endl;
}
break;
}
case 2: { // deep
double dCost = CostFunction(pNtk);
Ntk best(*pNtk);
std::mt19937 rng(pJob->iSeed);
int n = 0;
std::mt19937 rng(Par.iSeed);
double dCost = CostFunction(pJob->pNtk);
Ntk best(*(pJob->pNtk));
if(nVerbose) {
std::cout << "start: cost = " << dCost << std::endl;
}
@ -179,37 +244,37 @@ namespace rrr {
if(fFx)
Command += "; &fx; &st";
Command += pComp;
Abc9Execute(pNtk, Command);
CallAbc(pJob->pNtk, Command);
if(nVerbose) {
std::cout << "ite " << std::setw(6) << i << ": cost = " << CostFunction(pNtk) << std::endl;
std::cout << "ite " << std::setw(6) << i << ": cost = " << CostFunction(pJob->pNtk) << std::endl;
}
// rrr
for(int j = 0; j < n; j++) {
if(GetRemainingTime() < 0) {
break;
}
opt.Randomize();
opt.UpdateNetwork(pNtk, true);
opt.UpdateNetwork(pJob->pNtk, true);
opt.Randomize(rng());
opt.Run(GetRemainingTime());
if(rng() & 1) {
Abc9Execute(pNtk, "&dc2");
CallAbc(pJob->pNtk, "&dc2");
} else {
Abc9Execute(pNtk, "&put; " + pCompress2rs + "; &get");
CallAbc(pJob->pNtk, "&put; " + pCompress2rs + "; &get");
}
if(nVerbose) {
std::cout << "\trrr " << std::setw(6) << j << ": cost = " << CostFunction(pNtk) << std::endl;
std::cout << "\trrr " << std::setw(6) << j << ": cost = " << CostFunction(pJob->pNtk) << std::endl;
}
}
// eval
double dNewCost = CostFunction(pNtk);
double dNewCost = CostFunction(pJob->pNtk);
if(dNewCost < dCost) {
dCost = dNewCost;
best = *pNtk;
best = *(pJob->pNtk);
} else {
n++;
}
}
*pNtk = best;
*(pJob->pNtk) = best;
if(nVerbose) {
std::cout << "end: cost = " << dCost << std::endl;
}
@ -218,6 +283,208 @@ namespace rrr {
default:
assert(0);
}
}
/* }}} */
/* {{{ Manage jobs */
template <typename Ntk, typename Opt>
void Scheduler<Ntk, Opt>::CreateJob(Ntk *pNtk_, int iSeed_) {
Job *pJob = new Job(nJobs++, pNtk_, iSeed_);
#ifdef ABC_USE_PTHREADS
if(fMultiThreading) {
{
std::unique_lock<std::mutex> l(mutexPendingJobs);
qPendingJobs.push(pJob);
condPendingJobs.notify_one();
}
return;
}
#endif
qPendingJobs.push(pJob);
}
template <typename Ntk, typename Opt>
void Scheduler<Ntk, Opt>::OnJobEnd(std::function<void(Job *pJob)> const &func) {
#ifdef ABC_USE_PTHREADS
if(fMultiThreading) {
Job *pJob = NULL;
{
std::unique_lock<std::mutex> l(mutexFinishedJobs);
while(qFinishedJobs.empty() || (fDeterministic && qFinishedJobs.top()->id != nFinishedJobs)) {
condFinishedJobs.wait(l);
}
pJob = qFinishedJobs.top();
qFinishedJobs.pop();
}
assert(pJob != NULL);
func(pJob);
delete pJob;
nFinishedJobs++;
return;
}
#endif
// if single thread
assert(!qPendingJobs.empty());
Job *pJob = qPendingJobs.front();
qPendingJobs.pop();
RunJob(*pOpt, pJob);
func(pJob);
delete pJob;
nFinishedJobs++;
}
/* }}} */
/* {{{ Thread */
#ifdef ABC_USE_PTHREADS
template <typename Ntk, typename Opt>
void Scheduler<Ntk, Opt>::Thread(Parameter const *pPar) {
Opt opt(pPar, CostFunction);
while(true) {
Job *pJob = NULL;
{
std::unique_lock<std::mutex> l(mutexPendingJobs);
while(!fTerminate && qPendingJobs.empty()) {
condPendingJobs.wait(l);
}
if(fTerminate) {
assert(qPendingJobs.empty());
return;
}
pJob = qPendingJobs.front();
qPendingJobs.pop();
}
assert(pJob != NULL);
RunJob(opt, pJob);
{
std::unique_lock<std::mutex> l(mutexFinishedJobs);
qFinishedJobs.push(pJob);
condFinishedJobs.notify_one();
}
}
}
#endif
/* }}} */
/* {{{ Constructors */
template <typename Ntk, typename Opt>
Scheduler<Ntk, Opt>::Scheduler(Ntk *pNtk, Parameter const *pPar) :
pNtk(pNtk),
nVerbose(pPar->nSchedulerVerbose),
iSeed(pPar->iSeed),
nFlow(pPar->nSchedulerFlow),
nRestarts(pPar->nRestarts),
fMultiThreading(pPar->nThreads > 1),
fPartitioning(pPar->nWindowSize > 0),
fDeterministic(pPar->fDeterministic),
nTimeout(pPar->nTimeout),
nJobs(0),
nFinishedJobs(0),
par(pPar),
pOpt(NULL) {
// prepare cost function
CostFunction = [](Ntk *pNtk) {
int nTwoInputSize = 0;
pNtk->ForEachInt([&](int id) {
nTwoInputSize += pNtk->GetNumFanins(id) - 1;
});
return nTwoInputSize;
};
#ifdef ABC_USE_PTHREADS
fTerminate = false;
if(fMultiThreading) {
vThreads.reserve(pPar->nThreads);
for(int i = 0; i < pPar->nThreads; i++) {
vThreads.emplace_back(std::bind(&Scheduler::Thread, this, pPar));
}
return;
}
#endif
assert(!fMultiThreading);
pOpt = new Opt(pPar, CostFunction);
}
template <typename Ntk, typename Opt>
Scheduler<Ntk, Opt>::~Scheduler() {
#ifdef ABC_USE_PTHREADS
if(fMultiThreading) {
{
std::unique_lock<std::mutex> l(mutexPendingJobs);
fTerminate = true;
condPendingJobs.notify_all();
}
for(std::thread &t: vThreads) {
t.join();
}
return;
}
#endif
delete pOpt;
}
/* }}} */
/* {{{ Run */
template <typename Ntk, typename Opt>
void Scheduler<Ntk, Opt>::Run() {
start = GetCurrentTime();
if(fPartitioning) {
pNtk->Sweep();
par.UpdateNetwork(pNtk);
while(nJobs < nRestarts) {
Ntk *pSubNtk = par.Extract(iSeed + nJobs);
if(pSubNtk == NULL) {
if(nJobs == nFinishedJobs) {
std::cout << "failed to extract a window" << std::endl;
break;
}
while(nFinishedJobs < nJobs) {
OnJobEnd([&](Job *pJob) {
std::cout << "job " << pJob->id << " finished (size = " << pJob->pNtk->GetNumInts() << ")" << std::endl;
par.Insert(pJob->pNtk);
});
}
} else {
CreateJob(pSubNtk, iSeed + nJobs);
std::cout << "job " << nJobs - 1 << " created (size = " << pSubNtk->GetNumInts() << ")" << std::endl;
}
}
while(nFinishedJobs < nJobs) {
OnJobEnd([&](Job *pJob) {
std::cout << "job " << pJob->id << " finished (size = " << pJob->pNtk->GetNumInts() << ")" << std::endl;
par.Insert(pJob->pNtk);
});
}
} else if(nRestarts > 0) {
fDeterministic = false; // it is deterministic anyways
double dCost = CostFunction(pNtk);
for(int i = 0; i < 1 + nRestarts; i++) {
Ntk *pCopy = new Ntk(*pNtk);
CreateJob(pCopy, iSeed + i);
}
for(int i = 0; i < 1 + nRestarts; i++) {
OnJobEnd([&](Job *pJob) {
double dNewCost = CostFunction(pJob->pNtk);
if(nVerbose) {
std::cout << "run " << pJob->id << ": cost = " << dNewCost << std::endl;
}
if(dNewCost < dCost) {
dCost = dNewCost;
*pNtk = *(pJob->pNtk);
}
delete pJob->pNtk;
});
}
} else {
CreateJob(pNtk, iSeed);
OnJobEnd([&](Job *pJob) { (void)pJob; });
}
time_point end = GetCurrentTime();
double elapsed_seconds = Duration(start, end);
if(nVerbose) {

View File

@ -1,15 +1,11 @@
#pragma once
#include <iostream>
#include <iomanip>
#include <vector>
#include <set>
#include <algorithm>
#include <random>
#include <bitset>
#include "rrrParameter.h"
#include "rrrTypes.h"
#include "rrrUtils.h"
ABC_NAMESPACE_CXX_HEADER_START
@ -87,7 +83,7 @@ namespace rrr {
public:
// constructors
Simulator();
Simulator(Ntk *pNtk, Parameter const *pPar);
Simulator(Parameter const *pPar);
~Simulator();
void UpdateNetwork(Ntk *pNtk_, bool fSame);
@ -267,7 +263,7 @@ namespace rrr {
void Simulator<Ntk>::SimulateNode(std::vector<word> &v, int id, int to_negate) {
itr x = v.end();
itr y = v.begin() + id * nWords;
bool cx;
bool cx = false;
switch(pNtk->GetNodeType(id)) {
case AND:
pNtk->ForEachFanin(id, [&](int fi, bool c) {
@ -292,7 +288,7 @@ namespace rrr {
template <typename Ntk>
bool Simulator<Ntk>::ResimulateNode(std::vector<word> &v, int id, int to_negate) {
itr x = v.end();
bool cx;
bool cx = false;
switch(pNtk->GetNodeType(id)) {
case AND:
pNtk->ForEachFanin(id, [&](int fi, bool c) {
@ -324,7 +320,7 @@ namespace rrr {
void Simulator<Ntk>::SimulateOneWordNode(std::vector<word> &v, int id, int offset, int to_negate) {
itr x = v.end();
itr y = v.begin() + id * nWords + offset;
bool cx;
bool cx = false;
switch(pNtk->GetNodeType(id)) {
case AND:
pNtk->ForEachFanin(id, [&](int fi, bool c) {
@ -476,7 +472,7 @@ namespace rrr {
});
*/
Clear(nWords, care.begin());
pNtk->ForEachPoDriver([&](int fi, bool c) {
pNtk->ForEachPoDriver([&](int fi) {
assert(fi != target);
for(int i = 0; i < nWords; i++) {
care[i] = care[i] | (vValues[fi * nWords + i] ^ vValues2[fi * nWords + i]);
@ -495,7 +491,9 @@ namespace rrr {
template <typename Ntk>
void Simulator<Ntk>::Save(int slot) {
if(slot >= vBackups.size()) {
assert(slot >= 0);
assert(!check_int_max(slot));
if(slot >= int_size(vBackups)) {
vBackups.resize(slot + 1);
}
vBackups[slot].nWords = nWords;
@ -522,7 +520,8 @@ namespace rrr {
template <typename Ntk>
void Simulator<Ntk>::Load(int slot) {
assert(slot < vBackups.size());
assert(slot >= 0);
assert(slot < int_size(vBackups));
nWords = vBackups[slot].nWords;
target = vBackups[slot].target;
vValues = vBackups[slot].vValues;
@ -551,8 +550,8 @@ namespace rrr {
}
template <typename Ntk>
Simulator<Ntk>::Simulator(Ntk *pNtk, Parameter const *pPar) :
pNtk(pNtk),
Simulator<Ntk>::Simulator(Parameter const *pPar) :
pNtk(NULL),
nVerbose(pPar->nSimulatorVerbose),
nWords(pPar->nWords),
target(-1),
@ -560,13 +559,8 @@ namespace rrr {
fUpdate(false),
nAdds(0),
nResets(0) {
pNtk->AddCallback(std::bind(&Simulator<Ntk>::ActionCallback, this, std::placeholders::_1));
vValues.resize(nWords * pNtk->GetNumNodes());
care.resize(nWords);
tmp.resize(nWords);
vAssignedStimuli.resize(nWords * pNtk->GetNumPis());
GenerateRandomStimuli();
Simulate();
}
template <typename Ntk>
@ -603,7 +597,7 @@ namespace rrr {
switch(pNtk->GetNodeType(id)) {
case AND: {
itr x = vValues.end();
bool cx;
bool cx = false;
pNtk->ForEachFaninIdx(id, [&](int idx2, int fi, bool c) {
if(idx == idx2) {
return;
@ -640,7 +634,7 @@ namespace rrr {
switch(pNtk->GetNodeType(id)) {
case AND: {
itr x = vValues.end();
bool cx;
bool cx = false;
pNtk->ForEachFanin(id, [&](int fi, bool c) {
if(x == vValues.end()) {
x = vValues.begin() + fi * nWords;
@ -680,7 +674,7 @@ namespace rrr {
std::cout << std::endl;
}
// record care pi indices
assert((int)vCex.size() == pNtk->GetNumPis());
assert(int_size(vCex) == pNtk->GetNumPis());
std::vector<int> vCarePiIdxs;
for(int idx = 0; idx < pNtk->GetNumPis(); idx++) {
switch(vCex[idx]) {
@ -792,7 +786,7 @@ namespace rrr {
}
});
Clear(1, care.begin() + iWord);
pNtk->ForEachPoDriver([&](int fi, bool c) {
pNtk->ForEachPoDriver([&](int fi) {
assert(fi != target);
care[iWord] = care[iWord] | (vValues[fi * nWords + iWord] ^ vValues2[fi * nWords + iWord]);
});

View File

@ -1,10 +1,7 @@
#pragma once
#include <iostream>
#include <vector>
#include <string>
#include <chrono>
#include <cassert>
ABC_NAMESPACE_CXX_HEADER_START
@ -32,44 +29,6 @@ namespace rrr {
TEMP_FALSE
};
/* {{{ VarValue functions */
static inline VarValue DecideVarValue(VarValue x) {
switch(x) {
case UNDEF:
assert(0);
case TRUE:
return TRUE;
case FALSE:
return FALSE;
case TEMP_TRUE:
return TRUE;
case TEMP_FALSE:
return FALSE;
default:
assert(0);
}
}
static inline char GetVarValueChar(VarValue x) {
switch(x) {
case UNDEF:
return 'x';
case TRUE:
return '1';
case FALSE:
return '0';
case TEMP_TRUE:
return 't';
case TEMP_FALSE:
return 'f';
default:
assert(0);
}
}
/* }}} */
enum ActionType {
NONE,
REMOVE_FANIN,
@ -82,7 +41,8 @@ namespace rrr {
SORT_FANINS,
SAVE,
LOAD,
POP_BACK
POP_BACK,
INSERT
};
struct Action {
@ -96,112 +56,10 @@ namespace rrr {
std::vector<int> vFanouts;
};
/* {{{ Action functions */
static inline void PrintAction(Action action) {
switch(action.type) {
case REMOVE_FANIN:
std::cout << "remove fanin";
break;
case REMOVE_UNUSED:
std::cout << "remove unused";
break;
case REMOVE_BUFFER:
std::cout << "remove buffer";
break;
case REMOVE_CONST:
std::cout << "remove const";
break;
case ADD_FANIN:
std::cout << "add fanin";
break;
case TRIVIAL_COLLAPSE:
std::cout << "trivial collapse";
break;
case TRIVIAL_DECOMPOSE:
std::cout << "trivial decompose";
break;
case SORT_FANINS:
std::cout << "sort fanins";
break;
case SAVE:
std::cout << "save";
break;
case LOAD:
std::cout << "load";
break;
case POP_BACK:
std::cout << "pop back";
break;
default:
assert(0);
}
std::cout << ":";
if(action.id != -1) {
std::cout << " node " << action.id;
}
if(action.fi != -1) {
std::cout << " fanin " << (action.c? "!": "") << action.fi;
}
if(action.idx != -1) {
std::cout << " index " << action.idx;
}
std::cout << std::endl;
if(!action.vFanins.empty()) {
std::cout << "\t" << "fanins: ";
std::string delim = "";
for(int fi: action.vFanins) {
std::cout << delim << fi;
delim = ", ";
}
std::cout << std::endl;
}
if(!action.vIndices.empty()) {
std::cout << "\t" << "indices: ";
std::string delim = "";
for(int fi: action.vIndices) {
std::cout << delim << fi;
delim = ", ";
}
std::cout << std::endl;
}
if(!action.vFanouts.empty()) {
std::cout << "\t" << "fanouts: ";
std::string delim = "";
for(int fo: action.vFanouts) {
std::cout << delim << fo;
delim = ", ";
}
std::cout << std::endl;
}
}
/* }}} */
using seconds = int64_t;
using clock_type = std::chrono::steady_clock;
using time_point = std::chrono::time_point<clock_type>;
/* {{{ Time functions */
static inline time_point GetCurrentTime() {
return clock_type::now();
}
static inline seconds DurationInSeconds(time_point start, time_point end) {
seconds t = (std::chrono::duration_cast<std::chrono::seconds>(end - start)).count();
assert(t >= 0);
return t;
}
static inline double Duration(time_point start, time_point end) {
double t = (std::chrono::duration<double>(end - start)).count();
assert(t >= 0);
return t;
}
/* }}} */
}
ABC_NAMESPACE_CXX_HEADER_END

215
src/opt/rrr/rrrUtils.h Normal file
View File

@ -0,0 +1,215 @@
#pragma once
#include <iostream>
#include <iomanip>
#include <vector>
#include <set>
#include <string>
#include <functional>
#include <limits>
#include <type_traits>
#include <cassert>
#include "rrrTypes.h"
ABC_NAMESPACE_CXX_HEADER_START
namespace rrr {
/* {{{ Invocable */
#if defined(__cpp_lib_is_invocable)
template <typename Fn, typename... Args>
using is_invokable = std::is_invocable<Fn, Args...>;
#else
template <typename Fn, typename... Args>
struct is_invokable: std::is_constructible<std::function<void(Args...)>, std::reference_wrapper<typename std::remove_reference<Fn>::type>> {};
#endif
/* }}} */
/* {{{ Int size */
template <template <typename...> typename Container, typename ... Ts>
static inline int int_size(Container<Ts...> const &c) {
assert(c.size() <= (typename Container<Ts...>::size_type)std::numeric_limits<int>::max());
return c.size();
}
template <template <typename...> typename Container, typename ... Ts>
static inline bool check_int_size(Container<Ts...> const &c) {
return c.size() <= (typename Container<Ts...>::size_type)std::numeric_limits<int>::max();
}
static inline bool check_int_max(int i) {
return i == std::numeric_limits<int>::max();
}
/* }}} */
/* {{{ Print helpers */
template <typename T>
std::ostream& operator<<(std::ostream& os, const std::vector<T>& v) {
std::string delim;
os << "[";
for(T const &e: v) {
os << delim << e;
delim = ", ";
}
os << "]";
return os;
}
template <typename T>
std::ostream& operator<<(std::ostream& os, const std::set<T>& s) {
std::string delim;
os << "{";
for(T const &e: s) {
os << delim << e;
delim = ", ";
}
os << "}";
return os;
}
void PrintComplementedEdges(std::function<void(std::function<void(int, bool)> const &)> const &ForEachEdge) {
std::string delim;
std::cout << "[";
ForEachEdge([&] (int id, bool c) {
std::cout << delim << (c? "!": "") << id;
delim = ", ";
});
std::cout << "]";
}
/* }}} */
/* {{{ VarValue functions */
static inline VarValue DecideVarValue(VarValue x) {
switch(x) {
case UNDEF:
assert(0);
case TRUE:
return TRUE;
case FALSE:
return FALSE;
case TEMP_TRUE:
return TRUE;
case TEMP_FALSE:
return FALSE;
default:
assert(0);
}
}
static inline char GetVarValueChar(VarValue x) {
switch(x) {
case UNDEF:
return 'x';
case TRUE:
return '1';
case FALSE:
return '0';
case TEMP_TRUE:
return 't';
case TEMP_FALSE:
return 'f';
default:
assert(0);
}
}
/* }}} */
/* {{{ Action functions */
static inline void PrintAction(Action action) {
switch(action.type) {
case REMOVE_FANIN:
std::cout << "remove fanin";
break;
case REMOVE_UNUSED:
std::cout << "remove unused";
break;
case REMOVE_BUFFER:
std::cout << "remove buffer";
break;
case REMOVE_CONST:
std::cout << "remove const";
break;
case ADD_FANIN:
std::cout << "add fanin";
break;
case TRIVIAL_COLLAPSE:
std::cout << "trivial collapse";
break;
case TRIVIAL_DECOMPOSE:
std::cout << "trivial decompose";
break;
case SORT_FANINS:
std::cout << "sort fanins";
break;
case SAVE:
std::cout << "save";
break;
case LOAD:
std::cout << "load";
break;
case POP_BACK:
std::cout << "pop back";
break;
case INSERT:
std::cout << "insert";
break;
default:
assert(0);
}
std::cout << ":";
if(action.id != -1) {
std::cout << " node " << action.id;
}
if(action.fi != -1) {
std::cout << " fanin " << (action.c? "!": "") << action.fi;
}
if(action.idx != -1) {
std::cout << " index " << action.idx;
}
std::cout << std::endl;
if(!action.vFanins.empty()) {
std::cout << "\t" << "fanins: " << action.vFanins << std::endl;
}
if(!action.vIndices.empty()) {
std::cout << "\t" << "indices: " << action.vIndices << std::endl;
}
if(!action.vFanouts.empty()) {
std::cout << "\t" << "fanouts: " << action.vFanouts << std::endl;
}
}
/* }}} */
/* {{{ Time functions */
static inline time_point GetCurrentTime() {
return clock_type::now();
}
static inline seconds DurationInSeconds(time_point start, time_point end) {
seconds t = (std::chrono::duration_cast<std::chrono::seconds>(end - start)).count();
assert(t >= 0);
return t;
}
static inline double Duration(time_point start, time_point end) {
double t = (std::chrono::duration<double>(end - start)).count();
assert(t >= 0);
return t;
}
/* }}} */
}
ABC_NAMESPACE_CXX_HEADER_END