diff --git a/src/algorithm/CNDFS.cpp b/src/algorithm/CNDFS.cpp index 73e186f1a5171a4e677b67f3f3855bdd2a2e7eda..c983e66022f572224c56b62a8ca6eb947414fd0e 100644 --- a/src/algorithm/CNDFS.cpp +++ b/src/algorithm/CNDFS.cpp @@ -11,17 +11,16 @@ #include <utility> #include <spot/twa/twa.hh> #include <bddx.h> -#include <cstddef> #include <deque> #include <atomic> #include <condition_variable> -#include "misc/SafeDequeue.h" +#include <algorithm> #include "misc/stacksafe.h" using namespace std; -CNDFS::CNDFS(ModelCheckBaseMT *mcl, const spot::twa_graph_ptr &af, const uint16_t &nbTh) : mMcl(mcl), mAa(af), mNbTh(nbTh) -{ +CNDFS::CNDFS(ModelCheckBaseMT *mcl, const spot::twa_graph_ptr &af, const uint16_t &nbTh) : mMcl(mcl), mAa(af), + mNbTh(nbTh) { getInitialState(); spawnThreads(); } @@ -46,168 +45,151 @@ void CNDFS::spawnThreads() { void CNDFS::threadHandler(void *context) { ((CNDFS *) context)->threadRun(); } + void CNDFS::threadRun() { uint16_t idThread = mIdThread++; - vector<myState_t*> Rp; - dfsBlue(mInitStatePtr,Rp,idThread); + vector<myState_t *> Rp; + dfsBlue(mInitStatePtr, Rp, idThread); } -//get initial state of the product automata -void CNDFS::getInitialState(){ - mInitStatePtr = new myState_t; //static_cast<_state *>(malloc(sizeof(_state))); +/* + * Build initial state of the product automata + */ +void CNDFS::getInitialState() { + mInitStatePtr = new myState_t; mInitStatePtr->left = mMcl->getInitialMetaState(); mInitStatePtr->right = mAa->get_init_state(); - //mInitStatePtr->new_successors = nullptr; mInitStatePtr->isAcceptance = mAa->state_is_accepting(mAa->get_init_state()); mInitStatePtr->isConstructed = true; + mlBuiltStates.push_back(mInitStatePtr); } //this function is to build a state with list of successor initially null -myState_t* CNDFS::buildState(LDDState* left, spot::state* right, bool acc, bool constructed, bool cyan){ - myState_t * buildStatePtr = new myState_t; +myState_t *CNDFS::buildState(LDDState *left, spot::state *right, bool acc, bool constructed, bool cyan) { + myState_t *buildStatePtr = new myState_t; buildStatePtr->left = left; - buildStatePtr->right = dynamic_cast<const spot::twa_graph_state *>(right); + buildStatePtr->right = (spot::twa_graph_state *) right; buildStatePtr->isAcceptance = acc; buildStatePtr->isConstructed = constructed; - return buildStatePtr; } -std::ostream & operator<<(std::ostream & Str,myState_t* state) { - Str << "({ Sog state= " << state->left << ", BA state= " << state->right << ", acceptance= " << state->isAcceptance << ", constructed= " << state->isConstructed << ", red= " << state->red << ", blue= " << state->blue << " }" << endl; - int i = 0; - for (const auto & ii : state->new_successors) - { - cout << "succ num " << i << ii.first << " with transition " << ii.second<< endl; - i++; - } +std::ostream &operator<<(std::ostream &Str, myState_t *state) { + Str << "({ Sog state= " << state->left << ", BA state= " << state->right << ", acceptance= " << state->isAcceptance + << ", constructed= " << state->isConstructed << ", red= " << state->red << ", blue= " << state->blue << " }" + << endl; + int i = 0; + for (const auto &ii: state->new_successors) { + cout << "succ num " << i << ii.first << " with transition " << ii.second << endl; + i++; + } return Str; } - - -//block all threads while awaitCondition is false -//void CNDFS::WaitForTestCompleted(_state* state) { -// while ( awaitCondition(state) == false) ; -//} - -void CNDFS::dfsRed(myState_t *state, vector<myState_t*>& Rp,uint8_t idThread) -{ +void CNDFS::dfsRed(myState_t *state, vector<myState_t *> &Rp, uint8_t idThread) { cout << "dfsRed" << endl; Rp.push_back(state); computeSuccessors(state); - for (const auto& succ:state->new_successors) { - if (succ.first->cyan[idThread]) - { - cout << "cycle detected" << endl; - exit(0); - } - // unvisited and not red state - if ((find(Rp.begin(), Rp.end(), state) != Rp.end()) && ! succ.first->red ) - dfsRed(succ.first, Rp,idThread); + for (const auto &succ: state->new_successors) { + if (succ.first->cyan[idThread]) { + cout << "cycle detected" << endl; + exit(0); + } + // unvisited and not red state + if ((find(Rp.begin(), Rp.end(), state) != Rp.end()) && !succ.first->red) + dfsRed(succ.first, Rp, idThread); } } +/* + * Check whether a product state exists or not + */ +myState_t *CNDFS::isStateBuilt(LDDState *sogState, spot::twa_graph_state *spotState) { + auto compare = [sogState, spotState](myState_t *state) { + return (state->left == sogState && state->right == spotState); + }; + auto result = find_if(begin(mlBuiltStates), end(mlBuiltStates), compare); + return result == end(mlBuiltStates) ? nullptr : *result; +} + //compute new successors of a product state -void CNDFS::computeSuccessors(myState_t *state) -{ - auto sog_current_state = state->left; - const spot::twa_graph_state* ba_current_state = state->right; +void CNDFS::computeSuccessors(myState_t *state) { + if (state->succState == SuccState::built) return; + std::unique_lock lk(mMutexStatus); + if (state->succState == SuccState::beingbuilt) { + mMutexStatus.unlock(); + mDataCondWait.wait(lk, [state] { return state->succState == SuccState::built; }); + return; + } + state->succState = SuccState::beingbuilt; + lk.unlock(); + auto sog_current_state = state->left; + const spot::twa_graph_state *ba_current_state = state->right; while (!sog_current_state->isCompletedSucc()); auto p = mAa->get_dict(); //avoir le dictionnaire bdd,proposition atomique //fetch the state's atomic proposition - for (const auto & vv: sog_current_state->getMarkedPlaces(mMcl->getPlaceProposition())) - { - auto name = string(mMcl->getPlace(vv)); - auto f = spot::formula::ap(name); - transitionNames.push(f); + /* for (const auto & vv: sog_current_state->getMarkedPlaces(mMcl->getPlaceProposition())) + { + auto name = string(mMcl->getPlace(vv)); + auto f = spot::formula::ap(name); + transitionNames.push(f); - } + }*/ //iterate over the successors of a current aggregate - for (const auto &elt : sog_current_state->Successors) - { + for (const auto &elt: sog_current_state->Successors) { auto transition = elt.second; // je récupère le numéro du transition auto name = string(mMcl->getTransition(transition)); // récuprer le nom de la transition auto f = spot::formula::ap(name);// récuperer la proposition atomique qui correspond à la transition - transitionNames.push(f); // push state'S AP to edge'S AP - - SafeDequeue<spot::formula> tempTransitionNames = transitionNames; - while (!tempTransitionNames.empty()) - { - //iterate over the successors of a BA state - auto ii = mAa->succ_iter(ba_current_state); - if (ii->first()) - do { - if (p->var_map.find(tempTransitionNames.front()) !=p->var_map.end()) - { - //fetch the transition of BA that have the same AP as the SOG transition - const bdd result = bdd_ithvar((p->var_map.find(tempTransitionNames.front()))->second); - if ((ii->cond() & result) != bddfalse) - { - //make a copy that we can iterate -// SafeDequeue<myCouple> tempSharedPool = sharedPool; - SafeDequeue<myState_t*> tempSharedPool = mSharedPoolTemp; - while (!tempSharedPool.empty()) - { - std::lock_guard<std::mutex> guard(mMutex); -// if ((tempSharedPool.front().first == sog_current_state->Successors.at(i).first) && -// (tempSharedPool.front().second == const_cast<spot::state *>(ii->dst()))) - if ((tempSharedPool.front()->left == elt.first) && (tempSharedPool.front()->right == const_cast<spot::state *>(ii->dst()))) - { -// nd->cyan = true; - state->new_successors.push_back(make_pair(tempSharedPool.front(), transition)); - } else - { - //new terminal state without successors - //state_is_accepting() should only be called on automata with state-based acceptance - myState_t *nd = buildState(elt.first, - const_cast<spot::state *>(ii->dst()), - mAa->state_is_accepting(ii->dst()), true, false); - state->new_successors.push_back(make_pair(nd, transition)); - } -// - - } - } + //iterate over the successors of a BA state + auto ii = mAa->succ_iter(ba_current_state); + if (ii->first()) + do { + if (p->var_map.find(f) != p->var_map.end()) { + //fetch the transition of BA that have the same AP as the SOG transition + const bdd result = bdd_ithvar((p->var_map.find(f))->second); + if ((ii->cond() & result) != bddfalse) { + std::unique_lock lk(mMutex); + auto result = isStateBuilt(elt.first, (spot::twa_graph_state *) ii->dst()); + if (result) { + state->new_successors.push_back(make_pair(result, transition)); + } else { + myState_t *nd = buildState(elt.first, + const_cast<spot::state *>(ii->dst()), + mAa->state_is_accepting(ii->dst()), true, false); + state->new_successors.push_back(make_pair(nd, transition)); } } - while (ii->next()); - mAa->release_iter(ii); - tempTransitionNames.try_pop(tempTransitionNames.front()); - } - transitionNames.try_pop(transitionNames.front()); + } + } while (ii->next()); + mAa->release_iter(ii); } + state->succState = SuccState::built; + mDataCondWait.notify_all(); } - //Perform the dfsBlue -void CNDFS::dfsBlue(myState_t *state, vector<myState_t*>& Rp,uint8_t idThread) { - state->cyan[idThread]=true; - for (const auto & succ:state->new_successors) - { - if (!succ.first->blue && !succ.first->cyan[idThread]) - { - dfsBlue(succ.first,Rp,idThread); - } +void CNDFS::dfsBlue(myState_t *state, vector<myState_t *> &Rp, uint8_t idThread) { + state->cyan[idThread] = true; + for (const auto &succ: state->new_successors) { + if (!succ.first->blue && !succ.first->cyan[idThread]) { + dfsBlue(succ.first, Rp, idThread); + } } state->blue = true; - if (state->isAcceptance) - { + if (state->isAcceptance) { cout << "Acceptance state detected " << endl; - if (state->left->isDeadLock() || state->left->isDiv()) - { - cout << "cycle detected: an aggregate with deal_lock or live_lock" << endl; + if (state->left->isDeadLock() || state->left->isDiv()) { + cout << "cycle detected: an aggregate with deal_lock or live_lock" << endl; exit(0); - } else - { + } else { Rp.clear(); - dfsRed(state, Rp,idThread); //looking for an accepting cycle - // the thread processed the current state waits for all visited accepting nodes (non seed, non red) to turn red - // the late red coloring forces the other acceptance states to be processed in post-order by the other threads + dfsRed(state, Rp, idThread); //looking for an accepting cycle + // the thread processed the current state waits for all visited accepting nodes (non seed, non red) to turn red + // the late red coloring forces the other acceptance states to be processed in post-order by the other threads bool cond; do { cond = true; @@ -218,7 +200,7 @@ void CNDFS::dfsBlue(myState_t *state, vector<myState_t*>& Rp,uint8_t idThread) { } } while (!cond); - for (const auto& qu: Rp) // prune other dfsRed + for (const auto &qu: Rp) // prune other dfsRed { qu->red = true; } @@ -227,5 +209,6 @@ void CNDFS::dfsBlue(myState_t *state, vector<myState_t*>& Rp,uint8_t idThread) { } state->cyan[idThread] = false; } + spot::bdd_dict_ptr *CNDFS::m_dict_ptr; diff --git a/src/algorithm/CNDFS.h b/src/algorithm/CNDFS.h index 87369446ad6717881c4429f1ba8998f45d4090ac..c58e6ff4d397cc3d2e5f8a30ec1c2d1af3574ce3 100644 --- a/src/algorithm/CNDFS.h +++ b/src/algorithm/CNDFS.h @@ -3,6 +3,7 @@ // #ifndef PMC_SOG_CNDFS_H #define PMC_SOG_CNDFS_H + #include "../ModelCheckBaseMT.h" #include <spot/tl/apcollect.hh> #include <cstdint> @@ -13,49 +14,64 @@ #include <condition_variable> #include "misc/SafeDequeue.h" -using namespace std ; -typedef pair<struct myState_t*, int> coupleSuccessor; -static constexpr uint8_t MAX_THREADS=64; +using namespace std; +typedef pair<struct myState_t *, int> coupleSuccessor; +static constexpr uint8_t MAX_THREADS = 64; + +enum class SuccState {notyet,beingbuilt,built}; struct myState_t { LDDState *left; - const spot::twa_graph_state* right; - vector<pair<struct myState_t*, int>> new_successors; + const spot::twa_graph_state *right; + vector<pair<struct myState_t *, int>> new_successors; bool isAcceptance {false}; bool isConstructed {false}; - array<bool,MAX_THREADS> cyan {false}; - atomic<bool> blue {false}; - atomic<bool> red {false}; + array<bool, MAX_THREADS> cyan {false}; + atomic<bool> blue{false}; + atomic<bool> red{false}; + SuccState succState {SuccState::notyet}; }; class CNDFS { private: - - ModelCheckBaseMT * mMcl; + ModelCheckBaseMT *mMcl; spot::twa_graph_ptr mAa; uint16_t mNbTh; atomic<uint8_t> mIdThread; - std::thread* mlThread[MAX_THREADS]; - mutex mMutex; + std::thread *mlThread[MAX_THREADS]; + mutex mMutex,mMutexStatus; + std::condition_variable mDataCondWait; condition_variable cv; - void spawnThreads(); - myState_t * mInitStatePtr; - SafeDequeue<struct myState_t*> mSharedPoolTemp; - static spot::bdd_dict_ptr* m_dict_ptr; + myState_t *mInitStatePtr; + vector<myState_t *> mlBuiltStates; + SafeDequeue<struct myState_t *> mSharedPoolTemp; + static spot::bdd_dict_ptr *m_dict_ptr; + void getInitialState(); + + void spawnThreads(); + static void threadHandler(void *context); + void threadRun(); + + void computeSuccessors(myState_t *state); + + myState_t *buildState(LDDState *left, spot::state *right, bool acc, bool constructed, bool cyan); + myState_t* isStateBuilt(LDDState *sogState,spot::twa_graph_state *spotState); public: -// SafeDequeue<myCouple> sharedPool; - SafeDequeue<spot::formula> transitionNames; - SafeDequeue<coupleSuccessor> new_successor; - CNDFS(ModelCheckBaseMT *mcl,const spot::twa_graph_ptr &af,const uint16_t& nbTh); + CNDFS(ModelCheckBaseMT *mcl, const spot::twa_graph_ptr &af, const uint16_t &nbTh); + virtual ~CNDFS(); - void computeSuccessors(myState_t *state); - void dfsBlue(myState_t *state, vector<myState_t*>& Rp,uint8_t idThread); - void dfsRed(myState_t* state, vector<myState_t*>& Rp,uint8_t idThread); - void WaitForTestCompleted(myState_t* state); - myState_t* buildState(LDDState* left, spot::state* right, bool acc, bool constructed,bool cyan); + + + void dfsBlue(myState_t *state, vector<myState_t *> &Rp, uint8_t idThread); + + void dfsRed(myState_t *state, vector<myState_t *> &Rp, uint8_t idThread); + + + + };