mCRL2
Loading...
Searching...
No Matches
state_space_generator.h
Go to the documentation of this file.
1// Author(s): Wieger Wesselink
2// Copyright: see the accompanying file COPYING or copy at
3// https://github.com/mCRL2org/mCRL2/blob/master/COPYING
4//
5// Distributed under the Boost Software License, Version 1.0.
6// (See accompanying file LICENSE_1_0.txt or copy at
7// http://www.boost.org/LICENSE_1_0.txt)
8//
9/// \file mcrl2/lts/state_space_generator.h
10/// \brief add your file description here.
11
12#ifndef MCRL2_LTS_STATE_SPACE_GENERATOR_H
13#define MCRL2_LTS_STATE_SPACE_GENERATOR_H
14
15#include "mcrl2/lps/explorer.h"
16#include "mcrl2/lts/trace.h"
17
18#include <forward_list>
19
20namespace mcrl2::lts
21{
22
23inline
25{
26 return out << atermpp::pp(s);
27}
28
29inline
30const lps::state& first_state(const lps::state& s)
31{
32 return s;
33}
34
35inline
36const lps::state& first_state(const lps::stochastic_state& s)
37{
38 return s.states.front();
39}
40
41namespace detail
42{
43
44inline
46 class trace& tr,
47 const std::string& filename
48)
49{
50 try
51 {
52 tr.save(filename);
53 mCRL2log(log::info) << " and saved trace to '" << filename << "'";
54 return true;
55 }
56 catch(...)
57 {
58 mCRL2log(log::info) << ", but its trace could not be saved to '" << filename << "'";
59 }
60 return false;
61}
62
63inline
65 class trace& tr,
66 const std::string& filename1,
67 class trace& tr2,
68 const std::string& filename2
69)
70{
71 try
72 {
73 tr.save(filename1);
74 tr2.save(filename2);
75 mCRL2log(log::info) << " and saved traces to '" << filename1 << "' and '" << filename2 << "'";
76 }
77 catch(...)
78 {
79 mCRL2log(log::info) << ", but its traces could not be saved to '" << filename1 << "' and '" << filename2 << "'";
80 }
81}
82
83// Facility for constructing a trace to a given state.
84template <typename Explorer>
86{
87 protected:
88 Explorer& m_explorer;
90
91 // Finds a transition s0 --a--> s1, and returns a.
92 lps::multi_action find_action(const lps::state& s0,
93 const lps::state& s1)
94 {
95 if constexpr (Explorer::is_stochastic)
96 {
97 for (const std::pair<lps::multi_action, lps::stochastic_state>& t: m_explorer.generate_transitions(s0))
98 {
99 for (const lps::state& s: t.second.states)
100 {
101 if (s == s1)
102 {
103 return t.first;
104 }
105 }
106 }
107 }
108 else
109 {
110 for (const std::pair<lps::multi_action, lps::state>& t: m_explorer.generate_transitions(s0))
111 {
112 if (t.second == s1)
113 {
114 return t.first;
115 }
116 }
117 }
118 throw mcrl2::runtime_error("no transition found in find_action");
119 }
120
121 public:
122 explicit trace_constructor(Explorer& explorer_)
123 : m_explorer(explorer_)
124 {}
125
126 // Constructs a trace ending in s, using the backpointers map.
127 class trace construct_trace(const lps::state& s)
128 {
129 std::deque<lps::state> states{ s };
130 std::deque<lps::multi_action> actions;
131 while (true)
132 {
133 const lps::state& s1 = states.front();
134 auto i = m_backpointers.find(s1);
135 if (i == m_backpointers.end())
136 {
137 break;
138 }
139 const lps::state& s0 = i->second;
140 states.push_front(s0);
141 actions.push_front(find_action(s0, s1));
142 }
143
144 class trace tr;
145 for (std::size_t i = 0; i < actions.size(); i++)
146 {
147 tr.set_state(states[i]);
148 tr.add_action(actions[i]);
149 }
150 tr.set_state(states.back());
151 return tr;
152 }
153
154 // Adds a back pointer for the given edge
155 void add_edge(const lps::state& s0, const lps::state& s1)
156 {
157 m_backpointers[s1] = s0;
158 }
159
160 void clear()
161 {
162 m_backpointers.clear();
163 }
164
165 // Providing access to the explorer should perhaps be avoided.
166 Explorer& explorer()
167 {
168 return m_explorer;
169 }
170};
171
172template <typename Explorer>
174{
175 protected:
183
184 bool match_action(const lps::action_summand& summand) const
185 {
186 using utilities::detail::contains;
187 for (const process::action& a: summand.multi_action().actions())
188 {
189 if (contains(trace_actions, a.label().name()))
190 {
191 return true;
192 }
193 }
194 return false;
195 }
196
197 bool match_summand(std::size_t i) const
198 {
199 return summand_matches[i];
200 }
201
203 {
204 using utilities::detail::contains;
205 std::string filename = filename_prefix + "_act_" + std::to_string(m_trace_count++);
206 if (utilities::detail::contains(trace_multiactions, a))
207 {
208 filename += "_" + lps::pp(a);
209 }
210 for (const process::action& a_i: a.actions())
211 {
212 if (utilities::detail::contains(trace_actions, a_i.label().name()))
213 {
214 filename += "_" + core::pp(a_i.label().name());
215 }
216 }
217 filename = filename + ".trc";
218 return filename;
219 }
220
221 public:
222 template <typename Specification>
224 const Specification& lpsspec,
225 trace_constructor<Explorer>& trace_constructor_,
226 const std::set<core::identifier_string>& trace_actions_,
227 const std::set<lps::multi_action>& trace_multiactions_,
228 const std::string& filename_prefix_,
229 std::size_t max_trace_count
230 )
233 m_trace_constructor(trace_constructor_),
236 {
237 using utilities::detail::contains;
238 const auto& summands = lpsspec.process().action_summands();
239 summand_matches.reserve(summands.size());
240 for (const auto& summand: summands)
241 {
242 summand_matches.push_back(match_action(summand));
243 }
244 }
245
246 bool detect_action(const lps::state& s0, std::size_t s0_index, const lps::multi_action& a, const lps::state& s1, std::size_t summand_index)
247 {
248 using utilities::detail::contains;
249 if (!match_summand(summand_index))
250 {
251 return false;
252 }
253 bool result = false;
254
255 mCRL2log(log::info) << "Action '" + lps::pp(a) + "' found (state index: " + std::to_string(s0_index) + ")";
256 if (m_trace_count < m_max_trace_count)
257 {
258 class trace tr = m_trace_constructor.construct_trace(s0);
259 tr.add_action(a);
260 tr.set_state(s1);
261 std::string filename = create_filename(a);
262 save_trace(tr, filename);
263 result = true;
264 }
265 mCRL2log(log::info) << ".\n";
266 if (m_max_trace_count > 0 && m_trace_count >= m_max_trace_count)
267 {
268 m_trace_constructor.explorer().abort();
269 }
270 return result;
271 }
272};
273
274template <typename Explorer>
276{
277 protected:
282
283 public:
285 trace_constructor<Explorer>& trace_constructor_,
286 const std::string& filename_prefix_,
287 std::size_t max_trace_count
288 )
289 : m_trace_constructor(trace_constructor_),
292 {}
293
294 void detect_deadlock(const lps::state& s, std::size_t s_index)
295 {
296 mCRL2log(log::info) << "Deadlock found (state index: " + std::to_string(s_index) + ")";
297 if (m_trace_count < m_max_trace_count)
298 {
299 class trace tr = m_trace_constructor.construct_trace(s);
300 std::string filename = filename_prefix + "_dlk_" + std::to_string(m_trace_count++) + ".trc";
301 save_trace(tr, filename);
302 }
303 if (m_max_trace_count > 0 && m_trace_count >= m_max_trace_count)
304 {
305 m_trace_constructor.explorer().abort();
306 }
307 mCRL2log(log::info) << ".\n";
308 }
309};
310
311template <typename Explorer>
313{
314 protected:
320
321 public:
323 trace_constructor<Explorer>& trace_constructor_,
324 const std::string& filename_prefix_,
325 const std::size_t number_of_threads,
326 std::size_t max_trace_count = 0
327 )
328 : m_trace_constructor(trace_constructor_),
330 m_transitions_vec(number_of_threads+1), //Threads are number from 1 to n.
332 {
333 assert(number_of_threads>0);
334 }
335
336 void start_state(std::size_t thread_index)
337 {
338 assert(thread_index<m_transitions_vec.size());
339 m_transitions_vec[thread_index].clear();
340 }
341
342 bool detect_nondeterminism(const lps::state& s0, std::size_t s0_index, const lps::multi_action& a, const lps::state& s1, std::size_t thread_index)
343 {
344 bool result = false;
345 assert(thread_index<m_transitions_vec.size());
346 auto i = m_transitions_vec[thread_index].find(a);
347 if (i == m_transitions_vec[thread_index].end())
348 {
349 m_transitions_vec[thread_index].insert(std::make_pair(a, s1));
350 }
351 else if (i->second != s1) // nondeterminism detected
352 {
353 mCRL2log(log::info) << "Nondeterministic state found (state index: " + std::to_string(s0_index) + ")";
354 if (m_trace_count < m_max_trace_count)
355 {
356 class trace tr = m_trace_constructor.construct_trace(s0);
357 tr.add_action(a);
358 tr.set_state(s1);
359 std::string filename = filename_prefix + "_nondeterministic_" + std::to_string(m_trace_count++) + ".trc";
360 save_trace(tr, filename);
361 result = true;
362 }
363 mCRL2log(log::info) << ".\n";
364 if (m_max_trace_count > 0 && m_trace_count >= m_max_trace_count)
365 {
366 m_trace_constructor.explorer().abort();
367 }
368 }
369 return result;
370 }
371};
372
373template <typename Explorer>
375{
376 public:
377 using state_type = typename Explorer::state_type;
378 using state_index_type = typename Explorer::state_index_type;
379
380 // data type for storing the last discovered states
382
383 protected:
384 Explorer& explorer;
392 std::mutex divergence_detector_mutex; // As it stands the divergence detector is sequential.
393
394 public:
396 Explorer& explorer_,
397 const std::set<core::identifier_string>& actions,
398 const std::string& filename_prefix_,
399 std::size_t max_trace_count
400 )
401 : explorer(explorer_),
405 {
406 using utilities::detail::contains;
407
408 auto is_hidden = [&](const lps::explorer_summand& summand)
409 {
410 for (const process::action& a: summand.multi_action.actions())
411 {
412 if (!contains(actions, a.label().name()))
413 {
414 return false;
415 }
416 }
417 return true;
418 };
419
420 for (const lps::explorer_summand& summand: explorer.regular_summands())
421 {
422 if (is_hidden(summand))
423 {
424 m_regular_summands.push_back(summand);
425 }
426 }
427
428 for (const lps::explorer_summand& summand: explorer.confluent_summands())
429 {
430 if (is_hidden(summand))
431 {
432 m_confluent_summands.push_back(summand);
433 }
434 }
435 }
436
437 // Returns true if a trace was saved.
438 bool detect_divergence(const lps::state& s, std::size_t s_index, trace_constructor<Explorer>& global_trace_constructor, bool dfs_recursive = false)
439 {
440 using utilities::detail::contains;
441
442 bool result = false;
443 std::lock_guard guard(divergence_detector_mutex);
445
446 auto q = m_divergent_states.find(s);
447 if (q != m_divergent_states.end())
448 {
449 std::string message = "Divergent state found (state index: " + std::to_string(s_index) +
450 "), reachable from divergent state with index " + std::to_string(q->second);
451 mCRL2log(log::info) << message << ".\n";
452 m_divergent_states.erase(q);
453 return false;
454 }
455
456 std::unordered_set<lps::state> discovered;
457 data::data_expression_list process_parameter_undo = explorer.process_parameter_values();
458
459 if (dfs_recursive)
460 {
461 std::unordered_set<lps::state> gray;
462 explorer.generate_state_space_dfs_recursive(
463 s,
464 gray,
465 discovered,
466 m_regular_summands,
467 m_confluent_summands,
468 utilities::skip(), // discover_state
469 utilities::skip(), // examine_transition
470 utilities::skip(), // tree_edge
471
472 // back_edge
473 [&](const lps::state& s0, const lps::multi_action& a, const state_type& s1) {
474 mCRL2log(log::info) << "Divergent state found (state index: " + std::to_string(s_index) + ")";
475 if (m_trace_count < m_max_trace_count)
476 {
477 class trace tr = global_trace_constructor.construct_trace(s);
478 class trace tr_loop = m_local_trace_constructor.construct_trace(s0);
479 for (const lps::state& u: tr_loop.states())
480 {
481 m_divergent_states[u] = s_index;
482 }
483 tr_loop.add_action(a);
484 tr_loop.set_state(first_state(s1));
485 std::string filename = filename_prefix + "_divergence_" + std::to_string(m_trace_count) + ".trc";
486 std::string loop_filename = filename_prefix + "_divergence_loop" + std::to_string(m_trace_count++) + ".trc";
487 save_traces(tr, filename, tr_loop, loop_filename);
488 result = true;
489 }
490 mCRL2log(log::info) << ".\n";
491 //--- Workaround for Visual Studio 2019 ---//
492 // explorer.abort();
493 static_cast<lps::abortable&>(explorer).abort();
494 }
495 );
496 }
497 else
498 {
499 explorer.generate_state_space_dfs_iterative(
500 s,
501 discovered,
502 m_regular_summands,
503 m_confluent_summands,
504 utilities::skip(), // discover_state
505 utilities::skip(), // examine_transition
506 utilities::skip(), // tree_edge
507
508 // back_edge
509 [&](const lps::state& s0, const lps::multi_action& a, const state_type& s1) {
510 mCRL2log(log::info) << "Divergent state found (state index: " + std::to_string(s_index) + ")";
511 if (m_trace_count < m_max_trace_count)
512 {
513 class trace tr = global_trace_constructor.construct_trace(s);
514 class trace tr_loop = m_local_trace_constructor.construct_trace(s0);
515 for (const lps::state& u: tr_loop.states())
516 {
517 m_divergent_states[u] = s_index;
518 }
519 tr_loop.add_action(a);
520 tr_loop.set_state(first_state(s1));
521 std::string filename = filename_prefix + "_divergence_" + std::to_string(m_trace_count) + ".trc";
522 std::string loop_filename = filename_prefix + "_divergence_loop" + std::to_string(m_trace_count++) + ".trc";
523 save_traces(tr, filename, tr_loop, loop_filename);
524 result = true;
525 }
526 mCRL2log(log::info) << ".\n";
527 //--- Workaround for Visual Studio 2019 ---//
528 // explorer.abort();
529 static_cast<lps::abortable&>(explorer).abort();
530 }
531 );
532 }
533 explorer.set_process_parameter_values(process_parameter_undo);
534 if (m_max_trace_count > 0 && m_trace_count >= m_max_trace_count)
535 {
536 explorer.abort();
537 }
538 return result;
539 }
540};
541
543{
544 protected:
545 std::size_t level = 1; // the current exploration level
546 std::size_t level_up = 1; // when count reaches level_up, the level is increased
549
552 std::atomic<time_t> last_log_time = time(nullptr) - 1;
553
554 lps::exploration_strategy search_strategy;
555
556 public:
557 explicit progress_monitor(lps::exploration_strategy search_strategy_)
558 : search_strategy(search_strategy_)
559 {}
560
562 {
563 transition_count++;
564 }
565
566 void finish_state(std::size_t state_count, std::size_t todo_list_size, std::size_t number_of_threads)
567 {
568 time_t new_log_time = 0;
569
570 static std::mutex exclusive_print_mutex;
571 if (search_strategy == lps::es_breadth)
572 {
573 ++count;
574 if (number_of_threads == 1 && count == level_up)
575 {
576 std::lock_guard guard(exclusive_print_mutex);
577 mCRL2log(log::debug) << "Number of states at level " << level << " is " << state_count - last_state_count << "\n";
578 level++;
579 level_up = count + todo_list_size;
580 last_state_count = state_count;
581 last_transition_count = transition_count;
582 }
583
584 if (time(&new_log_time) > last_log_time.load(std::memory_order_relaxed))
585 {
586 std::lock_guard guard(exclusive_print_mutex);
587
588 last_log_time = new_log_time;
589 std::size_t lvl_states = state_count - last_state_count;
590 std::size_t lvl_transitions = transition_count - last_transition_count;
591 if (number_of_threads>1) // Levels have no meaning with multiple threads.
592 {
593 mCRL2log(log::status) << std::fixed << std::setprecision(2)
594 << state_count << "st, " << transition_count << "tr"
595 << ", explored " << 100.0 * (static_cast<float>(count) / static_cast<float>(state_count))
596 << "%.\n";
597 }
598 else
599 {
600 mCRL2log(log::status) << std::fixed << std::setprecision(2)
601 << state_count << "st, " << transition_count << "tr"
602 << ", explored " << 100.0 * (static_cast<float>(count) / static_cast<float>(state_count))
603 << "%. Last level: " << level << ", " << lvl_states << "st, "
604 << lvl_transitions << "tr.\n";
605 }
606 }
607 }
608 else
609 {
610 count++;
611 if (time(&new_log_time) > last_log_time.load(std::memory_order_relaxed))
612 {
613 std::lock_guard guard(exclusive_print_mutex);
614 last_log_time = new_log_time;
615 mCRL2log(log::status) << "monitor: currently explored "
616 << count << " state" << ((count==1)?"":"s")
617 << " and " << transition_count << " transition" << ((transition_count==1)?".":"s.")
618 << std::endl;
619 }
620 }
621 }
622
623 void finish_exploration(std::size_t state_count, std::size_t number_of_threads)
624 {
625 if (search_strategy == lps::es_breadth)
626 {
627 mCRL2log(log::verbose) << "Done with state space generation (";
628 if (number_of_threads==1)
629 {
630 mCRL2log(log::verbose) << level-1 << " level" << ((level==2)?"":"s") << ", ";
631 }
632 mCRL2log(log::verbose) << state_count << " state" << ((state_count == 1)?"":"s")
633 << " and " << transition_count << " transition" << ((transition_count==1)?"":"s") << ")" << std::endl;
634 }
635 else
636 {
637 mCRL2log(log::verbose) << "Done with state space generation ("
638 << state_count << " state" << ((state_count == 1)?"":"s")
639 << " and " << transition_count << " transition" << ((transition_count==1)?"":"s") << ")" << std::endl;
640 }
641 }
642};
643
644} // namespace detail
645
646template <bool Stochastic, bool Timed, typename Specification>
648{
649 using explorer_type = lps::explorer<Stochastic, Timed, Specification>;
650 using state_type = typename explorer_type::state_type;
651
653 explorer_type& explorer;
655
661
662 state_space_generator(const Specification& lpsspec, const lps::explorer_options& options_, explorer_type& explorer_)
663 : options(options_),
664 explorer(explorer_),
666 m_action_detector(lpsspec, m_trace_constructor, options.trace_actions, options.trace_multiactions, options.trace_prefix, options.max_traces),
667 m_deadlock_detector(m_trace_constructor, options.trace_prefix, options.max_traces),
668 m_nondeterminism_detector(m_trace_constructor, options.trace_prefix, options.number_of_threads, options.max_traces),
670 {
672 {
673 m_divergence_detector =
674 std::unique_ptr<detail::divergence_detector<explorer_type>>(
675 new detail::divergence_detector<explorer_type>(explorer,
676 options.actions_internal_for_divergencies,
677 options.trace_prefix,
678 options.max_traces));
679 }
680 }
681
682 bool max_states_exceeded(const std::size_t thread_index)
683 {
684 return explorer.state_map().size(thread_index) >= options.max_states;
685 }
686
688 {
689 alignas(64) size_t m_bool;
690 };
691
692 // Explore the specification passed via the constructor, and put the results in builder.
693 template <typename LTSBuilder>
694 bool explore(LTSBuilder& builder)
695 {
696 std::vector<aligned_bool> has_outgoing_transitions(options.number_of_threads+1); // thread indices start at 1.
697 const lps::state* source = nullptr;
698
699 try
700 {
701 explorer.generate_state_space(
702 false,
703
704 // discover_state
705 [&](const std::size_t thread_index, const lps::state& s, std::size_t s_index)
706 {
707 if (options.generate_traces && source)
708 {
709 m_trace_constructor.add_edge(*source, s);
710 }
712 {
713 // TODO: support divergence checks for stochastic specifications
714 if constexpr (!Stochastic)
715 {
716 m_divergence_detector->detect_divergence(s, s_index, m_trace_constructor, options.dfs_recursive);
717 }
718 }
719 // if (explorer.state_map().size() >= options.max_states)
720 //--- Workaround for Visual Studio 2019 ---//
721 if (max_states_exceeded(thread_index))
722 {
723 static bool not_reported_yet=true;
724 if (not_reported_yet)
725 {
726 not_reported_yet=false;
727 mCRL2log(log::verbose) << "Explored the maximum number (" << options.max_states << ") of states, terminating." << std::endl;
728 }
729 //--- Workaround for Visual Studio 2019 ---//
730 // explorer.abort();
731 static_cast<lps::abortable&>(explorer).abort();
732 }
733 },
734
735 // examine_transition
736 [&](const std::size_t thread_index, const std::size_t number_of_threads,
737 const lps::state& s0, std::size_t s0_index, const lps::multi_action& a,
738 const auto& s1, const auto& s1_index, std::size_t summand_index)
739 {
740 if constexpr (Stochastic)
741 {
742 builder.add_transition(s0_index, a, s1_index, s1.probabilities, number_of_threads);
743 }
744 else
745 {
746 builder.add_transition(s0_index, a, s1_index, number_of_threads);
747 }
748 assert(thread_index<has_outgoing_transitions.size());
749 has_outgoing_transitions[thread_index].m_bool = true;
751 {
752 m_action_detector.detect_action(s0, s0_index, a, first_state(s1), summand_index);
753 }
755 {
756 m_nondeterminism_detector.detect_nondeterminism(s0, s0_index, a, first_state(s1), thread_index);
757 }
759 {
760 m_progress_monitor.examine_transition();
761 }
762 },
763
764 // start_state
765 [&](const std::size_t thread_index, const lps::state& s, std::size_t /* s_index */)
766 {
767 if (options.number_of_threads == 1) {
768 source = &s;
769 }
770
771 assert(thread_index<has_outgoing_transitions.size());
772 has_outgoing_transitions[thread_index].m_bool = false;
774 {
775 m_nondeterminism_detector.start_state(thread_index);
776 }
777 },
778
779 // finish_state
780 [&](const std::size_t thread_index, const std::size_t number_of_threads,
781 const lps::state& s, std::size_t s_index, std::size_t todo_list_size)
782 {
783 assert(thread_index<has_outgoing_transitions.size());
784 if (options.detect_deadlock && !has_outgoing_transitions[thread_index].m_bool)
785 {
786 m_deadlock_detector.detect_deadlock(s, s_index);
787 }
789 {
790 m_progress_monitor.finish_state(explorer.state_map().size(thread_index), todo_list_size, number_of_threads);
791 }
792 },
793
794 // discover_initial_state
795 [&](const lps::stochastic_state& s, const std::list<std::size_t>& s_index)
796 {
797 if constexpr (Stochastic)
798 {
799 builder.set_initial_state(s_index, s.probabilities);
800 }
801 }
802 );
803 m_progress_monitor.finish_exploration(explorer.state_map().size(), options.number_of_threads);
804 builder.finalize(explorer.state_map(), Timed);
805 }
806 catch (const data::enumerator_error& e)
807 {
808 mCRL2log(log::error) << "Error while exploring state space: " << e.what() << ".\n";
810 {
811 const lps::state& s = *source;
812 class trace tr = m_trace_constructor.construct_trace(s);
813 std::string filename = options.trace_prefix + "_error.trc";
814 detail::save_trace(tr, filename);
815 }
816 return false;
817 }
818
819 return true;
820 }
821};
822
823} // namespace mcrl2::lts
824
825#endif // MCRL2_LTS_STATE_SPACE_GENERATOR_H
LPS summand containing a multi-action.
\brief A timed multi-action
action_detector(const Specification &lpsspec, trace_constructor< Explorer > &trace_constructor_, const std::set< core::identifier_string > &trace_actions_, const std::set< lps::multi_action > &trace_multiactions_, const std::string &filename_prefix_, std::size_t max_trace_count)
trace_constructor< Explorer > & m_trace_constructor
bool detect_action(const lps::state &s0, std::size_t s0_index, const lps::multi_action &a, const lps::state &s1, std::size_t summand_index)
bool match_action(const lps::action_summand &summand) const
const std::set< core::identifier_string > & trace_actions
std::string create_filename(const lps::multi_action &a)
const std::set< lps::multi_action > & trace_multiactions
function object to compare two constln_t pointers based on their contents
deadlock_detector(trace_constructor< Explorer > &trace_constructor_, const std::string &filename_prefix_, std::size_t max_trace_count)
void detect_deadlock(const lps::state &s, std::size_t s_index)
trace_constructor< Explorer > & m_trace_constructor
std::vector< lps::explorer_summand > m_confluent_summands
utilities::unordered_map< lps::state, std::size_t > m_divergent_states
bool detect_divergence(const lps::state &s, std::size_t s_index, trace_constructor< Explorer > &global_trace_constructor, bool dfs_recursive=false)
std::vector< lps::explorer_summand > m_regular_summands
trace_constructor< Explorer > m_local_trace_constructor
divergence_detector(Explorer &explorer_, const std::set< core::identifier_string > &actions, const std::string &filename_prefix_, std::size_t max_trace_count)
trace_constructor< Explorer > & m_trace_constructor
std::vector< std::map< lps::multi_action, lps::state > > m_transitions_vec
nondeterminism_detector(trace_constructor< Explorer > &trace_constructor_, const std::string &filename_prefix_, const std::size_t number_of_threads, std::size_t max_trace_count=0)
bool detect_nondeterminism(const lps::state &s0, std::size_t s0_index, const lps::multi_action &a, const lps::state &s1, std::size_t thread_index)
progress_monitor(lps::exploration_strategy search_strategy_)
std::atomic< std::size_t > transition_count
void finish_exploration(std::size_t state_count, std::size_t number_of_threads)
void finish_state(std::size_t state_count, std::size_t todo_list_size, std::size_t number_of_threads)
lps::multi_action find_action(const lps::state &s0, const lps::state &s1)
void add_edge(const lps::state &s0, const lps::state &s1)
This class contains a trace consisting of a sequence of (timed) actions possibly with intermediate st...
Definition trace.h:51
void set_state(const lps::state &s)
Set the state at the current position.
Definition trace.h:329
void add_action(const mcrl2::lps::multi_action &action)
Add an action to the current trace.
Definition trace.h:316
#define mCRL2log(LEVEL)
mCRL2log(LEVEL) provides the stream used to log.
Definition logger.h:393
The main namespace for the LPS library.
Definition constelm.h:18
void save_traces(class trace &tr, const std::string &filename1, class trace &tr2, const std::string &filename2)
bool save_trace(class trace &tr, const std::string &filename)
std::ostream & operator<<(std::ostream &out, const lps::state &s)
const lps::state & first_state(const lps::state &s)
const lps::state & first_state(const lps::stochastic_state &s)
Enumerator exception.
Definition enumerator.h:214
virtual void abort()=0
std::unique_ptr< detail::divergence_detector< explorer_type > > m_divergence_detector
const lps::explorer_options & options
bool max_states_exceeded(const std::size_t thread_index)
detail::action_detector< explorer_type > m_action_detector
state_space_generator(const Specification &lpsspec, const lps::explorer_options &options_, explorer_type &explorer_)
detail::progress_monitor m_progress_monitor
detail::trace_constructor< explorer_type > m_trace_constructor
detail::nondeterminism_detector< explorer_type > m_nondeterminism_detector
detail::deadlock_detector< explorer_type > m_deadlock_detector