25 #include <spot/bricks/brick-hashset>
26 #include <spot/kripke/kripke.hh>
27 #include <spot/misc/common.hh>
28 #include <spot/misc/fixpool.hh>
29 #include <spot/misc/timer.hh>
30 #include <spot/twacube/twacube.hh>
31 #include <spot/mc/mc.hh>
37 template<
typename State,
typename SuccIterator,
38 typename StateHash,
typename StateEqual>
50 std::atomic<bool> blue;
51 std::atomic<bool> red;
65 state_hasher(
const product_state&)
68 state_hasher() =
default;
70 brick::hash::hash128_t
71 hash(
const product_state& lhs)
const
75 unsigned u = hash(lhs.st_kripke) % (1<<30);
81 bool equal(
const product_state& lhs,
82 const product_state& rhs)
const
85 return (lhs.st_prop == rhs.st_prop)
86 && equal(lhs.st_kripke, rhs.st_kripke);
93 SuccIterator* it_kripke;
94 std::shared_ptr<trans_index> it_prop;
101 using shared_map = brick::hashset::FastConcurrent <product_state,
115 unsigned tid, std::atomic<bool>& stop):
116 sys_(sys), twa_(
twa), tid_(tid), map_(map),
117 nb_th_(std::thread::hardware_concurrency()),
118 p_colors_(sizeof(cndfs_colors) +
119 sizeof(local_colors)*(std::thread::hardware_concurrency() - 1)),
123 State, SuccIterator>::value,
124 "error: does not match the kripkecube requirements");
125 SPOT_ASSERT(nb_th_ > tid);
130 while (!todo_blue_.empty())
132 sys_.recycle(todo_blue_.back().it_kripke, tid_);
133 todo_blue_.pop_back();
135 while (!todo_red_.empty())
137 sys_.recycle(todo_red_.back().it_kripke, tid_);
138 todo_red_.pop_back();
153 tm_.start(
"DFS thread " + std::to_string(tid_));
157 std::pair<bool, product_state>
160 cndfs_colors* c = (cndfs_colors*) p_colors_.allocate();
163 for (
unsigned i = 0; i < nb_th_; ++i)
165 c->l[i].cyan =
false;
166 c->l[i].is_in_Rp =
false;
172 auto it = map_.insert(s);
179 p_colors_.deallocate(c);
180 bool blue = ((*it)).colors->blue.load();
181 bool cyan = ((*it)).colors->l[tid_].cyan;
187 ((*it)).colors->l[tid_].cyan =
true;
189 todo_blue_.push_back({*it,
190 sys_.succ(((*it)).st_kripke, tid_),
191 twa_->succ(((*it)).st_prop),
197 std::pair<bool, product_state>
201 auto it = map_.insert(s);
202 SPOT_ASSERT(!it.isnew());
203 bool red = ((*it)).colors->red.load();
204 bool cyan = ((*it)).colors->l[tid_].cyan;
205 bool in_Rp = ((*it)).colors->l[tid_].is_in_Rp;
206 if (red || (cyan && !ignore_cyan) || in_Rp)
210 ((*it)).colors->l[tid_].is_in_Rp =
true;
213 todo_red_.push_back({*it,
214 sys_.succ(((*it)).st_kripke, tid_),
215 twa_->succ(((*it)).st_prop),
224 dfs_ = todo_blue_.size() > dfs_ ? todo_blue_.size() : dfs_;
226 todo_blue_.back().st.colors->l[tid_].cyan =
false;
227 sys_.recycle(todo_blue_.back().it_kripke, tid_);
228 todo_blue_.pop_back();
236 dfs_ = todo_blue_.size() + todo_red_.size() > dfs_ ?
237 todo_blue_.size() + todo_red_.size() : dfs_;
240 sys_.recycle(todo_red_.back().it_kripke, tid_);
241 todo_red_.pop_back();
248 bool tst_val =
false;
250 bool exchanged = stop_.compare_exchange_strong(tst_val, new_val);
253 tm_.stop(
"DFS thread " + std::to_string(tid_));
277 return tm_.timer(
"DFS thread " + std::to_string(tid_)).walltime();
301 SPOT_ASSERT(!is_empty_);
303 auto state_equal = [equal](product_state a, product_state b)
305 return a.st_prop == b.st_prop
306 && equal(a.st_kripke, b.st_kripke);
309 std::string res =
"Prefix:\n";
311 auto it = todo_blue_.begin();
312 while (it != todo_blue_.end())
314 if (state_equal(((*it)).st, cycle_start_))
316 res +=
" " + std::to_string(((*it)).st.st_prop)
317 +
"*" + sys_.to_string(((*it)).st.st_kripke) +
"\n";
322 while (it != todo_blue_.end())
324 res +=
" " + std::to_string(((*it)).st.st_prop)
325 +
"*" + sys_.to_string(((*it)).st.st_kripke) +
"\n";
329 if (!todo_red_.empty())
331 it = todo_red_.begin() + 1;
332 while (it != todo_red_.end())
334 res +=
" " + std::to_string(((*it)).st.st_prop)
335 +
"*" + sys_.to_string(((*it)).st.st_kripke) +
"\n";
339 res +=
" " + std::to_string(cycle_start_.st_prop)
340 +
"*" + sys_.to_string(cycle_start_.st_kripke) +
"\n";
348 product_state initial = {sys_.initial(tid_),
351 if (!push_blue(initial,
false).first)
355 if (todo_blue_.back().it_prop->done())
358 forward_iterators(sys_, twa_, todo_blue_.back().it_kripke,
359 todo_blue_.back().it_prop,
true, tid_);
361 while (!todo_blue_.empty() && !stop_.load(std::memory_order_relaxed))
363 auto current = todo_blue_.back();
365 if (!current.it_kripke->done())
369 current.it_kripke->state(),
370 twa_->trans_storage(current.it_prop, tid_).dst,
374 bool acc = (bool) twa_->trans_storage(current.it_prop, tid_).acc_;
375 forward_iterators(sys_, twa_, todo_blue_.back().it_kripke,
376 todo_blue_.back().it_prop,
false, tid_);
378 auto tmp = push_blue(s, acc);
380 forward_iterators(sys_, twa_, todo_blue_.back().it_kripke,
381 todo_blue_.back().it_prop,
true, tid_);
387 if (tmp.second.colors->l[tid_].cyan)
395 SPOT_ASSERT(tmp.second.colors->blue);
405 current.st.colors->blue.store(
true);
408 if (current.from_accepting)
410 red_dfs(todo_blue_.back().st);
423 for (product_state& s: Rp_acc_)
425 while (s.colors->red.load() && !stop_.load())
430 for (product_state& s: Rp_)
432 s.colors->red.store(
true);
433 s.colors->l[tid_].is_in_Rp =
false;
440 void red_dfs(product_state initial)
442 auto init_push = push_red(initial,
true);
443 SPOT_ASSERT(init_push.second.colors->blue);
445 if (!init_push.first)
448 forward_iterators(sys_, twa_, todo_red_.back().it_kripke,
449 todo_red_.back().it_prop,
true, tid_);
451 while (!todo_red_.empty() && !stop_.load(std::memory_order_relaxed))
453 auto current = todo_red_.back();
455 if (!current.it_kripke->done())
459 current.it_kripke->state(),
460 twa_->trans_storage(current.it_prop, tid_).dst,
463 bool acc = (bool) twa_->trans_storage(current.it_prop, tid_).acc_;
464 forward_iterators(sys_, twa_, todo_red_.back().it_kripke,
465 todo_red_.back().it_prop,
false, tid_);
467 auto res = push_red(s,
false);
470 forward_iterators(sys_, twa_, todo_red_.back().it_kripke,
471 todo_red_.back().it_prop,
true, tid_);
473 SPOT_ASSERT(res.second.colors->blue);
481 for (
auto& st: Rp_acc_)
483 if (st.colors == res.second.colors)
490 Rp_acc_.push_back(Rp_.back());
495 if (res.second.colors->l[tid_].cyan)
500 if (init_push.second.colors == res.second.colors && !acc)
507 else if (acc && res.second.colors->l[tid_].is_in_Rp)
509 auto it = map_.insert(s);
510 Rp_acc_.push_back(*it);
521 kripkecube<State, SuccIterator>& sys_;
523 std::vector<todo_element> todo_blue_;
524 std::vector<todo_element> todo_red_;
525 unsigned transitions_ = 0;
529 unsigned states_ = 0;
532 fixed_size_pool<pool_type::Unsafe> p_colors_;
533 bool is_empty_ =
true;
534 std::atomic<bool>& stop_;
535 std::vector<product_state> Rp_;
536 std::vector<product_state> Rp_acc_;
537 product_state cycle_start_;
538 bool finisher_ =
false;
This class allows to ensure (at compile time) if a given parameter is of type kripkecube....
Definition: kripke.hh:71
This class is a template representation of a Kripke structure. It is composed of two template paramet...
Definition: kripke.hh:40
Swarmed variant of the CNDFS parallel emptiness-check algorithm.
Definition: cndfs.hh:40
unsigned walltime()
Return wall time in milliseconds.
Definition: cndfs.hh:275
shared_map shared_struct
Type alias for shared structure.
Definition: cndfs.hh:104
std::string name()
Return algorithm name.
Definition: cndfs.hh:281
void finalize()
Finalize thread resources.
Definition: cndfs.hh:246
int sccs()
Return number of SCCs found (returns -1)
Definition: cndfs.hh:287
swarmed_cndfs(kripkecube< State, SuccIterator > &sys, twacube_ptr twa, shared_map &map, shared_struct *, unsigned tid, std::atomic< bool > &stop)
Constructor for parallel CNDFS algorithm.
Definition: cndfs.hh:113
bool pop_blue()
Pop state from blue stack.
Definition: cndfs.hh:221
brick::hashset::FastConcurrent< product_state, state_hasher > shared_map
Concurrent hashset for shared state storage.
Definition: cndfs.hh:102
bool finisher()
Check if this thread finished the search.
Definition: cndfs.hh:257
mc_rvalue result()
Return emptiness check result.
Definition: cndfs.hh:293
bool pop_red()
Pop state from red stack.
Definition: cndfs.hh:233
std::pair< bool, product_state > push_blue(product_state s, bool from_accepting)
Push state to blue stack.
Definition: cndfs.hh:158
static shared_struct * make_shared_structure(shared_map m, unsigned i)
Create shared structure for thread tid.
Definition: cndfs.hh:107
void setup()
Setup thread resources.
Definition: cndfs.hh:151
unsigned states()
Return number of states visited.
Definition: cndfs.hh:263
std::string trace()
Return trace.
Definition: cndfs.hh:299
unsigned transitions()
Return number of transitions traversed.
Definition: cndfs.hh:269
std::pair< bool, product_state > push_red(product_state s, bool ignore_cyan)
Push state to red stack.
Definition: cndfs.hh:198
void run()
Run the algorithm.
Definition: cndfs.hh:143
A map of timer, where each timer has a name.
Definition: timer.hh:231
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:25
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.