27 #include <spot/bricks/brick-hashset>
28 #include <spot/kripke/kripke.hh>
29 #include <spot/misc/common.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/mc.hh>
40 template<
typename State,
82 brick::hash::hash128_t
87 unsigned u =
hash(lhs->
st_) % (1<<30);
106 map_(uf.map_), tid_(uf.tid_), size_(std::thread::hardware_concurrency()),
107 nb_th_(std::thread::hardware_concurrency()), inserted_(0),
114 map_(map), tid_(tid), size_(std::thread::hardware_concurrency()),
115 nb_th_(std::thread::hardware_concurrency()), inserted_(0),
124 std::pair<claim_status, uf_element*>
127 unsigned w_id = (1U << tid_);
138 auto it = map_.insert({v});
149 if (a_root->
uf_status_.load() == uf_status::DEAD)
150 return {claim_status::CLAIM_DEAD, *it};
152 if ((a_root->
worker_.load() & w_id) != 0)
153 return {claim_status::CLAIM_FOUND, *it};
155 atomic_fetch_or(&(a_root->
worker_), w_id);
156 while (a_root->
parent.load() != a_root)
158 a_root =
find(a_root);
159 atomic_fetch_or(&(a_root->
worker_), w_id);
162 return {claim_status::CLAIM_NEW, *it};
175 parent = y->
parent.load();
180 parent = x->
parent.load();
192 if (a_root == b_root)
195 if (a_root->
parent.load() == a_root)
206 if (std::atomic_compare_exchange_strong
207 (&(a->
uf_status_), &expected, uf_status::LOCK))
209 if (a->
parent.load() == a)
229 bool dontcare =
false;
231 if (a_list ==
nullptr)
236 auto expected = list_status::BUSY;
237 bool b = std::atomic_compare_exchange_strong
238 (&(a_list->
list_status_), &expected, list_status::LOCK);
243 a_list = a_list->
next_.load();
266 if (a_root == b_root)
269 r = std::max(a_root, b_root);
270 q = std::min(a_root, b_root);
279 if (a_list ==
nullptr)
286 if (b_list ==
nullptr)
293 SPOT_ASSERT(a_list->
list_status_.load() == list_status::LOCK);
294 SPOT_ASSERT(b_list->
list_status_.load() == list_status::LOCK);
299 SPOT_ASSERT(a_next !=
nullptr);
300 SPOT_ASSERT(b_next !=
nullptr);
302 a_list->
next_.store(b_next);
303 b_list->
next_.store(a_next);
307 unsigned q_worker = q->
worker_.load();
308 unsigned r_worker = r->
worker_.load();
309 if ((q_worker|r_worker) != r_worker)
311 atomic_fetch_or(&(r->
worker_), q_worker);
312 while (r->
parent.load() != r)
315 atomic_fetch_or(&(r->
worker_), q_worker);
335 if (a_status == list_status::BUSY)
340 if (a_status == list_status::DONE)
367 while (status != uf_status::DEAD)
369 if (status == uf_status::LIVE)
370 *sccfound = std::atomic_compare_exchange_strong
371 (&(a_root->
uf_status_), &status, uf_status::DEAD);
382 if (b_status == list_status::BUSY)
387 if (b_status == list_status::DONE)
391 SPOT_ASSERT(b_status == list_status::DONE);
392 SPOT_ASSERT(a_status == list_status::DONE);
407 if (a_status == list_status::DONE)
410 if (a_status == list_status::BUSY)
411 std::atomic_compare_exchange_strong
439 template<
typename State,
typename SuccIterator,
440 typename StateHash,
typename StateEqual>
470 std::atomic<bool>& stop):
471 sys_(sys), uf_(*
uf), tid_(tid),
472 nb_th_(std::thread::hardware_concurrency()),
476 State, SuccIterator>::value,
477 "error: does not match the kripkecube requirements");
484 State init = sys_.initial(tid_);
485 auto pair = uf_.make_claim(init);
486 todo_.push_back(pair.second);
487 Rp_.push_back(pair.second);
490 while (!todo_.empty())
492 bloemen_recursive_start:
493 while (!stop_.load(std::memory_order_relaxed))
495 bool sccfound =
false;
496 uf_element* v_prime = uf_.pick_from_list(todo_.back(), &sccfound);
497 if (v_prime ==
nullptr)
504 auto it = sys_.succ(v_prime->st_, tid_);
507 auto w = uf_.make_claim(it->state());
510 if (w.first == uf::claim_status::CLAIM_NEW)
512 todo_.push_back(w.second);
513 Rp_.push_back(w.second);
515 sys_.recycle(it, tid_);
516 goto bloemen_recursive_start;
518 else if (w.first == uf::claim_status::CLAIM_FOUND)
520 while (!uf_.sameset(todo_.back(), w.second))
524 uf_.unite(r, Rp_.back());
528 uf_.remove_from_list(v_prime);
529 sys_.recycle(it, tid_);
532 if (todo_.back() == Rp_.back())
542 tm_.
start(
"DFS thread " + std::to_string(tid_));
548 bool tst_val =
false;
550 bool exchanged = stop_.compare_exchange_strong(tst_val, new_val);
553 tm_.
stop(
"DFS thread " + std::to_string(tid_));
577 return tm_.
timer(
"DFS thread " + std::to_string(tid_)).
walltime();
583 return "bloemen_scc";
607 std::vector<uf_element*> todo_;
608 std::vector<uf_element*> Rp_;
612 unsigned inserted_ = 0;
613 unsigned states_ = 0;
614 unsigned transitions_ = 0;
617 std::atomic<bool>& stop_;
618 bool finisher_ =
false;
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 reachability algorithms.
Definition: bloemen.hh:44
uf_status
Status values for union-find elements.
Definition: bloemen.hh:48
bool sameset(uf_element *a, uf_element *b)
Check if elements are in same set.
Definition: bloemen.hh:186
std::pair< claim_status, uf_element * > make_claim(State a)
Try to claim a state; returns status and element pointer.
Definition: bloemen.hh:125
iterable_uf(const iterable_uf< State, StateHash, StateEqual > &uf)
Copy constructor.
Definition: bloemen.hh:105
void remove_from_list(uf_element *a)
Mark element as removed from list.
Definition: bloemen.hh:401
iterable_uf(shared_map &map, unsigned tid)
Constructor from shared map and thread ID.
Definition: bloemen.hh:113
claim_status
Status values for claim operations.
Definition: bloemen.hh:52
void unlock_root(uf_element *a)
Unlock root element.
Definition: bloemen.hh:218
brick::hashset::FastConcurrent< uf_element *, uf_element_hasher > shared_map
Concurrent hashset for shared state storage.
Definition: bloemen.hh:102
void unlock_list(uf_element *a)
Unlock list element.
Definition: bloemen.hh:248
uf_element * find(uf_element *a)
Find root of element using path compression.
Definition: bloemen.hh:166
uf_element * pick_from_list(uf_element *u, bool *sccfound)
Pick element from list; mark SCC as dead if complete.
Definition: bloemen.hh:325
unsigned inserted()
Return number of successfully inserted states.
Definition: bloemen.hh:417
bool lock_root(uf_element *a)
Lock root element if live; return true if successful.
Definition: bloemen.hh:201
list_status
Status values for list operations.
Definition: bloemen.hh:50
~iterable_uf()
Destructor.
Definition: bloemen.hh:121
void unite(uf_element *a, uf_element *b)
Unite two sets.
Definition: bloemen.hh:254
uf_element * lock_list(uf_element *a)
Lock next element in list.
Definition: bloemen.hh:224
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 reachability.
Definition: bloemen.hh:442
typename uf::shared_map shared_map
Type alias for shared map.
Definition: bloemen.hh:456
unsigned walltime()
Return wall time in milliseconds.
Definition: bloemen.hh:575
int sccs()
Return number of SCCs found.
Definition: bloemen.hh:587
mc_rvalue result()
Return emptiness check result.
Definition: bloemen.hh:593
unsigned transitions()
Return number of transitions traversed.
Definition: bloemen.hh:569
static shared_struct * make_shared_structure(shared_map m, unsigned i)
Create shared structure for thread tid.
Definition: bloemen.hh:459
std::string name()
Return algorithm name.
Definition: bloemen.hh:581
bool finisher()
Check if this thread finished the search.
Definition: bloemen.hh:557
unsigned states()
Return number of states visited.
Definition: bloemen.hh:563
void finalize()
Finalize thread resources.
Definition: bloemen.hh:546
void run()
Run the algorithm.
Definition: bloemen.hh:481
std::string trace()
Return trace (returns empty string)
Definition: bloemen.hh:599
typename uf::uf_element uf_element
Type alias for union-find element.
Definition: bloemen.hh:451
iterable_uf< State, StateHash, StateEqual > uf
Type alias for iterable union-find.
Definition: bloemen.hh:449
swarmed_bloemen(kripkecube< State, SuccIterator > &sys, twacube_ptr, shared_map &map, iterable_uf< State, StateHash, StateEqual > *uf, unsigned tid, std::atomic< bool > &stop)
Constructor for parallel Bloemen algorithm.
Definition: bloemen.hh:465
void setup()
Setup thread resources.
Definition: bloemen.hh:540
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
std::shared_ptr< twacube > twacube_ptr
Definition: fwd.hh:25
Definition: automata.hh:26
mc_rvalue
Return value of a parallel model-checking algorithm.
Definition: mc.hh:50
@ SUCCESS
The algorithm finished normally.
Hasher for union-find elements.
Definition: bloemen.hh:73
uf_element_hasher(const uf_element *)
Constructor from element pointer.
Definition: bloemen.hh:75
brick::hash::hash128_t hash(const uf_element *lhs) const
Compute hash of element.
Definition: bloemen.hh:83
uf_element_hasher()=default
Default constructor.
bool equal(const uf_element *lhs, const uf_element *rhs) const
Check equality of elements.
Definition: bloemen.hh:92
Represents a Union-Find element.
Definition: bloemen.hh:56
std::atomic< list_status > list_status_
current status for the list
Definition: bloemen.hh:68
std::atomic< unsigned > worker_
The set of worker for a given state.
Definition: bloemen.hh:62
State st_
the state handled by the element
Definition: bloemen.hh:58
std::atomic< uf_element * > parent
reference to the pointer
Definition: bloemen.hh:60
std::atomic< uf_element * > next_
next element for work stealing
Definition: bloemen.hh:64
std::atomic< uf_status > uf_status_
current status for the element
Definition: bloemen.hh:66