LCOV - code coverage report
Current view: top level - lps/test - ltsmin_test.cpp (source / functions) Hit Total Coverage
Test: mcrl2_coverage.info.cleaned Lines: 175 177 98.9 %
Date: 2024-04-19 03:43:27 Functions: 12 12 100.0 %
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 ltsmin_test.cpp
      10             : /// \brief Test for the pins class that connects mCRL2 with LTSMin (http://fmt.cs.utwente.nl/tools/ltsmin/).
      11             : 
      12             : #define BOOST_TEST_MODULE ltsmin_test
      13             : #include <boost/test/included/unit_test.hpp>
      14             : 
      15             : #include "mcrl2/lps/detail/test_input.h"
      16             : #include "mcrl2/lps/linearise.h"
      17             : #include "mcrl2/lps/ltsmin.h"
      18             : 
      19             : using namespace mcrl2;
      20             : 
      21             : typedef int* state_vector;
      22             : 
      23             : inline
      24          14 : std::string print_state(const state_vector& s, std::size_t size, const std::string& msg = "state: ")
      25             : {
      26          14 :   int* first = s;
      27          14 :   int* last = s + size;
      28             : 
      29          14 :   std::ostringstream out;
      30          14 :   out << msg << "[";
      31         168 :   for (int* i = first; i != last; ++i)
      32             :   {
      33         154 :     if (i != first)
      34             :     {
      35         140 :       out << ", ";
      36             :     }
      37         154 :     out << *i;
      38             :   }
      39          14 :   out << "]";
      40          28 :   return out.str();
      41          14 : }
      42             : 
      43             : struct state_callback_function
      44             : {
      45             :   std::size_t state_size;
      46             :   std::size_t state_count;
      47             : 
      48          26 :   explicit state_callback_function(std::size_t size)
      49          26 :     : state_size(size),
      50          26 :       state_count(0)
      51          26 :   {}
      52             : 
      53          12 :   void operator()(state_vector const& next_state, int* const& labels, int group=-1)
      54             :   {
      55          12 :     state_count++;
      56          12 :     std::cout << print_state(next_state, state_size, "visit state: ") << " edge label = " << labels[0] << " group = " << group << std::endl;
      57          12 :   }
      58             : };
      59             : 
      60           2 : void test_data_type(lps::pins_data_type& type)
      61             : {
      62           2 :   std::cout << "test_data_type(" << type.name() << ")" << std::endl;
      63             : 
      64             :   // check serialize/deserialize
      65           6 :   for (std::size_t i = 0; i < type.size(); ++i)
      66             :   {
      67           4 :     std::string s = type.serialize(i);
      68           4 :     std::cout << "serialize(" << i << ") = " << type.serialize(i) << std::endl;
      69           4 :     std::size_t j = type.deserialize(s);
      70           4 :     BOOST_CHECK(i == j);
      71           4 :   }
      72             : 
      73             :   // check print/parse
      74           6 :   for (std::size_t i = 0; i < type.size(); ++i)
      75             :   {
      76           4 :     std::string s = type.print(i);
      77           4 :     std::cout << "print(" <<  i << ") = " << s << std::endl;
      78           4 :     std::size_t j = type.parse(s);
      79           4 :     std::cout << "parse(" <<  s << ") = " << j << std::endl;
      80           4 :   }
      81             : 
      82             :   // test iterator
      83           2 :   std::size_t index = 0;
      84           6 :   for (auto i = type.index_begin(); i != type.index_end(); ++i)
      85             :   {
      86           4 :     std::cout << "iterator " << index << " -> " << *i << std::endl;
      87           4 :     BOOST_CHECK(*i == index);
      88           4 :     index++;
      89             :   }
      90           2 : }
      91             : 
      92           2 : void test_ltsmin(const lps::specification& lpsspec, const std::string& filename, const std::string& rewriter_strategy)
      93             : {
      94           2 :   lps::pins p(filename, rewriter_strategy);
      95           2 :   std::size_t N = p.process_parameter_count();
      96             : 
      97           2 :   BOOST_CHECK(p.process_parameter_count() == 11);
      98             : 
      99           2 :   std::size_t G = p.guard_count();
     100             : 
     101           2 :   BOOST_CHECK(G == 13);
     102           2 :   BOOST_CHECK(p.guard_parameters(0).size() == 1);
     103           2 :   BOOST_CHECK(p.guard_info(5).size() == 2);
     104             :   // Check below is removed as the result is unpredictable, since processes are put into a set instead of
     105             :   // a vector. The result below depends on the ordering in which process identifiers are stored in memory.
     106             :   // BOOST_CHECK(p.guard_name(0) == "s1_S == 2" || p.guard_name(0) == "s1_S == 1");
     107             : 
     108           2 :   BOOST_CHECK(p.edge_label_count() == 1);
     109           4 :   for (std::size_t i = 0; i < p.edge_label_count(); i++)
     110             :   {
     111           2 :     BOOST_CHECK(p.edge_label_type(i) == p.datatype_count() - 1);
     112             :   }
     113             : 
     114           2 :   std::set<data::sort_expression> params;
     115          24 :   for (const data::variable& v: lpsspec.process().process_parameters())
     116             :   {
     117          22 :     params.insert(v.sort());
     118             :   }
     119           2 :   BOOST_CHECK(p.datatype_count() == params.size() + 1);
     120           2 :   BOOST_CHECK(p.group_count() == 10);
     121             : 
     122           2 :   std::size_t index = 0;
     123          24 :   for (const data::variable& v: lpsspec.process().process_parameters())
     124             :   {
     125          22 :         const lps::pins_data_type& type = p.data_type(p.process_parameter_type(index++));
     126          22 :         BOOST_CHECK(type.name() == data::pp(v.sort()));
     127             :   }
     128             : 
     129             :   // get the initial state
     130           2 :   state_vector initial_state = new int[N];
     131           2 :   state_vector dest_state = new int[N];
     132           2 :   int* labels = new int[p.edge_label_count()];
     133           2 :   p.get_initial_state(initial_state);
     134           2 :   std::cout << print_state(initial_state, N, "initial state: ") << std::endl;
     135             : 
     136             :   // find all successors of the initial state
     137           2 :   state_callback_function f_all(p.process_parameter_count());
     138           2 :   p.next_state_all(initial_state, f_all, dest_state, labels);
     139           2 :   std::cout << "f_all.state_count = " << f_all.state_count << std::endl;
     140             : 
     141             :   // find successors of the initial state for individual groups
     142           2 :   std::size_t count = 0;
     143          22 :   for (std::size_t group = 0; group < p.group_count(); group++)
     144             :   {
     145          20 :     state_callback_function f_long(p.process_parameter_count());
     146          20 :     p.next_state_long(initial_state, group, f_long, dest_state, labels);
     147          20 :     std::cout << "group " << group << " count = " << f_long.state_count << std::endl;
     148          20 :     count += f_long.state_count;
     149             :   }
     150           2 :   BOOST_CHECK(count == f_all.state_count);
     151             : 
     152             :   // find successors (without evaluating condition) of the initial state for individual groups
     153           2 :   count = 0;
     154          22 :   for (std::size_t group = 0; group < p.group_count(); group++)
     155             :   {
     156             : 
     157          20 :     std::size_t all_true = p.GUARD_TRUE;
     158          40 :     for(std::size_t guard = 0; guard < p.guard_info(group).size() && all_true == p.GUARD_TRUE; guard++) {
     159          20 :       all_true = p.eval_guard_long(initial_state, p.guard_info(group)[guard]);
     160             :     }
     161             : 
     162          20 :     if (all_true == p.GUARD_TRUE) {
     163           4 :       state_callback_function f_long(p.process_parameter_count());
     164           4 :       p.update_long(initial_state, group, f_long, dest_state, labels);
     165           4 :       std::cout << "group " << group << " count = " << f_long.state_count << std::endl;
     166           4 :       count += f_long.state_count;
     167             :     }
     168             :   }
     169           2 :   BOOST_CHECK(count == f_all.state_count);
     170             : 
     171           2 :   lps::pins_data_type& action_label_type = p.data_type(p.datatype_count() - 1);
     172           2 :   test_data_type(action_label_type);
     173             : 
     174           2 :   delete[] initial_state;
     175           2 :   delete[] dest_state;
     176           2 :   delete[] labels;
     177             : 
     178           2 :   std::cout << p.info() << std::endl;
     179             : 
     180             :   // test summand_action_names()
     181           2 :   std::cout << "--- summand action names ---" << std::endl;
     182          22 :   for (std::size_t i = 0; i < p.group_count(); i++)
     183             :   {
     184          20 :     std::cout << i << " {";
     185          20 :     std::set<std::string> s = p.summand_action_names(i);
     186          40 :     for (auto j = s.begin(); j != s.end(); ++j)
     187             :     {
     188          20 :       if (j != s.begin())
     189             :       {
     190           0 :         std::cout << ", ";
     191             :       }
     192          20 :       std::cout << *j;
     193             :     }
     194          20 :     std::cout << "}" << std::endl;
     195          20 :   }
     196           2 : }
     197             : 
     198           1 : void test_ltsmin()
     199             : {
     200           2 :   lps::specification abp_spec = remove_stochastic_operators(lps::linearise(lps::detail::ABP_SPECIFICATION()));
     201           1 :   std::string abp_filename = "temporary_abp.lps";
     202           1 :   save_lps(abp_spec, abp_filename);
     203           1 :   test_ltsmin(abp_spec, abp_filename, "jitty");
     204             : #ifdef MCRL2_ENABLE_JITTYC
     205           1 :   test_ltsmin(abp_spec, abp_filename, "jittyc");
     206             : #endif // MCRL2_ENABLE_JITTYC
     207           1 :   std::remove(abp_filename.c_str());
     208           1 : }
     209             : 
     210             : template <typename Iter>
     211           6 : std::string print_vector(Iter first, Iter last)
     212             : {
     213           6 :   std::ostringstream out;
     214           6 :   out << "[";
     215           8 :   for (Iter i = first; i != last; ++i)
     216             :   {
     217           2 :     if (i != first)
     218             :     {
     219           0 :       out << ", ";
     220             :     }
     221           2 :     out << *i;
     222             :   }
     223           6 :   out << "]";
     224          12 :   return out.str();
     225           6 : }
     226             : 
     227             : template <typename Container>
     228           6 : std::string print_vector(const Container& c)
     229             : {
     230           6 :   return print_vector(c.begin(), c.end());
     231             : }
     232             : 
     233             : inline
     234             : std::string read_groups(const lps::pins& p)
     235             : {
     236             :   std::ostringstream out;
     237             :   for (std::size_t i = 0; i < p.group_count(); i++)
     238             :   {
     239             :     out << print_vector(p.read_group(i)) << std::endl;
     240             :   }
     241             :   return out.str();
     242             : }
     243             : 
     244             : inline
     245             : std::string write_groups(const lps::pins& p)
     246             : {
     247             :   std::ostringstream out;
     248             :   for (std::size_t i = 0; i < p.group_count(); i++)
     249             :   {
     250             :     out << print_vector(p.write_group(i)) << std::endl;
     251             :   }
     252             :   return out.str();
     253             : }
     254             : 
     255             : inline
     256             : std::string update_groups(const lps::pins& p)
     257             : {
     258             :   std::ostringstream out;
     259             :   for (std::size_t i = 0; i < p.group_count(); i++)
     260             :   {
     261             :     out << print_vector(p.update_group(i)) << std::endl;
     262             :   }
     263             :   return out.str();
     264             : }
     265             : 
     266             : inline
     267           1 : void test_dependency_matrix()
     268             : {
     269             :   std::string ONEBIT =
     270             :     "proc P(b: Bool) =          \n"
     271             :     "       tau . P(b = false); \n"
     272             :     "                           \n"
     273           1 :     "init P(true);              \n"
     274             :     ;
     275             : 
     276           1 :   lps::specification spec = lps::parse_linear_process_specification(ONEBIT);
     277           1 :   std::string filename = "temporary_onebit.lps";
     278           1 :   save_lps(spec, filename);
     279           2 :   lps::pins p(filename, "jitty");
     280             : 
     281           2 :   for (std::size_t i = 0; i < p.group_count(); i++)
     282             :   {
     283           1 :     std::cout << "\n";
     284           1 :     std::cout << "  read_group(" << i << ") = " << print_vector(p.read_group(i)) << std::endl;
     285           1 :     std::cout << " write_group(" << i << ") = " << print_vector(p.write_group(i)) << std::endl;
     286           1 :     std::cout << "update_group(" << i << ") = " << print_vector(p.update_group(i)) << std::endl;
     287             :   }
     288           1 :   BOOST_CHECK(print_vector(p.read_group(0)) == "[]");
     289           1 :   BOOST_CHECK(print_vector(p.write_group(0)) == "[0]");
     290           1 :   BOOST_CHECK(print_vector(p.update_group(0)) == "[]");
     291             : 
     292             :   // cleanup temporary files
     293           1 :   std::remove(filename.c_str());
     294           1 : }
     295             : 
     296             : inline
     297           1 : void test_serialisation()
     298             : {
     299             :   std::string EXAMPLE  =
     300             :     "sort Piece = struct Red | Yellow | None;   \n"
     301             :     "                                           \n"
     302             :     "proc P(i: Pos, j: Nat, p: Piece) =         \n"
     303             :     "       tau . P(i = 1, j = 0, p = Red);     \n"
     304             :     "                                           \n"
     305           1 :     "init P(1, 1, None);                        \n"
     306             :     ;
     307             : 
     308           1 :   lps::specification spec = lps::parse_linear_process_specification(EXAMPLE);
     309           1 :   std::string filename = "temporary_onebit.lps";
     310           1 :   save_lps(spec, filename);
     311           2 :   lps::pins p1(filename, "jitty");
     312           2 :   lps::pins p2(filename, "jitty");
     313           1 :   std::cout << "datatypes: " << p1.datatype_count() << std::endl;
     314           5 :   for(std::size_t i=0; i < p1.datatype_count(); i++)
     315             :   {
     316           4 :     std::cout << i << ": " << p1.data_type(i).name() << std::endl;
     317             :   }
     318           1 :   std::vector<std::pair<std::string, std::size_t>> expressions;
     319           1 :   expressions.push_back(std::make_pair("1", 0));
     320           1 :   expressions.push_back(std::make_pair("0", 1));
     321           1 :   expressions.push_back(std::make_pair("1", 1));
     322           1 :   expressions.push_back(std::make_pair("Red", 2));
     323           1 :   expressions.push_back(std::make_pair("Yellow", 2));
     324             : 
     325           6 :   for(auto e : expressions)
     326             :   {
     327           5 :     std::string s = e.first;
     328           5 : std::cerr << "STRING " << s << "\n";
     329           5 :     std::size_t type = e.second;
     330           5 : std::cerr << "TYPE " << type << "\n";
     331             : 
     332           5 :     data::data_expression d1 = data::parse_data_expression(s, spec.data());
     333           5 : std::cerr << "DATA EXPRESSION " << d1 << "\n";
     334           5 :     std::string serialised = p1.data_type(type).serialize(p1.data_type(type)[d1]);
     335           5 :     data::data_expression d2(p2.data_type(type).get(p2.data_type(type).deserialize(serialised)));
     336           5 :     std::cout << "string:     " << s << std::endl;
     337           5 :     std::cout << "expression: " << d1 << std::endl;
     338           5 :     std::cout << "serialised: " << serialised << std::endl;
     339           5 :     std::cout << "result:     " << d2 << std::endl;
     340           5 :     BOOST_CHECK(d1==d2);
     341           5 :   }
     342             : 
     343             :   // cleanup temporary files
     344           1 :   std::remove(filename.c_str());
     345           1 : }
     346             : 
     347           2 : BOOST_AUTO_TEST_CASE(test_main)
     348             : {
     349           1 :   test_dependency_matrix();
     350           1 :   test_serialisation();
     351           1 :   test_ltsmin();
     352           1 : }

Generated by: LCOV version 1.14