LCOV - code coverage report
Current view: top level - pbes/test - pbes_explorer_test.cpp (source / functions) Hit Total Coverage
Test: mcrl2_coverage.info.cleaned Lines: 129 133 97.0 %
Date: 2024-04-26 03:18:02 Functions: 18 18 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Author(s): Gijs Kant
       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 pbes_explorer_test.cpp
      10             : /// \brief Test for the PBES_Explorer interface.
      11             : 
      12             : #include <boost/test/included/unit_test.hpp>
      13             : #include "mcrl2/utilities/logger.h"
      14             : 
      15             : #ifndef MCRL2_SKIP_LONG_TESTS
      16             : 
      17             : #include "mcrl2/utilities/test_utilities.h"
      18             : #include "mcrl2/pbes/normalize.h"
      19             : #include "mcrl2/pbes/pbes_explorer.h"
      20             : #include "mcrl2/pbes/txt2pbes.h"
      21             : 
      22             : using namespace mcrl2;
      23             : using namespace mcrl2::pbes_system;
      24             : using namespace mcrl2::pbes_system::detail;
      25             : 
      26             : namespace ltsmin
      27             : {
      28             : 
      29             : namespace test
      30             : {
      31             : 
      32             : class explorer : public mcrl2::pbes_system::explorer {
      33             : private:
      34             :     std::set<std::vector<int> > visited;
      35             :     std::deque<std::vector<int> > fresh;
      36             :     std::size_t transition_count;
      37             : 
      38             : public:
      39             : #ifdef MCRL2_ENABLE_JITTYC
      40           4 :     explorer(const pbes& p, const std::string& rewrite_strategy = "jittyc", bool reset = false, bool always_split = false) :
      41             : #else
      42             :     explorer(const pbes& p, const std::string& rewrite_strategy = "jitty", bool reset = false, bool always_split = false) :
      43             : #endif
      44             :         mcrl2::pbes_system::explorer(p, rewrite_strategy, reset, always_split),
      45           4 :         transition_count(0)
      46           4 :     {}
      47             : 
      48           2 :     explorer(const std::string& f, const std::string& rewrite_strategy = "jittyc", bool reset = false, bool always_split = false) :
      49             :       mcrl2::pbes_system::explorer(f, rewrite_strategy, reset, always_split),
      50           2 :       transition_count(0)
      51           2 :     {}
      52             : 
      53             :     std::size_t get_state_count() const
      54             :     {
      55             :         return visited.size();
      56             :     }
      57             : 
      58             :     std::size_t get_transition_count() const
      59             :     {
      60             :         return transition_count;
      61             :     }
      62             : 
      63             :     const std::set<std::vector<int> >& get_visited() const
      64             :     {
      65             :         return visited;
      66             :     }
      67             : 
      68        3366 :     std::vector<int> to_int_vector(int size, int* data)
      69             :     {
      70        3366 :       std::vector<int> result;
      71       16730 :       for(int i=0; i < size; i++)
      72             :       {
      73             :         // testing serialisation/deserialisation
      74       13364 :         int type_no = this->get_info()->get_lts_type().get_state_type_no(i);
      75       13364 :         std::string s = this->get_value(type_no, data[i]);
      76             :         //std::clog << "Testing (de)serialisation of expression: " << s << std::endl;
      77       13364 :         int index = this->get_index(type_no, s);
      78       13364 :         BOOST_CHECK(index==data[i]);
      79             : 
      80       13364 :         result.push_back(data[i]);
      81       13364 :       }
      82        3366 :       return result;
      83           0 :     }
      84             : 
      85         866 :     void from_int_vector(int size, std::vector<int> data, int* dst)
      86             :     {
      87         866 :       BOOST_CHECK(size==(int)data.size());
      88         866 :       auto it = data.begin();
      89        4302 :       for(int i=0; i < size; i++, it++)
      90             :       {
      91        3436 :         dst[i] = *it;
      92             :       }
      93         866 :     }
      94             : 
      95             :     template <typename callback>
      96        4302 :     void next_state_long(int* const& src, std::size_t group, callback& f)
      97             :     {
      98        4302 :         mcrl2::pbes_system::explorer::next_state_long(src, group, f);
      99        4302 :     }
     100             : 
     101             :     template <typename callback>
     102         866 :     void next_state_all(int* const& src, callback& f)
     103             :     {
     104         866 :         mcrl2::pbes_system::explorer::next_state_all(src, f);
     105         866 :     }
     106             : 
     107           6 :     void initial_state(int* state)
     108             :     {
     109           6 :         mcrl2::pbes_system::explorer::initial_state(state);
     110           6 :     }
     111             : 
     112             :     int state_label(int label, int* const& s)
     113             :     {
     114             :         std::string varname = this->get_string_value(s[0]);
     115             :         if (label==0)
     116             :         {
     117             :             int priority = map_at(this->get_info()->get_variable_priorities(), varname);
     118             :             return priority;
     119             :         }
     120             :         else if (label==1)
     121             :         {
     122             :             lts_info::operation_type type = map_at(this->get_info()->get_variable_types(), varname);
     123             :             return type==parity_game_generator::PGAME_AND ? 1 : 0;
     124             :         }
     125             :         return 0;
     126             :     }
     127             : 
     128             :     void bfs();
     129             : };
     130             : 
     131             : struct pbes_state_cb
     132             : {
     133             :     ltsmin::test::explorer* explorer;
     134             :     std::vector<std::vector<int> > successors;
     135             :     std::size_t count;
     136             : 
     137        5168 :     pbes_state_cb (ltsmin::test::explorer* explorer_)
     138        5168 :         : explorer(explorer_), count(0)
     139        5168 :     {}
     140             : 
     141        3360 :     void operator()(int* const& next_state,
     142             :                     int group = -1)
     143             :     {
     144        3360 :         int state_length = explorer->get_info()->get_lts_type().get_state_length();
     145        3360 :         successors.push_back(explorer->to_int_vector(state_length, next_state));
     146        3360 :         count++;
     147        3360 :     }
     148             : 
     149        5168 :     const std::vector<std::vector<int> >& get_successors() const
     150             :     {
     151        5168 :         return successors;
     152             :     }
     153             : 
     154             :     std::size_t get_count() const
     155             :     {
     156             :         return count;
     157             :     }
     158             : };
     159             : 
     160           6 : void explorer::bfs()
     161             : {
     162           6 :     int state_length = get_info()->get_lts_type().get_state_length();
     163           6 :     int num_rows = get_info()->get_number_of_groups();
     164             :     // int initial_state[state_length]; N.B. This is not portable C++
     165           6 :     int* initial_state = MCRL2_SPECIFIC_STACK_ALLOCATOR(int, state_length);
     166           6 :     this->initial_state(initial_state);
     167           6 :     std::vector<int> initial_state_vector = this->to_int_vector(state_length, initial_state);
     168           6 :     visited.insert(initial_state_vector);
     169           6 :     fresh.push_back(initial_state_vector);
     170             :     // int state[state_length]; N.B. This is not portable C++
     171           6 :     int* state = MCRL2_SPECIFIC_STACK_ALLOCATOR(int, state_length);
     172         872 :     while (!fresh.empty())
     173             :     {
     174         866 :         std::vector<int> state_vector = fresh.front();
     175         866 :         fresh.pop_front();
     176         866 :         from_int_vector(state_length, state_vector, state);
     177         866 :         ltsmin::test::pbes_state_cb f(this);
     178         866 :         this->next_state_all(state, f);
     179         866 :         std::vector<std::vector<int> > successors = f.get_successors();
     180             : 
     181         866 :         std::set<std::vector<int> > succ_set;
     182             :         //std::clog << successors.size() << " successors" << std::endl;
     183         866 :         transition_count += successors.size();
     184        2546 :         for(const std::vector<int>& s: successors)
     185             :         {
     186        1680 :           std::pair<std::set<std::vector<int> >::iterator,bool> ret;
     187        1680 :           ret = visited.insert(s);
     188        1680 :           if (ret.second)
     189             :           {
     190         860 :             fresh.push_back(s);
     191             :           }
     192        1680 :           succ_set.insert(s);
     193             :         }
     194             :         // check if the result is the same if we use groups:
     195             : 
     196         866 :         std::set<std::vector<int> > succ_set_groups;
     197        5168 :         for(int g=0; g < num_rows; g++)
     198             :         {
     199        4302 :             ltsmin::test::pbes_state_cb f(this);
     200        4302 :             this->next_state_long(state, g, f);
     201        4302 :             std::vector<std::vector<int> > successors_groups = f.get_successors();
     202             : 
     203        5982 :             for(const std::vector<int>& s: successors_groups)
     204             :             {
     205        1680 :                 succ_set_groups.insert(s);
     206             :             }
     207        4302 :         }
     208         866 :         BOOST_CHECK(succ_set==succ_set_groups);
     209         866 :     }
     210           6 : }
     211             : 
     212             : } // namespace test
     213             : 
     214             : } // namespace ltsmin
     215             : 
     216             : 
     217           4 : void run_pbes_explorer(const std::string& pbes_text, int num_parts, int num_groups, int num_states, int num_transitions,
     218             :     const std::string& rewrite_strategy = "jitty")
     219             : {
     220           4 :   std::clog << "run_pbes_explorer" << std::endl;
     221           4 :   pbes p = txt2pbes(pbes_text);
     222           4 :   normalize(p);
     223           4 :   if (!is_ppg(p))
     224             :   {
     225           0 :     std::clog << "Rewriting to PPG..." << std::endl;
     226           0 :     p = to_ppg(p);
     227           0 :     std::clog << "done." << std::endl;
     228             :   }
     229           4 :   ltsmin::test::explorer* pbes_explorer = new ltsmin::test::explorer(p, rewrite_strategy);
     230           4 :   lts_info* info = pbes_explorer->get_info();
     231           4 :   int state_length = info->get_lts_type().get_state_length();
     232           4 :   BOOST_CHECK(num_parts==state_length);
     233             :   //std::clog << state_length << " parts" << std::endl;
     234             :   //int num_rows = info->get_number_of_groups();
     235             :   //std::clog << num_rows << " groups" << std::endl;
     236             :   //BOOST_CHECK(num_groups==num_rows);
     237           4 :   std::map<int,std::vector<bool> > matrix = info->get_dependency_matrix();
     238           4 :   std::map<int,std::vector<bool> > read_matrix = info->get_read_matrix();
     239           4 :   std::map<int,std::vector<bool> > write_matrix = info->get_write_matrix();
     240             :   (void)matrix;
     241             :   (void)read_matrix;
     242             :   (void)write_matrix;
     243             :   // TODO: check matrices ...
     244             : 
     245           4 :   pbes_explorer->bfs();
     246             :   // check number of states and transitions:
     247             :   //BOOST_CHECK(num_states==(int)pbes_explorer->get_state_count());
     248             :   //BOOST_CHECK(num_transitions==(int)pbes_explorer->get_transition_count());
     249           4 :   delete pbes_explorer;
     250             : 
     251           4 : }
     252             : 
     253           2 : void run_pbes_explorer_file(const std::string& filename, int num_parts, int num_groups, int num_states, int num_transitions,
     254             :     const std::string& rewrite_strategy = "jitty")
     255             : {
     256           2 :   std::clog << "run_pbes_explorer_file" << std::endl;
     257           2 :   ltsmin::test::explorer* pbes_explorer = new ltsmin::test::explorer(filename, rewrite_strategy);
     258           2 :   lts_info* info = pbes_explorer->get_info();
     259           2 :   int state_length = info->get_lts_type().get_state_length();
     260           2 :   BOOST_CHECK(num_parts==state_length);
     261             :   //std::clog << state_length << " parts" << std::endl;
     262             :   //int num_rows = info->get_number_of_groups();
     263             :   //std::clog << num_rows << " groups" << std::endl;
     264             :   //BOOST_CHECK(num_groups==num_rows);
     265           2 :   std::map<int,std::vector<bool> > matrix = info->get_dependency_matrix();
     266           2 :   std::map<int,std::vector<bool> > read_matrix = info->get_read_matrix();
     267           2 :   std::map<int,std::vector<bool> > write_matrix = info->get_write_matrix();
     268             :   (void)matrix;
     269             :   (void)read_matrix;
     270             :   (void)write_matrix;
     271             :   // TODO: check matrices ...
     272             : 
     273           2 :   pbes_explorer->bfs();
     274             :   // check number of states and transitions:
     275             :   //BOOST_CHECK(num_states==(int)pbes_explorer->get_state_count());
     276             :   //BOOST_CHECK(num_transitions==(int)pbes_explorer->get_transition_count());
     277           2 :   delete pbes_explorer;
     278           2 : }
     279             : 
     280             : 
     281           2 : BOOST_AUTO_TEST_CASE(buffer)
     282             : {
     283             :   // buffer.nodeadlock.pbesparelm
     284             :   std::string pbes_text =
     285             :     "sort D = struct d1 | d2;\n"
     286             :     "map  N: Pos;\n"
     287             :     "eqn  N  =  2;\n"
     288             :     "pbes nu X(q_Buffer: List(D)) =\n"
     289             :     "  (val(#q_Buffer < 2) || val(!(q_Buffer == [])))\n"
     290             :     "  && (forall d_Buffer1: D. val(!(#q_Buffer < 2)) || X(q_Buffer <| d_Buffer1))\n"
     291             :     "  && (val(!!(q_Buffer == [])) || X(tail(q_Buffer)));\n"
     292           1 :     "init X([]);"
     293             :   ;
     294           1 :   int num_parts = 2; // 1 var + 1 parameter
     295           1 :   int num_groups = 3; // each of the conjuncts
     296           1 :   int num_states = 7;
     297           1 :   int num_transitions = 12;
     298           1 :   run_pbes_explorer(pbes_text, num_parts, num_groups, num_states, num_transitions, "jitty");
     299             : #ifdef MCRL2_ENABLE_JITTYC
     300           1 :   run_pbes_explorer(pbes_text, num_parts, num_groups, num_states, num_transitions, "jittyc");
     301             : #endif
     302           1 : }
     303           2 : BOOST_AUTO_TEST_CASE(buffer_2_read_then_eventually_send_pbesparelm_simple)
     304             : {
     305             :   std::string pbes_text =
     306             :       "sort D = struct d1 | d2;\n"
     307             :       "map  M: Pos;\n"
     308             :       "eqn  M  =  2;\n"
     309             :       "pbes nu Z(q_In,q_Out: List(D)) =\n"
     310             :       "  (forall d: D. forall d_In2: D. val(!(d_In2 == d)) || val(!(#q_In < 2)) || X(q_In <| d_In2, q_Out, d)) && (forall d_In1: D. val(!(#q_In < 2)) || Z(q_In <| d_In1, q_Out)) && (val(q_Out == []) || Z(q_In, tail(q_Out))) && (val(!(!(q_In == []) && #q_Out < 2)) || Z(tail(q_In), q_Out <| head(q_In)));\n"
     311             :       "nu X(q_In,q_Out: List(D), d: D) =\n"
     312             :       "  Y(q_In, q_Out, d);\n"
     313             :       "mu Y(q_In,q_Out: List(D), d: D) =\n"
     314             :       "  (val(!(head(q_Out) == d)) || val(q_Out == []) || X(q_In, tail(q_Out), d)) && (forall d_In1: D. val(!(#q_In < 2)) || Y(q_In <| d_In1, q_Out, d)) && (val(head(q_Out) == d) || val(q_Out == []) || Y(q_In, tail(q_Out), d)) && (val(!(!(q_In == []) && #q_Out < 2)) || Y(tail(q_In), q_Out <| head(q_In), d));\n"
     315           1 :       "init Z([], []);\n"
     316             :   ;
     317           1 :   int num_parts = 4; // 1 var + 3 parameters: q_In, q_Out, d
     318           1 :   int num_groups = 9; // each of the conjuncts of every equation
     319           1 :   int num_states = 213;
     320           1 :   int num_transitions = 414;
     321             : 
     322           2 :   std::string pbes_filename = utilities::temporary_filename("pbes_explorer_test");
     323           1 :   save_pbes(txt2pbes(pbes_text), pbes_filename);
     324             : 
     325           1 :   run_pbes_explorer(pbes_text, num_parts, num_groups, num_states, num_transitions, "jitty");
     326           1 :   run_pbes_explorer_file(pbes_filename, num_parts, num_groups, num_states, num_transitions, "jitty");
     327             : #ifdef MCRL2_ENABLE_JITTYC
     328           1 :   run_pbes_explorer(pbes_text, num_parts, num_groups, num_states, num_transitions, "jittyc");
     329           1 :   run_pbes_explorer_file(pbes_filename, num_parts, num_groups, num_states, num_transitions, "jittyc");
     330             : #endif
     331             :   // clean up
     332           1 :   std::remove(pbes_filename.c_str());
     333           1 : }
     334             : 
     335             : #else // ndef MCRL2_SKIP_LONG_TESTS
     336             : 
     337             : BOOST_AUTO_TEST_CASE(skip_test)
     338             : {
     339             : }
     340             : 
     341             : #endif // ndef MCRL2_SKIP_LONG_TESTS
     342             : 
     343           1 : boost::unit_test::test_suite* init_unit_test_suite(int argc, char* argv[])
     344             : {
     345             :   (void) argc;  (void) argv;  //< avoid warning about unused parameters
     346           1 :   mcrl2::log::logger::set_reporting_level(mcrl2::log::debug);
     347           1 :   return nullptr;
     348             : }

Generated by: LCOV version 1.14