LCOV - code coverage report
Current view: top level - lts/include/mcrl2/lts - state_space_generator.h (source / functions) Hit Total Coverage
Test: mcrl2_coverage.info.cleaned Lines: 117 356 32.9 %
Date: 2024-05-01 03:37:31 Functions: 53 142 37.3 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14