23#include <spot/bricks/brick-hashset>
28#include <spot/misc/common.hh>
29#include <spot/kripke/kripke.hh>
30#include <spot/misc/fixpool.hh>
31#include <spot/misc/timer.hh>
32#include <spot/twacube/twacube.hh>
33#include <spot/twacube/fwd.hh>
34#include <spot/mc/intersect.hh>
35#include <spot/mc/mc.hh>
41 template<
typename State,
89 brick::hash::hash128_t
116 map_(uf.map_), tid_(uf.tid_), size_(std::thread::hardware_concurrency()),
117 nb_th_(std::thread::hardware_concurrency()), inserted_(0),
123 map_(map), tid_(tid), size_(std::thread::hardware_concurrency()),
124 nb_th_(std::thread::hardware_concurrency()), inserted_(0),
132 std::pair<claim_status, uf_element*>
135 unsigned w_id = (1U << tid_);
149 auto it = map_.insert({v});
160 if (a_root->
uf_status_.load() == uf_status::DEAD)
161 return {claim_status::CLAIM_DEAD, *it};
163 if ((a_root->
worker_.load() & w_id) != 0)
164 return {claim_status::CLAIM_FOUND, *it};
166 atomic_fetch_or(&(a_root->
worker_), w_id);
167 while (a_root->
parent.load() != a_root)
169 a_root =
find(a_root);
170 atomic_fetch_or(&(a_root->
worker_), w_id);
173 return {claim_status::CLAIM_NEW, *it};
186 parent = y->
parent.load();
191 parent = x->
parent.load();
203 if (a_root == b_root)
206 if (a_root->
parent.load() == a_root)
217 if (std::atomic_compare_exchange_strong
218 (&(a->
uf_status_), &expected, uf_status::LOCK))
220 if (a->
parent.load() == a)
240 bool dontcare =
false;
242 if (a_list ==
nullptr)
247 auto expected = list_status::BUSY;
248 bool b = std::atomic_compare_exchange_strong
249 (&(a_list->
list_status_), &expected, list_status::LOCK);
254 a_list = a_list->
next_.load();
278 if (a_root == b_root)
282 std::lock_guard<std::mutex> rlock(a_root->
acc_mutex_);
287 while (a_root->
parent.load() != a_root)
289 a_root =
find(a_root);
290 std::lock_guard<std::mutex> rlock(a_root->
acc_mutex_);
297 r = std::max(a_root, b_root);
298 q = std::min(a_root, b_root);
303 if (a_list ==
nullptr)
310 if (b_list ==
nullptr)
317 SPOT_ASSERT(a_list->
list_status_.load() == list_status::LOCK);
318 SPOT_ASSERT(b_list->
list_status_.load() == list_status::LOCK);
323 SPOT_ASSERT(a_next !=
nullptr);
324 SPOT_ASSERT(b_next !=
nullptr);
326 a_list->
next_.store(b_next);
327 b_list->
next_.store(a_next);
331 unsigned q_worker = q->
worker_.load();
332 unsigned r_worker = r->
worker_.load();
333 if ((q_worker|r_worker) != r_worker)
335 atomic_fetch_or(&(r->
worker_), q_worker);
336 while (r->
parent.load() != r)
339 atomic_fetch_or(&(r->
worker_), q_worker);
345 std::lock_guard<std::mutex> rlock(r->
acc_mutex_);
346 std::lock_guard<std::mutex> qlock(q->
acc_mutex_);
351 while (r->
parent.load() != r)
354 std::lock_guard<std::mutex> rlock(r->
acc_mutex_);
355 std::lock_guard<std::mutex> qlock(q->
acc_mutex_);
377 if (a_status == list_status::BUSY)
380 if (a_status == list_status::DONE)
407 while (status != uf_status::DEAD)
409 if (status == uf_status::LIVE)
410 *sccfound = std::atomic_compare_exchange_strong
411 (&(a_root->
uf_status_), &status, uf_status::DEAD);
422 if (b_status == list_status::BUSY)
425 if (b_status == list_status::DONE)
429 SPOT_ASSERT(b_status == list_status::DONE);
430 SPOT_ASSERT(a_status == list_status::DONE);
445 if (a_status == list_status::DONE)
448 if (a_status == list_status::BUSY)
449 std::atomic_compare_exchange_strong
477 template<
typename State,
typename SuccIterator,
478 typename StateHash,
typename StateEqual>
507 std::atomic<bool>& stop):
508 sys_(sys), twa_(
twa), uf_(*
uf), tid_(tid),
509 nb_th_(std::thread::hardware_concurrency()),
513 State, SuccIterator>::value,
514 "error: does not match the kripkecube requirements");
524 State init_kripke = sys_.initial(tid_);
525 unsigned init_twa = twa_->get_initial();
526 auto pair = uf_.make_claim(init_kripke, init_twa);
527 todo_.push_back(pair.second);
528 Rp_.push_back(pair.second);
531 while (!todo_.empty())
533 bloemen_recursive_start:
534 while (!stop_.load(std::memory_order_relaxed))
536 bool sccfound =
false;
537 uf_element* v_prime = uf_.pick_from_list(todo_.back(), &sccfound);
538 if (v_prime ==
nullptr)
545 auto it_kripke = sys_.succ(v_prime->st_kripke, tid_);
546 auto it_prop = twa_->succ(v_prime->st_prop);
547 forward_iterators(sys_, twa_, it_kripke, it_prop,
true, tid_);
548 while (!it_kripke->done())
550 auto w = uf_.make_claim(it_kripke->state(),
551 twa_->trans_storage(it_prop, tid_)
553 auto trans_acc = twa_->trans_storage(it_prop, tid_).acc_;
555 if (w.first == uf::claim_status::CLAIM_NEW)
557 todo_.push_back(w.second);
558 Rp_.push_back(w.second);
560 sys_.recycle(it_kripke, tid_);
561 goto bloemen_recursive_start;
563 else if (w.first == uf::claim_status::CLAIM_FOUND)
571 scc_acc |= uf_.unite(w.second, w.second, scc_acc);
573 while (!uf_.sameset(todo_.back(), w.second))
577 uf_.unite(r, Rp_.back(), scc_acc);
582 auto root = uf_.find(w.second);
583 std::lock_guard<std::mutex> lock(root->acc_mutex_);
588 if (twa_->acc().accepting(scc_acc))
590 sys_.recycle(it_kripke, tid_);
593 tm_.
stop(
"DFS thread " + std::to_string(tid_));
597 forward_iterators(sys_, twa_, it_kripke, it_prop,
600 uf_.remove_from_list(v_prime);
601 sys_.recycle(it_kripke, tid_);
604 if (todo_.back() == Rp_.back())
614 tm_.
start(
"DFS thread " + std::to_string(tid_));
620 bool tst_val =
false;
622 bool exchanged = stop_.compare_exchange_strong(tst_val, new_val);
625 tm_.
stop(
"DFS thread " + std::to_string(tid_));
649 return tm_.
timer(
"DFS thread " + std::to_string(tid_)).
walltime();
673 return "Not implemented";
679 std::vector<uf_element*> todo_;
680 std::vector<uf_element*> Rp_;
684 unsigned inserted_ = 0;
685 unsigned states_ = 0;
686 unsigned transitions_ = 0;
688 bool is_empty_ =
true;
690 std::atomic<bool>& stop_;
691 bool finisher_ =
false;
A fixed-size memory pool implementation.
Definition fixpool.hh:46
void * allocate()
Allocate size bytes of memory.
Definition fixpool.hh:88
This class allows to ensure (at compile time) if a given parameter is of type kripkecube....
Definition kripke.hh:71
Iterable Union-Find for parallel emptiness-check algorithms.
Definition bloemen_ec.hh:45
uf_element * find(uf_element *a)
Find root of element using path compression.
Definition bloemen_ec.hh:177
claim_status
Status values for claim operations.
Definition bloemen_ec.hh:53
~iterable_uf_ec()
Destructor.
Definition bloemen_ec.hh:129
void unlock_root(uf_element *a)
Unlock root element.
Definition bloemen_ec.hh:229
list_status
Status values for list operations.
Definition bloemen_ec.hh:51
acc_cond::mark_t unite(uf_element *a, uf_element *b, acc_cond::mark_t acc)
Unite two sets with acceptance condition; return new acc.
Definition bloemen_ec.hh:266
brick::hashset::FastConcurrent< uf_element *, uf_element_hasher > shared_map
Concurrent hashset for shared state storage.
Definition bloemen_ec.hh:112
unsigned inserted()
Return number of successfully inserted states.
Definition bloemen_ec.hh:455
void remove_from_list(uf_element *a)
Mark element as removed from list.
Definition bloemen_ec.hh:439
iterable_uf_ec(shared_map &map, unsigned tid)
Constructor from shared map and thread ID.
Definition bloemen_ec.hh:122
uf_element * lock_list(uf_element *a)
Lock next element in list.
Definition bloemen_ec.hh:235
iterable_uf_ec(const iterable_uf_ec< State, StateHash, StateEqual > &uf)
Copy constructor.
Definition bloemen_ec.hh:115
std::pair< claim_status, uf_element * > make_claim(State kripke, unsigned prop)
Try to claim a state; returns status and element pointer.
Definition bloemen_ec.hh:133
void unlock_list(uf_element *a)
Unlock list element.
Definition bloemen_ec.hh:259
uf_status
Status values for union-find elements.
Definition bloemen_ec.hh:49
bool sameset(uf_element *a, uf_element *b)
Check if elements are in same set.
Definition bloemen_ec.hh:197
bool lock_root(uf_element *a)
Lock root element if live; return true if successful.
Definition bloemen_ec.hh:212
uf_element * pick_from_list(uf_element *u, bool *sccfound)
Pick element from list; mark SCC as dead if complete.
Definition bloemen_ec.hh:367
Interface for a Kripke structure.
Definition kripke.hh:178
This class is a template representation of a Kripke structure. It is composed of two template paramet...
Definition kripke.hh:40
Bloemen parallel SCC decomposition algorithm for emptiness check.
Definition bloemen_ec.hh:480
std::string trace()
Return trace (not implemented)
Definition bloemen_ec.hh:671
mc_rvalue result()
Return emptiness check result.
Definition bloemen_ec.hh:665
unsigned transitions()
Return number of transitions traversed.
Definition bloemen_ec.hh:641
unsigned states()
Return number of states visited.
Definition bloemen_ec.hh:635
void run()
Run the algorithm.
Definition bloemen_ec.hh:521
typename uf::shared_map shared_map
Type alias for shared map.
Definition bloemen_ec.hh:493
typename uf::uf_element uf_element
Type alias for union-find element.
Definition bloemen_ec.hh:488
int sccs()
Return number of SCCs found.
Definition bloemen_ec.hh:659
~swarmed_bloemen_ec()=default
Destructor.
std::string name()
Return algorithm name.
Definition bloemen_ec.hh:653
void setup()
Setup thread resources.
Definition bloemen_ec.hh:612
void finalize()
Finalize thread resources.
Definition bloemen_ec.hh:618
iterable_uf_ec< State, StateHash, StateEqual > uf
Type alias for iterable union-find.
Definition bloemen_ec.hh:486
static shared_struct * make_shared_structure(shared_map m, unsigned i)
Create shared structure for thread tid.
Definition bloemen_ec.hh:496
unsigned walltime()
Return wall time in milliseconds.
Definition bloemen_ec.hh:647
bool finisher()
Check if this thread finished the search.
Definition bloemen_ec.hh:629
swarmed_bloemen_ec(kripkecube< State, SuccIterator > &sys, twacube_ptr twa, shared_map &map, iterable_uf_ec< State, StateHash, StateEqual > *uf, unsigned tid, std::atomic< bool > &stop)
Constructor for parallel Bloemen algorithm.
Definition bloemen_ec.hh:502
A map of timer, where each timer has a name.
Definition timer.hh:231
void stop(const std::string &name)
Stop timer name.
Definition timer.hh:251
void start(const std::string &name)
Start a timer with name name.
Definition timer.hh:240
const spot::timer & timer(const std::string &name) const
Return the timer name.
Definition timer.hh:276
std::chrono::milliseconds::rep walltime() const
Return cumulative wall time.
Definition timer.hh:208
A Transition-based ω-Automaton.
Definition twa.hh:648
size_t wang32_hash(size_t key)
Thomas Wang's 32 bit hash function.
Definition hashfunc.hh:37
std::shared_ptr< twacube > twacube_ptr
Definition fwd.hh:28
Definition automata.hh:26
mc_rvalue
Return value of a parallel model-checking algorithm.
Definition mc.hh:50
@ NOT_EMPTY
The product is not empty.
@ EMPTY
The product is empty.
An acceptance mark.
Definition acc.hh:76
Hasher for union-find elements.
Definition bloemen_ec.hh:80
bool equal(const uf_element *lhs, const uf_element *rhs) const
Check equality of elements.
Definition bloemen_ec.hh:101
uf_element_hasher()=default
Default constructor.
uf_element_hasher(const uf_element *)
Constructor from element pointer.
Definition bloemen_ec.hh:82
brick::hash::hash128_t hash(const uf_element *lhs) const
Compute hash of element.
Definition bloemen_ec.hh:90
Represents a Union-Find element.
Definition bloemen_ec.hh:57
State st_kripke
the kripke state handled by the element
Definition bloemen_ec.hh:59
std::mutex acc_mutex_
mutex for acceptance condition
Definition bloemen_ec.hh:65
std::atomic< uf_element * > parent
reference to the pointer
Definition bloemen_ec.hh:67
std::atomic< unsigned > worker_
The set of worker for a given state.
Definition bloemen_ec.hh:69
std::atomic< list_status > list_status_
current status for the list
Definition bloemen_ec.hh:75
unsigned st_prop
the prop state handled by the element
Definition bloemen_ec.hh:61
acc_cond::mark_t acc
acceptance conditions of the union
Definition bloemen_ec.hh:63
std::atomic< uf_status > uf_status_
current status for the element
Definition bloemen_ec.hh:73
std::atomic< uf_element * > next_
next element for work stealing
Definition bloemen_ec.hh:71