LCOV - code coverage report
Current view: top level - pbes/include/mcrl2/pbes - parelm.h (source / functions) Hit Total Coverage
Test: mcrl2_coverage.info.cleaned Lines: 89 145 61.4 %
Date: 2024-04-26 03:18:02 Functions: 11 17 64.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Author(s): Wieger Wesselink
       2             : //
       3             : // Distributed under the Boost Software License, Version 1.0.
       4             : // (See accompanying file LICENSE_1_0.txt or copy at
       5             : // http://www.boost.org/LICENSE_1_0.txt)
       6             : //
       7             : /// \file mcrl2/pbes/parelm.h
       8             : /// \brief The parelm algorithm.
       9             : 
      10             : #ifndef MCRL2_PBES_PARELM_H
      11             : #define MCRL2_PBES_PARELM_H
      12             : 
      13             : #include "mcrl2/pbes/algorithms.h"
      14             : #include "mcrl2/pbes/detail/find_free_variables.h"
      15             : #include "mcrl2/utilities/detail/iota.h"
      16             : #include "mcrl2/utilities/reachable_nodes.h"
      17             : 
      18             : namespace mcrl2::pbes_system {
      19             : 
      20             : namespace detail {
      21             : 
      22             : /// \brief Finds the index of a variable in a sequence
      23             : /// \param variables A sequence of data variables
      24             : /// \param d A data variable
      25             : /// \return The index of \p d in \p v, or -1 if the variable wasn't found
      26             : inline
      27         117 : int variable_index(const data::variable_list& variables, const data::variable& d)
      28             : {
      29         117 :   int index = 0;
      30         781 :   for (const data::variable& v: variables)
      31             :   {
      32         767 :     if (v == d)
      33             :     {
      34         103 :       return index;
      35             :     }
      36         664 :     index++;
      37             :   }
      38          14 :   return -1;
      39             : }
      40             : 
      41             : } // namespace detail
      42             : 
      43             : /// \brief Algorithm class for the parelm algorithm
      44             : class pbes_parelm_algorithm
      45             : {
      46             :   protected:
      47             :     /// \brief The graph type of the dependency graph
      48             :     typedef boost::adjacency_list<boost::setS, boost::vecS, boost::directedS> graph;
      49             : 
      50             :     /// \brief The vertex type of the dependency graph
      51             :     typedef boost::graph_traits<graph>::vertex_descriptor vertex_descriptor;
      52             : 
      53             :     /// \brief The edge type of the dependency graph
      54             :     typedef boost::graph_traits<graph>::edge_descriptor edge_descriptor;
      55             : 
      56             :     struct parelm_dependency_traverser: public pbes_expression_traverser<parelm_dependency_traverser>
      57             :     {
      58             :       typedef pbes_expression_traverser<parelm_dependency_traverser> super;
      59             :       using super::enter;
      60             :       using super::leave;
      61             :       using super::apply;
      62             : 
      63             :       graph& G;
      64             :       const std::map<core::identifier_string, std::size_t>& propvar_offsets;
      65             : 
      66             :       core::identifier_string X;
      67             :       data::variable_list Xparams;
      68             :       std::multiset<data::variable> bound_variables;
      69             : 
      70           1 :       parelm_dependency_traverser(graph& G_, const std::map<core::identifier_string, std::size_t>& propvar_offsets_)
      71           1 :         : G(G_), propvar_offsets(propvar_offsets_)
      72           1 :       {}
      73             : 
      74           6 :       void enter(const forall& x)
      75             :       {
      76          12 :         for (const data::variable& v: x.variables())
      77             :         {
      78           6 :           bound_variables.insert(v);
      79             :         }
      80           6 :       }
      81             : 
      82           6 :       void leave(const forall& x)
      83             :       {
      84          12 :         for (const data::variable& v: x.variables())
      85             :         {
      86           6 :           bound_variables.erase(v);
      87             :         }
      88           6 :       }
      89             : 
      90           0 :       void enter(const exists& x)
      91             :       {
      92           0 :         for (const data::variable& v: x.variables())
      93             :         {
      94           0 :           bound_variables.insert(v);
      95             :         }
      96           0 :       }
      97             : 
      98           0 :       void leave(const exists& x)
      99             :       {
     100           0 :         for (const data::variable& v: x.variables())
     101             :         {
     102           0 :           bound_variables.erase(v);
     103             :         }
     104           0 :       }
     105             : 
     106          11 :       void apply(const propositional_variable_instantiation& x)
     107             :       {
     108             :         using utilities::detail::contains;
     109             : 
     110          11 :         const core::identifier_string& Y = x.name();
     111          11 :         int Yindex = 0;
     112         132 :         for (const data::data_expression& e: x.parameters())
     113             :         {
     114         243 :           for (const data::variable& var: data::find_free_variables(e))
     115             :           {
     116         122 :             if (contains(bound_variables, var))
     117             :             {
     118          13 :               continue;
     119             :             }
     120         109 :             int Xindex = detail::variable_index(Xparams, var);
     121         109 :             if (Xindex < 0)
     122             :             {
     123          14 :               continue;
     124             :             }
     125             :             // parameter (Y, Yindex) is influenced by (X, Xindex)
     126          95 :             boost::add_edge(propvar_offsets.at(Y) + Yindex, propvar_offsets.at(X) + Xindex, G);
     127         121 :           }
     128         121 :           Yindex++;
     129             :         }
     130          11 :       }
     131             : 
     132           2 :       void apply(const pbes_equation& eqn)
     133             :       {
     134           2 :         X = eqn.variable().name();
     135           2 :         Xparams = eqn.variable().parameters();
     136           2 :         super::apply(eqn);
     137           2 :       }
     138             :     };
     139             : 
     140             :     /// \brief Finds unbound variables in a pbes expression
     141             :     /// \param t A PBES expression
     142             :     /// \param bound_variables A sequence of data variables
     143             :     /// \return The unbound variables in \p t that are not contained in \p bound_variables
     144           2 :     static std::set<data::variable> unbound_variables(const pbes_expression& t, const data::variable_list& bound_variables)
     145             :     {
     146           2 :       bool search_propositional_variables = false;
     147           2 :       return detail::find_free_variables(t, bound_variables, search_propositional_variables);
     148             :     }
     149             : 
     150             :     /// \brief Finds the predicate variable to which the data parameter with the given index belongs.
     151             :     /// Here index refers to the cumulative index in the array obtained by concatening all parameters
     152             :     /// of the predicate variables in the pbes \p p.
     153             :     /// \param p A pbes
     154             :     /// \param index A positive number
     155             :     /// \return The name of the predicate variable that corresponds with \p index
     156           0 :     static core::identifier_string find_predicate_variable(const pbes& p, std::size_t index)
     157             :     {
     158           0 :       std::size_t offset = 0;
     159           0 :       for (const pbes_equation& eqn: p.equations())
     160             :       {
     161           0 :         std::size_t size = eqn.variable().parameters().size();
     162           0 :         if (offset + size > index)
     163             :         {
     164           0 :           return eqn.variable().name();
     165             :         }
     166           0 :         offset += eqn.variable().parameters().size();
     167             :       }
     168           0 :       return core::identifier_string("<not found>");
     169             :     }
     170             : 
     171           1 :     static void compute_dependency_graph(const pbes& p, const std::map<core::identifier_string, std::size_t>& propvar_offsets, graph& G)
     172             :     {
     173           1 :       parelm_dependency_traverser f(G, propvar_offsets);
     174           3 :       for (const pbes_equation& eqn: p.equations())
     175             :       {
     176           2 :         f.apply(eqn);
     177             :       }
     178           1 :     }
     179             : 
     180             :   public:
     181             :     /// \brief Runs the parelm algorithm. The pbes \p is modified by the algorithm
     182             :     /// \param p A pbes
     183           1 :     void run(pbes& p)
     184             :     {
     185           1 :       data::variable_list global_variables(p.global_variables().begin(), p.global_variables().end());
     186           1 :       std::vector<data::variable> predicate_variables;
     187             : 
     188             :       // compute a mapping from propositional variable names to offsets
     189           1 :       std::size_t offset = 0;
     190           1 :       std::map<core::identifier_string, std::size_t> propvar_offsets;
     191           3 :       for (pbes_equation& eqn: p.equations())
     192             :       {
     193           2 :         propvar_offsets[eqn.variable().name()] = offset;
     194           2 :         offset += eqn.variable().parameters().size();
     195           2 :         predicate_variables.insert(predicate_variables.end(), eqn.variable().parameters().begin(), eqn.variable().parameters().end());
     196             :       }
     197           1 :       std::size_t N = offset; // # variables
     198             : 
     199             :       // compute the initial set v of significant variables
     200           1 :       std::set<std::size_t> significant_variables;
     201           1 :       offset = 0;
     202           3 :       for (pbes_equation& eqn: p.equations())
     203             :       {
     204          10 :         for (const data::variable& w: unbound_variables(eqn.formula(), global_variables))
     205             :         {
     206           8 :           int k = detail::variable_index(eqn.variable().parameters(), w);
     207           8 :           if (k < 0)
     208             :           {
     209           0 :             throw mcrl2::runtime_error("<variable error>" + data::pp(w));
     210             :           }
     211           8 :           significant_variables.insert(offset + k);
     212           2 :         }
     213           2 :         offset += eqn.variable().parameters().size();
     214             :       }
     215             : 
     216           1 :       graph G(N);
     217           1 :       compute_dependency_graph(p, propvar_offsets, G);
     218             : 
     219             :       // compute the indices s of the parameters that need to be removed
     220           1 :       std::vector<std::size_t> r = utilities::reachable_nodes(G, significant_variables.begin(), significant_variables.end());
     221           1 :       std::sort(r.begin(), r.end());
     222           1 :       std::vector<std::size_t> q(N);
     223           1 :       utilities::detail::iota(q.begin(), q.end(), 0);
     224           1 :       std::vector<std::size_t> s;
     225           1 :       std::set_difference(q.begin(), q.end(), r.begin(), r.end(), std::back_inserter(s));
     226             : 
     227             :       // create a map that specifies the parameters that need to be removed
     228           1 :       std::map<core::identifier_string, std::vector<std::size_t> > removals;
     229           1 :       std::size_t index = 0;
     230           1 :       auto sfirst = s.begin();
     231           3 :       for (pbes_equation& eqn: p.equations())
     232             :       {
     233           2 :         std::size_t maxindex = index + eqn.variable().parameters().size();
     234          17 :         auto slast = std::find_if(sfirst, s.end(), [&](std::size_t i) { return i >= maxindex; });
     235           2 :         if (slast > sfirst)
     236             :         {
     237           2 :           std::vector<std::size_t> w(sfirst, slast);
     238          16 :           std::transform(w.begin(), w.end(), w.begin(), [&](std::size_t i) { return i - index; });
     239           2 :           removals[eqn.variable().name()] = w;
     240           2 :         }
     241           2 :         index = maxindex;
     242           2 :         sfirst = slast;
     243             :       }
     244             : 
     245           1 :       if (mCRL2logEnabled(log::debug))
     246             :       {
     247           0 :         print_dependencies(p, predicate_variables, significant_variables, G);
     248             :       }
     249             : 
     250             :       // print verbose output
     251           1 :       if (mCRL2logEnabled(log::verbose))
     252             :       {
     253           0 :         print_removed_parameters(predicate_variables, propvar_offsets, removals);
     254             :       }
     255             : 
     256             :       // remove the parameters
     257           1 :       pbes_system::algorithms::remove_parameters(p, removals);
     258           1 :     }
     259             : 
     260           0 :     void print_removed_parameters(const std::vector<data::variable>& predicate_variables,
     261             :                                   const std::map<core::identifier_string, std::size_t>& propvar_offsets,
     262             :                                   const std::map<core::identifier_string, std::vector<std::size_t>>& removals) const
     263             :     {
     264           0 :       mCRL2log(log::verbose) << "\nremoving the following parameters:" << std::endl;
     265           0 :       for (auto& removal: removals)
     266             :       {
     267           0 :         core::identifier_string X1 = removal.first;
     268           0 :         for (std::size_t j: removal.second)
     269             :         {
     270           0 :           data::variable v1 = predicate_variables[j + propvar_offsets.at(X1)];
     271           0 :           mCRL2log(log::verbose) << "(" + core::pp(X1) + ", " + data::pp(v1) + ")\n";
     272           0 :         }
     273           0 :       }
     274           0 :     }
     275             : 
     276           0 :     static void print_dependencies(const pbes& p, const std::vector<data::variable>& predicate_variables, const std::set<std::size_t>& significant_variables, const graph& G)
     277             :     {
     278           0 :       mCRL2log(log::debug) << "\ninfluential parameters:" << std::endl;
     279           0 :       for (std::size_t i: significant_variables)
     280             :       {
     281           0 :         core::identifier_string X1 = find_predicate_variable(p, i);
     282           0 :         data::variable v1 = predicate_variables[i];
     283           0 :         mCRL2log(log::debug) << "(" + core::pp(X1) + ", " + data::pp(v1) + ")\n";
     284           0 :       }
     285           0 :       mCRL2log(log::debug) << "\ndependencies:" << std::endl;
     286             :       typedef boost::graph_traits<graph>::edge_iterator edge_iterator;
     287           0 :       std::pair<edge_iterator, edge_iterator> e = edges(G);
     288           0 :       edge_iterator first = e.first;
     289           0 :       edge_iterator last  = e.second;
     290           0 :       for (; first != last; ++first)
     291             :       {
     292           0 :         edge_descriptor f = *first;
     293           0 :         std::size_t i1 = boost::source(f, G);
     294           0 :         core::identifier_string X1 = find_predicate_variable(p, i1);
     295           0 :         data::variable v1 = predicate_variables[i1];
     296           0 :         std::size_t i2 = boost::target(f, G);
     297           0 :         core::identifier_string X2 = find_predicate_variable(p, i2);
     298           0 :         data::variable v2 = predicate_variables[i2];
     299           0 :         std::string left  = "(" + core::pp(X1) + ", " + data::pp(v1) + ")";
     300           0 :         std::string right = "(" + core::pp(X2) + ", " + data::pp(v2) + ")";
     301           0 :         mCRL2log(log::debug) << left << " -> " << right << std::endl;
     302           0 :       }
     303           0 :     }
     304             : };
     305             : 
     306             : /// \brief Apply the parelm algorithm
     307             : /// \param p A PBES to which the algorithm is applied
     308             : inline
     309           0 : void parelm(pbes& p)
     310             : {
     311             :   pbes_parelm_algorithm algorithm;
     312           0 :   algorithm.run(p);
     313           0 : }
     314             : 
     315             : } // namespace mcrl2::pbes_system
     316             : 
     317             : #endif // MCRL2_PBES_PARELM_H

Generated by: LCOV version 1.14