LCOV - code coverage report
Current view: top level - pbes/include/mcrl2/pbes - eqelm.h (source / functions) Hit Total Coverage
Test: mcrl2_coverage.info.cleaned Lines: 105 133 78.9 %
Date: 2024-04-26 03:18:02 Functions: 8 11 72.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/eqelm.h
       8             : /// \brief The eqelm algorithm.
       9             : 
      10             : #ifndef MCRL2_PBES_EQELM_H
      11             : #define MCRL2_PBES_EQELM_H
      12             : 
      13             : #include "mcrl2/pbes/algorithms.h"
      14             : #include "mcrl2/pbes/pbes_rewriter_type.h"
      15             : #include "mcrl2/pbes/print.h"
      16             : #include "mcrl2/pbes/replace.h"
      17             : #include "mcrl2/pbes/rewriters/enumerate_quantifiers_rewriter.h"
      18             : 
      19             : namespace mcrl2
      20             : {
      21             : 
      22             : namespace pbes_system
      23             : {
      24             : 
      25             : /// \brief Algorithm class for the eqelm algorithm
      26             : template <typename Term, typename DataRewriter, typename PbesRewriter>
      27             : class pbes_eqelm_algorithm
      28             : {
      29             :   protected:
      30             :     typedef std::set<data::variable> equivalence_class;
      31             : 
      32             :     /// \brief Compares data expressions for equality.
      33             :     const DataRewriter& m_data_rewriter;
      34             : 
      35             :     /// \brief Compares data expressions for equality.
      36             :     const PbesRewriter& m_pbes_rewriter;
      37             : 
      38             :     /// \brief The vertices of the grapth, i.e. the equivalence relations.
      39             :     /// It stores the equivalence sets for each propositional variable, for example
      40             :     /// X -> [ {x1, x3}, {x2, x4} ]. Equivalence sets of size 1 are not stored.
      41             :     std::map<core::identifier_string, std::vector<equivalence_class> > m_vertices;
      42             : 
      43             :     /// \brief The edges of the graph.
      44             :     /// It is a mapping from X to iocc(X).
      45             :     std::map<core::identifier_string, std::set<propositional_variable_instantiation> > m_edges;
      46             : 
      47             :     /// \brief The parameters of the propositional variable declarations.
      48             :     /// These are stored inside a vector, for efficiency reasons.
      49             :     std::map<core::identifier_string, std::vector<data::variable> > m_parameters;
      50             : 
      51             :     /// \brief Used for determining if a vertex has been visited before.
      52             :     std::map<core::identifier_string, bool> m_discovered;
      53             : 
      54             :     /// \brief Puts all parameters of the same sort in the same equivalence set.
      55           4 :     std::vector<equivalence_class> compute_equivalence_sets(const propositional_variable& X) const
      56             :     {
      57           4 :       std::map< data::sort_expression, equivalence_class> m;
      58          15 :       for (const auto & i : X.parameters())
      59             :       {
      60           7 :         m[i.sort()].insert(i);
      61             :       }
      62           4 :       std::vector<equivalence_class> result;
      63           8 :       for (auto & i : m)
      64             :       {
      65           4 :         if (i.second.size() > 1)
      66             :         {
      67           3 :           result.push_back(i.second);
      68             :         }
      69             :       }
      70           8 :       return result;
      71           4 :     }
      72             : 
      73             :     /// \brief Prints the vertices of the dependency graph.
      74           0 :     std::string print_vertices() const
      75             :     {
      76           0 :       std::ostringstream out;
      77           0 :       for (auto i = m_vertices.begin(); i != m_vertices.end(); ++i)
      78             :       {
      79           0 :         out << i->first << " -> [ ";
      80           0 :         const std::vector<equivalence_class>& v = i->second;
      81           0 :         for (auto j = v.begin(); j != v.end(); ++j)
      82             :         {
      83           0 :           if (j != v.begin())
      84             :           {
      85           0 :             out << ", ";
      86             :           }
      87           0 :           out << core::detail::print_set(*j);
      88             :         }
      89           0 :         out << " ]" << std::endl;
      90             :       }
      91           0 :       return out.str();
      92           0 :     }
      93             : 
      94             :     /// \brief Prints the edges of the dependency graph.
      95           0 :     std::string print_edges() const
      96             :     {
      97           0 :       std::ostringstream out;
      98           0 :       for (auto i = m_edges.begin(); i != m_edges.end(); ++i)
      99             :       {
     100           0 :         out << i->first << " -> " << core::detail::print_set(i->second) << std::endl;
     101             :       }
     102           0 :       return out.str();
     103           0 :     }
     104             : 
     105             :     /// \brief Prints the equivalence classes
     106           0 :     std::string print_equivalence_classes() const
     107             :     {
     108           0 :       std::ostringstream out;
     109           0 :       for (auto i = m_vertices.begin(); i != m_vertices.end(); ++i)
     110             :       {
     111           0 :         out << "  vertex " << i->first << ": ";
     112           0 :         for (auto j = i->second.begin(); j != i->second.end(); ++j)
     113             :         {
     114           0 :           out << core::detail::print_set(*j) << " ";
     115             :         }
     116           0 :         out << std::endl;
     117             :       }
     118           0 :       return out.str();
     119           0 :     }
     120             : 
     121             :     /// \brief Prints the todo list
     122             :     void log_todo_list(const std::set<core::identifier_string>& todo, const std::string& msg = "") const
     123             :     {
     124             :       mCRL2log(log::debug) << msg;
     125             :       mCRL2log(log::debug) << core::detail::print_set(todo) << "\n";
     126             :     }
     127             : 
     128             :     /// \brief Returns true if the vertex X should propagate its values to Y
     129           9 :     bool evaluate_guard(const core::identifier_string& /* X */, const propositional_variable_instantiation& /* Y */)
     130             :     {
     131           9 :       return true;
     132             :     }
     133             : 
     134             :     /// \brief Returns the index of the element x in the sequence v
     135             :     template <typename VariableContainer>
     136          13 :     std::size_t index_of(const data::variable& x, const VariableContainer& v)
     137             :     {
     138          13 :       return static_cast<std::size_t>(std::find(v.begin(), v.end(), x) - v.begin());
     139             :     }
     140             : 
     141             :     /// \brief Propagate the equivalence relations given by the substitution vX over the edge Ye.
     142             :     template <typename Substitution>
     143           9 :     void update_equivalence_classes(const propositional_variable_instantiation& Ye,
     144             :                                     const Substitution& vX,
     145             :                                     std::set<core::identifier_string>& todo
     146             :                                    )
     147             :     {
     148           9 :       const core::identifier_string& Y = Ye.name();
     149           9 :       std::vector<data::data_expression> e(Ye.parameters().begin(), Ye.parameters().end());
     150             : 
     151           9 :       std::vector<equivalence_class>& cY = m_vertices[Y];
     152           9 :       std::vector<equivalence_class> cY1;
     153          15 :       for (auto & equiv : cY)
     154             :       {
     155           6 :         std::map<data::data_expression, equivalence_class> w;
     156          18 :         for (const auto & k : equiv)
     157             :         {
     158          12 :           std::size_t p = index_of(k, m_parameters[Y]);
     159          12 :           pbes_system::data_rewriter<DataRewriter> rewr(m_data_rewriter);
     160          12 :           pbes_system::pbes_expression e_p = rewr(e[p], vX);
     161          12 :           w[atermpp::down_cast<const data::data_expression>(e_p)].insert(k);
     162             :         }
     163          14 :         for (auto & i : w)
     164             :         {
     165           8 :           if (i.second.size() > 1)
     166             :           {
     167           4 :             cY1.push_back(i.second);
     168             :           }
     169             :         }
     170             :       }
     171           9 :       if (cY != cY1)
     172             :       {
     173           2 :         todo.insert(Y);
     174           2 :         m_discovered[Y] = true;
     175           2 :         cY = cY1;
     176             :       }
     177           7 :       else if (!m_discovered[Y])
     178             :       {
     179           1 :         todo.insert(Y);
     180           1 :         m_discovered[Y] = true;
     181             :       }
     182           9 :     }
     183             : 
     184             :     /// \brief Computes a substitution that corresponds to the equivalence relations in X
     185          13 :     data::mutable_map_substitution<> compute_substitution(const core::identifier_string& X)
     186             :     {
     187          13 :       data::mutable_map_substitution<> result;
     188          13 :       const std::vector<equivalence_class>& cX = m_vertices[X];
     189          19 :       for (const auto & s : cX)
     190             :       {
     191          12 :         for (auto j = ++s.begin(); j != s.end(); ++j)
     192             :         {
     193           6 :           result[*j] = *s.begin();
     194             :         }
     195             :       }
     196          13 :       return result;
     197           0 :     }
     198             : 
     199             :     /// \brief Chooses one parameter for every equivalence class, and
     200             :     /// removes the others. All occurrences of the removed parameters
     201             :     /// are replaced by the chosen parameter.
     202             :     inline
     203           3 :     void apply_equivalence_relations(pbes& p)
     204             :     {
     205             :       // first apply the substitutions to the equations
     206           7 :       for (pbes_equation& eqn: p.equations())
     207             :       {
     208           4 :         core::identifier_string X = eqn.variable().name();
     209           4 :         data::mutable_map_substitution<> sigma = compute_substitution(X);
     210             : 
     211           4 :         if (!sigma.empty())
     212             :         {
     213           1 :           eqn.formula() = pbes_system::replace_variables_capture_avoiding(eqn.formula(), sigma);
     214             :         }
     215             :       }
     216             : 
     217             :       // then remove parameters
     218           3 :       std::map<core::identifier_string, std::vector<std::size_t> > to_be_removed;
     219           7 :       for (pbes_equation& eqn: p.equations())
     220             :       {
     221           4 :         core::identifier_string X = eqn.variable().name();
     222           4 :         const std::vector<equivalence_class>& eq = m_vertices[X];
     223           5 :         for (const auto & j : eq)
     224             :         {
     225           2 :           for (auto k = ++j.begin(); k != j.end(); ++k)
     226             :           {
     227           1 :             to_be_removed[X].push_back(index_of(*k, m_parameters[X]));
     228             :           }
     229           1 :           std::sort(to_be_removed[X].begin(), to_be_removed[X].end());
     230             :         }
     231             :       }
     232             : 
     233           3 :       pbes_system::algorithms::remove_parameters(p, to_be_removed);
     234           3 :     }
     235             : 
     236             :   public:
     237             :     /// \brief Constructor.
     238             :     /// \param datar A data rewriter
     239             :     /// \param pbesr A PBES rewriter
     240           3 :     pbes_eqelm_algorithm(const DataRewriter& datar, const PbesRewriter& pbesr)
     241           3 :       : m_data_rewriter(datar),
     242           3 :         m_pbes_rewriter(pbesr)
     243           3 :     {}
     244             : 
     245             :     /// \brief Runs the eqelm algorithm
     246             :     /// \param p A pbes
     247             :     /// \param ignore_initial_state If true, the initial state is ignored.
     248           3 :     void run(pbes& p, bool ignore_initial_state = false)
     249             :     {
     250           3 :       m_vertices.clear();
     251           3 :       m_edges.clear();
     252           3 :       std::set<core::identifier_string> todo;
     253             : 
     254             :       // compute the vertices and edges of the graph
     255           7 :       for (pbes_equation& eqn: p.equations())
     256             :       {
     257           4 :         core::identifier_string name = eqn.variable().name();
     258           4 :         m_edges[name] = find_propositional_variable_instantiations(eqn.formula());
     259           4 :         m_vertices[name] = compute_equivalence_sets(eqn.variable());
     260           4 :         const data::variable_list& param = eqn.variable().parameters();
     261           4 :         m_parameters[name] = std::vector<data::variable>(param.begin(), param.end());
     262           4 :         todo.insert(name);
     263           4 :         m_discovered[name] = ignore_initial_state;
     264             :       }
     265             : 
     266           3 :       if (!ignore_initial_state)
     267             :       {
     268           3 :         todo.clear();
     269           3 :         propositional_variable_instantiation kappa = p.initial_state();
     270           3 :         const core::identifier_string& X = kappa.name();
     271           3 :         data::mutable_map_substitution<> vX = compute_substitution(X);
     272             : 
     273             :         // propagate the equivalence relations in X over the edge kappa
     274           3 :         if (evaluate_guard(X, kappa))
     275             :         {
     276           3 :           todo.insert(X);
     277           3 :           m_discovered[X] = true;
     278           3 :           update_equivalence_classes(kappa, vX, todo);
     279           3 :           mCRL2log(log::debug) << "updated equivalence classes using initial state " << kappa << "\n" << print_equivalence_classes();
     280             :         }
     281           3 :       }
     282             : 
     283           3 :       mCRL2log(log::verbose) << "--- vertices ---\n" << print_vertices();
     284           3 :       mCRL2log(log::verbose) << "\n--- edges ---\n" << print_edges();
     285           3 :       mCRL2log(log::debug) << "computed initial equivalence classes\n" << print_equivalence_classes();
     286             : 
     287             :       // propagate constraints over the edges until the todo list is empty
     288          15 :       while (!todo.empty())
     289             :       {
     290           6 :         mCRL2log(log::debug) << "todo list = " << core::detail::print_set(todo) << "\n";
     291           6 :         mCRL2log(log::verbose) << "--- vertices ---\n" << print_vertices();
     292             : 
     293           6 :         core::identifier_string X = *todo.begin();
     294           6 :         todo.erase(X);
     295           6 :         mCRL2log(log::debug) << "choose todo element " << X << "\n";
     296             : 
     297             :         // create a substitution function that corresponds to cX
     298           6 :         data::mutable_map_substitution<> vX = compute_substitution(X);
     299           6 :         const std::set<propositional_variable_instantiation>& edges = m_edges[X];
     300          12 :         for (const auto& Ye : edges)
     301             :         {
     302             :           // propagate the equivalence relations in X over the edge Ye
     303           6 :           if (evaluate_guard(X, Ye))
     304             :           {
     305           6 :             update_equivalence_classes(Ye, vX, todo);
     306           6 :             mCRL2log(log::debug) << "updated equivalence classes using edge " << Ye << "\n" << print_equivalence_classes();
     307             :           }
     308             :         }
     309             :       }
     310           3 :       apply_equivalence_relations(p);
     311           3 :       mCRL2log(log::verbose) << "\n--- result ---\n" << print_vertices();
     312           3 :     }
     313             : };
     314             : 
     315             : /// \brief Apply the eqelm algorithm
     316             : /// \param p A PBES to which the algorithm is applied.
     317             : /// \param rewrite_strategy A data rewrite strategy.
     318             : /// \param rewriter_type A PBES rewriter type.
     319             : /// \param ignore_initial_state If true, the initial state will be ignored.
     320             : inline
     321             : void eqelm(pbes& p,
     322             :            data::rewrite_strategy rewrite_strategy,
     323             :            pbes_rewriter_type rewriter_type,
     324             :            bool ignore_initial_state = false
     325             :           )
     326             : {
     327             :   // data rewriter
     328             :   data::rewriter datar(p.data(), rewrite_strategy);
     329             : 
     330             :   // pbes rewriter
     331             :   switch (rewriter_type)
     332             :   {
     333             :     case simplify:
     334             :     {
     335             :       typedef simplify_data_rewriter<data::rewriter> pbes_rewriter;
     336             :       pbes_rewriter pbesr(datar);
     337             :       pbes_eqelm_algorithm<pbes_expression, data::rewriter, pbes_rewriter> algorithm(datar, pbesr);
     338             :       algorithm.run(p, ignore_initial_state);
     339             :       break;
     340             :     }
     341             :     case quantifier_all:
     342             :     case quantifier_finite:
     343             :     {
     344             :       bool enumerate_infinite_sorts = (rewriter_type == quantifier_all);
     345             :       enumerate_quantifiers_rewriter pbesr(datar, p.data(), enumerate_infinite_sorts);
     346             :       pbes_eqelm_algorithm<pbes_expression, data::rewriter, enumerate_quantifiers_rewriter> algorithm(datar, pbesr);
     347             :       algorithm.run(p, ignore_initial_state);
     348             :       break;
     349             :     }
     350             :     default:
     351             :     { }
     352             :   }
     353             : }
     354             : 
     355             : } // namespace pbes_system
     356             : 
     357             : } // namespace mcrl2
     358             : 
     359             : #endif // MCRL2_PBES_EQELM_H

Generated by: LCOV version 1.14