LCOV - code coverage report
Current view: top level - lps/include/mcrl2/lps - parelm.h (source / functions) Hit Total Coverage
Test: mcrl2_coverage.info.cleaned Lines: 96 100 96.0 %
Date: 2024-04-26 03:18:02 Functions: 18 19 94.7 %
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/lps/parelm.h
      10             : /// \brief The parelm algorithm.
      11             : 
      12             : #ifndef MCRL2_LPS_PARELM_H
      13             : #define MCRL2_LPS_PARELM_H
      14             : 
      15             : #include "mcrl2/lps/detail/lps_algorithm.h"
      16             : #include "mcrl2/utilities/detail/iota.h"
      17             : #include "mcrl2/utilities/reachable_nodes.h"
      18             : #include <boost/integer.hpp>
      19             : 
      20             : namespace mcrl2
      21             : {
      22             : 
      23             : namespace lps
      24             : {
      25             : 
      26             : namespace detail
      27             : {
      28             :   inline
      29          26 :   void collect_transition_variables(const action_summand& s, std::set<data::variable>& result)
      30             :   {
      31          26 :     std::set<data::variable> tmp;
      32             : 
      33          26 :     tmp = data::find_all_variables(s.condition());
      34          26 :     result.insert(tmp.begin(), tmp.end());
      35             : 
      36          26 :     tmp = lps::find_all_variables(s.multi_action());
      37          26 :     result.insert(tmp.begin(), tmp.end());
      38          26 :   }
      39             : 
      40             :   inline
      41          10 :   void collect_transition_variables(const stochastic_action_summand& s, std::set<data::variable>& result)
      42             :   {
      43          10 :     collect_transition_variables(static_cast<const action_summand&>(s), result);
      44          10 :     std::set<data::variable> tmp = lps::find_all_variables(s.distribution());
      45          10 :     result.insert(tmp.begin(), tmp.end());
      46          10 :   }
      47             : 
      48             :   inline
      49           3 :   void collect_transition_variables(const deadlock_summand& s, std::set<data::variable>& result)
      50             :   {
      51           3 :     std::set<data::variable> tmp;
      52             : 
      53           3 :     tmp = data::find_all_variables(s.condition());
      54           3 :     result.insert(tmp.begin(), tmp.end());
      55             : 
      56           3 :     tmp = lps::find_all_variables(s.deadlock());
      57           3 :     result.insert(tmp.begin(), tmp.end());
      58           3 :   }
      59             : 
      60             : } // namespace detail
      61             : 
      62             : /// \brief Algorithm class for elimination of unused parameters from a linear
      63             : /// process specification
      64             : template <typename Specification>
      65             : class parelm_algorithm: public lps::detail::lps_algorithm<Specification>
      66             : {
      67             :   typedef typename lps::detail::lps_algorithm<Specification> super;
      68             :   using super::m_spec;
      69             :   using super::verbose;
      70             : 
      71             :   protected:
      72             : 
      73             :     /// \brief Returns the data variables that are considered in the parelm algorithm.
      74             :     /// \return The data variables that appear in the condition, action or time of the summands
      75          15 :     std::set<data::variable> transition_variables()
      76             :     {
      77          15 :       std::set<data::variable> result;
      78             : 
      79          15 :       auto const& action_summands = m_spec.process().action_summands();
      80          41 :       for (auto i = action_summands.begin(); i != action_summands.end(); ++i)
      81             :       {
      82          26 :         detail::collect_transition_variables(*i, result);
      83             :       }
      84             : 
      85          15 :       auto const& deadlock_summands = m_spec.process().deadlock_summands();
      86          18 :       for (auto i = deadlock_summands.begin(); i != deadlock_summands.end(); ++i)
      87             :       {
      88           3 :         detail::collect_transition_variables(*i, result);
      89             :       }
      90          15 :       return result;
      91           0 :     }
      92             : 
      93          15 :     void report_results(const std::set<data::variable>& to_be_removed) const
      94             :     {
      95          15 :       if (verbose())
      96             :       {
      97           0 :         std::clog << "parelm removed " << to_be_removed.size() << " process parameters: " <<std::endl;
      98           0 :         for (const data::variable& v: to_be_removed)
      99             :         {
     100           0 :           std::clog << v << ":" << v.sort() << std::endl;
     101             :         }
     102             :       }
     103          15 :     }
     104             : 
     105             :     /// \brief First version of parelm1
     106           8 :     void parelm1()
     107             :     {
     108             : #ifdef MCRL2_LPS_PARELM_DEBUG
     109             :       std::clog << "--- parelm 1 ---" << std::endl;
     110             : #endif
     111           8 :       const data::variable_list& pars = m_spec.process().process_parameters();
     112           8 :       std::set<data::variable> process_parameters(pars.begin(),pars.end());
     113             : 
     114             :       // significant variables may not be removed by parelm
     115           8 :       std::set<data::variable> significant_variables = transition_variables();
     116             : 
     117             : #ifdef MCRL2_LPS_PARELM_DEBUG
     118             :       std::clog << "initial significant variables: ";
     119             :       for (auto i = significant_variables.begin(); i != significant_variables.end(); ++i)
     120             :       {
     121             :         std::clog << *i << " ";
     122             :       }
     123             :       std::clog << std::endl;
     124             : #endif
     125             : 
     126             :       // recursively extend the set of significant variables
     127           8 :       std::set<data::variable> todo = significant_variables;
     128          98 :       while (!todo.empty())
     129             :       {
     130          45 :         data::variable x = *todo.begin();
     131          45 :         todo.erase(todo.begin());
     132             : 
     133         370 :         for (auto i = m_spec.process().action_summands().begin(); i != m_spec.process().action_summands().end(); ++i)
     134             :         {
     135         325 :           const data::assignment_list& assignments = i->assignments();
     136        1439 :           auto j = std::find_if(assignments.begin(), assignments.end(), [&](const data::assignment& a) { return a.lhs() == x; });
     137         325 :           if (j != assignments.end())
     138             :           {
     139          52 :             std::set<data::variable> vars;
     140          52 :             data::find_all_variables(j->rhs(), std::inserter(vars, vars.end()));
     141          52 :             std::set<data::variable> new_variables = utilities::detail::set_difference(vars, significant_variables);
     142          52 :             todo.insert(new_variables.begin(), new_variables.end());
     143          52 :             significant_variables.insert(new_variables.begin(), new_variables.end());
     144             : #ifdef MCRL2_LPS_PARELM_DEBUG
     145             :             for (auto k = new_variables.begin(); k != new_variables.end(); ++k)
     146             :             {
     147             :               std::clog << "found dependency " << x << " -> " << *k << std::endl;
     148             :             }
     149             : #endif
     150          52 :           }
     151             :         }
     152             :       }
     153           8 :       std::set<data::variable> to_be_removed = utilities::detail::set_difference(process_parameters, significant_variables);
     154             : #ifdef MCRL2_LPS_PARELM_DEBUG
     155             :       std::clog << "to be removed: " << data::pp(data::variable_list(to_be_removed.begin(), to_be_removed.end())) << std::endl;
     156             : #endif
     157           8 :       report_results(to_be_removed);
     158           8 :       lps::remove_parameters(m_spec, to_be_removed);
     159           8 :       assert(check_well_typedness(m_spec));
     160           8 :     }
     161             : 
     162             :     /// \brief Second version of parelm that builds a dependency graph
     163           7 :     void parelm2()
     164             :     {
     165             : #ifdef MCRL2_LPS_PARELM_DEBUG
     166             :       std::clog << "--- parelm 2 ---" << std::endl;
     167             : #endif
     168           7 :       const data::variable_list& pars = m_spec.process().process_parameters();
     169           7 :       std::set<data::variable> process_parameters(pars.begin(),pars.end());
     170             : 
     171             :       // create a mapping m from process parameters to integers
     172           7 :       std::map<data::variable, std::size_t> m;
     173           7 :       int index = 0;
     174          33 :       for (const data::variable& process_parameter: process_parameters)
     175             :       {
     176             : #ifdef MCRL2_LPS_PARELM_DEBUG
     177             :         std::clog << "vertex " << index << " = " << data::pp(*i) << std::endl;
     178             : #endif
     179          26 :         m[process_parameter] = index++;
     180             :       }
     181             : 
     182             :       // compute the initial set v of significant variables
     183           7 :       std::set<data::variable> significant_variables = transition_variables();
     184           7 :       std::vector<std::size_t> v;
     185          18 :       for (const data::variable& significant_variable: significant_variables)
     186             :       {
     187          11 :         v.push_back(m[significant_variable]);
     188             :       }
     189             : 
     190             :       // compute the dependency graph G
     191             :       typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS> graph;
     192           7 :       graph G(process_parameters.size());
     193          15 :       for (auto i = m_spec.process().action_summands().begin(); i != m_spec.process().action_summands().end(); ++i)
     194             :       {
     195          35 :         for (const data::assignment& a: i->assignments())
     196             :         {
     197          19 :           std::size_t j0 = m[a.lhs()];
     198          19 :           std::set<data::variable> vars;
     199          19 :           data::find_all_variables(a.rhs(), std::inserter(vars, vars.end()));
     200          37 :           for (const data::variable& var: vars)
     201             :           {
     202          18 :             std::size_t k0 = m[var];
     203             : #ifdef MCRL2_LPS_PARELM_DEBUG
     204             :             std::clog << "edge " << j0 << " -> " << k0 << std::endl;
     205             : #endif
     206          18 :             boost::add_edge(j0, k0, G);
     207             :           }
     208             :         }
     209             :       }
     210             : 
     211             : #ifdef MCRL2_LPS_PARELM_DEBUG
     212             :       std::clog << "initial significant variables: ";
     213             :       for (auto k = v.begin(); k != v.end(); ++k)
     214             :       {
     215             :         std::clog << *k << " ";
     216             :       }
     217             :       std::clog << std::endl;
     218             : #endif
     219             : 
     220             :       // compute the reachable nodes (i.e. the significant parameters)
     221           7 :       std::vector<std::size_t> r1 = mcrl2::utilities::reachable_nodes(G, v.begin(), v.end());
     222             : #ifdef MCRL2_LPS_PARELM_DEBUG
     223             :       std::clog << "reachable nodes: ";
     224             :       for (auto k = r1.begin(); k != r1.end(); ++k)
     225             :       {
     226             :         std::clog << *k << " ";
     227             :       }
     228             :       std::clog << std::endl;
     229             : #endif
     230           7 :       std::set<std::size_t> r2(r1.begin(), r1.end());
     231           7 :       std::set<data::variable> to_be_removed;
     232          33 :       for (const data::variable& process_parameter: process_parameters)
     233             :       {
     234          26 :         if (r2.find(m[process_parameter]) == r2.end())
     235             :         {
     236          12 :           to_be_removed.insert(process_parameter);
     237             :         }
     238             :       }
     239             : #ifdef MCRL2_LPS_PARELM_DEBUG
     240             :       std::clog << "to be removed: " << data::pp(data::variable_list(to_be_removed.begin(), to_be_removed.end())) << std::endl;
     241             : #endif
     242           7 :       report_results(to_be_removed);
     243           7 :       lps::remove_parameters(m_spec, to_be_removed);
     244           7 :       assert(check_well_typedness(m_spec));
     245           7 :     }
     246             : 
     247             :   public:
     248             : 
     249             :     /// \brief Constructor
     250          15 :     parelm_algorithm(Specification& spec )
     251          15 :       : lps::detail::lps_algorithm<Specification>(spec)
     252          15 :     {}
     253             : 
     254             :     /// \brief Runs the parelm algorithm
     255          15 :     void run(bool variant1 = true)
     256             :     {
     257          15 :       if (variant1)
     258             :       {
     259           8 :         parelm1();
     260             :       }
     261             :       else
     262             :       {
     263           7 :         parelm2();
     264             :       }
     265          15 :     }
     266             : };
     267             : 
     268             : /// \brief Removes unused parameters from a linear process specification.
     269             : /// \param spec A linear process specification
     270             : /// \param variant1 If true the default variant of parelm is used, otherwise an
     271             : ///        alternative implementation is chosen.
     272             : template <typename Specification>
     273          15 : void parelm(Specification& spec, bool variant1 = true)
     274             : {
     275          15 :   parelm_algorithm<Specification> algorithm(spec);
     276          15 :   algorithm.run(variant1);
     277          15 : }
     278             : 
     279             : } // namespace lps
     280             : 
     281             : } // namespace mcrl2
     282             : 
     283             : #endif // MCRL2_LPS_PARELM_H

Generated by: LCOV version 1.14