spot 2.16
Loading...
Searching...
No Matches
lpar13.hh
1// -*- coding: utf-8 -*-
2// Copyright (C) by the Spot authors, see the AUTHORS file for details.
3//
4// This file is part of Spot, a model checking library.
5//
6// Spot is free software; you can redistribute it and/or modify it
7// under the terms of the GNU General Public License as published by
8// the Free Software Foundation; either version 3 of the License, or
9// (at your option) any later version.
10//
11// Spot is distributed in the hope that it will be useful, but WITHOUT
12// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
14// License for more details.
15//
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <http://www.gnu.org/licenses/>.
18
19#pragma once
20
21#include <atomic>
22#include <spot/twa/acc.hh>
23#include <spot/mc/unionfind.hh>
24#include <spot/mc/intersect.hh>
25#include <spot/mc/mc.hh>
26#include <spot/misc/timer.hh>
27#include <spot/twacube/twacube.hh>
28#include <spot/twacube/fwd.hh>
29
30namespace spot
31{
38 template<typename State, typename SuccIterator,
39 typename StateHash, typename StateEqual>
40 class SPOT_API lpar13
41 {
42 struct product_state
43 {
44 State st_kripke;
45 unsigned st_prop;
46 };
47
48 struct product_state_equal
49 {
50 bool
51 operator()(const product_state lhs,
52 const product_state rhs) const
53 {
54 StateEqual equal;
55 return (lhs.st_prop == rhs.st_prop) &&
56 equal(lhs.st_kripke, rhs.st_kripke);
57 }
58 };
59
60 struct product_state_hash
61 {
62 size_t
63 operator()(const product_state that) const noexcept
64 {
65 // FIXME: wang32_hash(that.st_prop) could have been
66 // pre-calculated!
67 StateHash hasher;
68 return wang32_hash(that.st_prop) ^ hasher(that.st_kripke);
69 }
70 };
71
72 public:
73
75 using shared_map = int; // Useless here.
77 using shared_struct = int; // Useless here.
78
81 {
82 return nullptr; // Useless
83 }
84
88 shared_map& map, /* useless here */
89 shared_struct*, /* useless here */
90 unsigned tid,
91 std::atomic<bool>& stop)
92 : sys_(sys), twa_(twa), tid_(tid), stop_(stop),
93 acc_(twa->acc()), sccs_(0U)
94 {
95 static_assert(spot::is_a_kripkecube_ptr<decltype(&sys),
96 State, SuccIterator>::value,
97 "error: does not match the kripkecube requirements");
98 }
99
101 virtual ~lpar13()
102 {
103 map.clear();
104 while (!todo.empty())
105 {
106 sys_.recycle(todo.back().it_kripke, tid_);
107 todo.pop_back();
108 }
109 }
110
112 bool run()
113 {
114 setup();
115 product_state initial = {sys_.initial(tid_), twa_->get_initial()};
116 if (SPOT_LIKELY(push_state(initial, dfs_number+1, {})))
117 {
118 todo.push_back({initial, sys_.succ(initial.st_kripke, tid_),
119 twa_->succ(initial.st_prop)});
120
121 // Not going further! It's a product with a single state.
122 if (todo.back().it_prop->done())
123 return false;
124
125 forward_iterators(sys_, twa_, todo.back().it_kripke,
126 todo.back().it_prop, true, 0);
127 map[initial] = ++dfs_number;
128 }
129 while (!todo.empty() && !stop_.load(std::memory_order_relaxed))
130 {
131 // Check the kripke is enough since it's the outer loop. More
132 // details in forward_iterators.
133 if (todo.back().it_kripke->done())
134 {
135 bool is_init = todo.size() == 1;
136 auto newtop = is_init? todo.back().st: todo[todo.size() -2].st;
137 if (SPOT_LIKELY(pop_state(todo.back().st,
138 map[todo.back().st],
139 is_init,
140 newtop,
141 map[newtop])))
142 {
143 sys_.recycle(todo.back().it_kripke, tid_);
144 // FIXME: a local storage for twacube iterator?
145 todo.pop_back();
146 if (SPOT_UNLIKELY(found_))
147 {
148 finalize();
149 return true;
150 }
151 }
152 }
153 else
154 {
155 ++trans_;
156 product_state dst =
157 {
158 todo.back().it_kripke->state(),
159 twa_->trans_storage(todo.back().it_prop, tid_).dst
160 };
161 auto acc = twa_->trans_data(todo.back().it_prop, tid_).acc_;
162 forward_iterators(sys_, twa_, todo.back().it_kripke,
163 todo.back().it_prop, false, 0);
164 auto it = map.find(dst);
165 if (it == map.end())
166 {
167 if (SPOT_LIKELY(push_state(dst, dfs_number+1, acc)))
168 {
169 map[dst] = ++dfs_number;
170 todo.push_back({dst, sys_.succ(dst.st_kripke, tid_),
171 twa_->succ(dst.st_prop)});
172 forward_iterators(sys_, twa_, todo.back().it_kripke,
173 todo.back().it_prop, true, 0);
174 }
175 }
176 else if (SPOT_UNLIKELY(update(todo.back().st,
177 dfs_number,
178 dst, map[dst], acc)))
179 {
180 finalize();
181 return true;
182 }
183 }
184 }
185 finalize();
186 return false;
187 }
188
190 void setup()
191 {
192 tm_.start("DFS thread " + std::to_string(tid_));
193 }
194
196 bool push_state(product_state, unsigned dfsnum, acc_cond::mark_t cond)
197 {
198 uf_.makeset(dfsnum);
199 roots_.push_back({dfsnum, cond, {}});
200 return true;
201 }
202
210 bool pop_state(product_state, unsigned top_dfsnum, bool,
211 product_state, unsigned)
212 {
213 if (top_dfsnum == roots_.back().dfsnum)
214 {
215 roots_.pop_back();
216 ++sccs_;
217 uf_.markdead(top_dfsnum);
218 }
219 dfs_ = todo.size() > dfs_ ? todo.size() : dfs_;
220 return true;
221 }
222
227 bool update(product_state, unsigned,
228 product_state, unsigned dst_dfsnum,
229 acc_cond::mark_t cond)
230 {
231 if (uf_.isdead(dst_dfsnum))
232 return false;
233
234 while (!uf_.sameset(dst_dfsnum, roots_.back().dfsnum))
235 {
236 auto& el = roots_.back();
237 roots_.pop_back();
238 uf_.unite(dst_dfsnum, el.dfsnum);
239 cond |= el.acc | el.ingoing;
240 }
241 roots_.back().acc |= cond;
242 found_ = acc_.accepting(roots_.back().acc);
243 if (SPOT_UNLIKELY(found_))
244 stop_ = true;
245 return found_;
246 }
247
249 void finalize()
250 {
251 bool tst_val = false;
252 bool new_val = true;
253 bool exchanged = stop_.compare_exchange_strong(tst_val, new_val);
254 if (exchanged)
255 finisher_ = true;
256 tm_.stop("DFS thread " + std::to_string(tid_));
257 }
258
260 bool finisher()
261 {
262 return finisher_;
263 }
264
266 unsigned int states()
267 {
268 return dfs_number;
269 }
270
272 unsigned int transitions()
273 {
274 return trans_;
275 }
276
278 unsigned walltime()
279 {
280 return tm_.timer("DFS thread " + std::to_string(tid_)).walltime();
281 }
282
284 std::string name()
285 {
286 return "renault_lpar13";
287 }
288
290 int sccs()
291 {
292 return sccs_;
293 }
294
297 {
298 return !found_ ? mc_rvalue::EMPTY : mc_rvalue::NOT_EMPTY;
299 }
300
302 std::string trace()
303 {
304 SPOT_ASSERT(found_);
305 std::string res = "Prefix:\n";
306
307 // Compute the prefix of the accepting run
308 for (auto& s : todo)
309 res += " " + std::to_string(s.st.st_prop) +
310 + "*" + sys_.to_string(s.st.st_kripke) + "\n";
311
312 // Compute the accepting cycle
313 res += "Cycle:\n";
314
315 struct ctrx_element
316 {
317 const product_state* prod_st;
318 ctrx_element* parent_st;
319 SuccIterator* it_kripke;
320 std::shared_ptr<trans_index> it_prop;
321 };
322 std::queue<ctrx_element*> bfs;
323
324 acc_cond::mark_t acc = {};
325
326 bfs.push(new ctrx_element({&todo.back().st, nullptr,
327 sys_.succ(todo.back().st.st_kripke, tid_),
328 twa_->succ(todo.back().st.st_prop)}));
329 while (true)
330 {
331 here:
332 auto* front = bfs.front();
333 bfs.pop();
334 // PUSH all successors of the state.
335 while (!front->it_kripke->done())
336 {
337 while (!front->it_prop->done())
338 {
339 if (twa_->get_cubeset().intersect
340 (twa_->trans_data(front->it_prop, tid_).cube_,
341 front->it_kripke->condition()))
342 {
343 const product_state dst = {
344 front->it_kripke->state(),
345 twa_->trans_storage(front->it_prop).dst
346 };
347
348 // Skip Unknown states or not same SCC
349 auto it = map.find(dst);
350 if (it == map.end() ||
351 !uf_.sameset(it->second,
352 map[todo.back().st]))
353 {
354 front->it_prop->next();
355 continue;
356 }
357
358 // This is a valid transition. If this transition
359 // is the one we are looking for, update the counter-
360 // -example and flush the bfs queue.
361 auto mark = twa_->trans_data(front->it_prop,
362 tid_).acc_;
363 if (!(acc & mark))
364 {
365 ctrx_element* current = front;
366 while (current != nullptr)
367 {
368 // FIXME: also display acc?
369 res = res + " " +
370 std::to_string(current->prod_st->st_prop) +
371 + "*" +
372 sys_. to_string(current->prod_st->st_kripke) +
373 "\n";
374 current = current->parent_st;
375 }
376
377 // empty the queue
378 while (!bfs.empty())
379 {
380 auto* e = bfs.front();
381 sys_.recycle(e->it_kripke, tid_);
382 bfs.pop();
383 delete e;
384 }
385 sys_.recycle(front->it_kripke, tid_);
386 delete front;
387
388 // update acceptance
389 acc |= mark;
390 if (twa_->acc().accepting(acc))
391 {
392 return res;
393 }
394
395 const product_state* q = &(it->first);
396 ctrx_element* root = new ctrx_element({
397 q , nullptr,
398 sys_.succ(q->st_kripke, tid_),
399 twa_->succ(q->st_prop)
400 });
401 bfs.push(root);
402 goto here;
403 }
404
405 // Otherwise increment iterator and push successor.
406 const product_state* q = &(it->first);
407 ctrx_element* root = new ctrx_element({
408 q , nullptr,
409 sys_.succ(q->st_kripke, tid_),
410 twa_->succ(q->st_prop)
411 });
412 bfs.push(root);
413 }
414 front->it_prop->next();
415 }
416 front->it_prop->reset();
417 front->it_kripke->next();
418 }
419 sys_.recycle(front->it_kripke, tid_);
420 delete front;
421 }
422
423 // never reach here;
424 return res;
425 }
426
427 private:
428
429 struct todo_element
430 {
431 product_state st;
432 SuccIterator* it_kripke;
433 std::shared_ptr<trans_index> it_prop;
434 };
435
436 struct root_element {
437 unsigned dfsnum;
438 acc_cond::mark_t ingoing;
439 acc_cond::mark_t acc;
440 };
441
442 typedef std::unordered_map<const product_state, int,
443 product_state_hash,
444 product_state_equal> visited_map;
445
446 kripkecube<State, SuccIterator>& sys_;
447 twacube_ptr twa_;
448 std::vector<todo_element> todo;
449 visited_map map;
450 unsigned int dfs_number = 0;
451 unsigned int trans_ = 0;
452 unsigned tid_;
453 std::atomic<bool>& stop_;
454 bool found_ = false;
455 std::vector<root_element> roots_;
456 int_unionfind uf_;
457 acc_cond acc_;
458 unsigned sccs_;
459 unsigned dfs_;
460 spot::timer_map tm_;
461 bool finisher_ = false;
462 };
463}
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
This class implements the sequential emptiness check as presented in "Three SCC-based Emptiness Check...
Definition lpar13.hh:41
bool run()
Run the algorithm.
Definition lpar13.hh:112
static shared_struct * make_shared_structure(shared_map m, unsigned i)
Create shared structure for thread tid.
Definition lpar13.hh:80
bool update(product_state, unsigned, product_state, unsigned dst_dfsnum, acc_cond::mark_t cond)
This method is called for every closing, back, or forward edge.
Definition lpar13.hh:227
unsigned int transitions()
Return number of transitions traversed.
Definition lpar13.hh:272
mc_rvalue result()
Return emptiness check result.
Definition lpar13.hh:296
bool push_state(product_state, unsigned dfsnum, acc_cond::mark_t cond)
Push product state to stack.
Definition lpar13.hh:196
unsigned int states()
Return number of states visited.
Definition lpar13.hh:266
int shared_map
Type alias for shared map (useless for sequential algorithm)
Definition lpar13.hh:75
int sccs()
Return number of SCCs found.
Definition lpar13.hh:290
bool finisher()
Check if this thread finished the search.
Definition lpar13.hh:260
void setup()
Setup thread resources.
Definition lpar13.hh:190
bool pop_state(product_state, unsigned top_dfsnum, bool, product_state, unsigned)
This method is called to notify the emptiness checks that a state will be popped. If the method retur...
Definition lpar13.hh:210
void finalize()
Finalize thread resources.
Definition lpar13.hh:249
unsigned walltime()
Return wall time in milliseconds.
Definition lpar13.hh:278
int shared_struct
Type alias for shared structure (useless here)
Definition lpar13.hh:77
std::string name()
Return algorithm name.
Definition lpar13.hh:284
std::string trace()
Return trace.
Definition lpar13.hh:302
virtual ~lpar13()
Destructor.
Definition lpar13.hh:101
lpar13(kripkecube< State, SuccIterator > &sys, twacube_ptr twa, shared_map &map, shared_struct *, unsigned tid, std::atomic< bool > &stop)
Constructor for LPAR13 emptiness check.
Definition lpar13.hh:86
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
@ U
until
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
An acceptance mark.
Definition acc.hh:76

Please direct any question, comment, or bug report to the Spot mailing list at spot@lrde.epita.fr.
Generated on Fri Feb 27 2015 10:00:07 for spot by doxygen 1.9.8