LCOV - code coverage report
Current view: top level - pbes/include/mcrl2/pbes/detail - stategraph_algorithm.h (source / functions) Hit Total Coverage
Test: mcrl2_coverage.info.cleaned Lines: 301 387 77.8 %
Date: 2024-04-21 03:44:01 Functions: 34 44 77.3 %
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/pbes/detail/stategraph_algorithm.h
      10             : /// \brief add your file description here.
      11             : 
      12             : #ifndef MCRL2_PBES_DETAIL_STATEGRAPH_ALGORITHM_H
      13             : #define MCRL2_PBES_DETAIL_STATEGRAPH_ALGORITHM_H
      14             : 
      15             : #include "mcrl2/pbes/detail/stategraph_graph.h"
      16             : #include "mcrl2/pbes/tools/pbesstategraph_options.h"
      17             : #include "mcrl2/utilities/sequence.h"
      18             : 
      19             : namespace mcrl2 {
      20             : 
      21             : namespace pbes_system {
      22             : 
      23             : namespace detail {
      24             : 
      25             : inline
      26           0 : std::string print_index(std::size_t index)
      27             : {
      28           0 :   std::ostringstream out;
      29           0 :   if (index == data::undefined_index())
      30             :   {
      31           0 :     out << "undefined";
      32             :   }
      33             :   else
      34             :   {
      35           0 :     out << index;
      36             :   }
      37           0 :   return out.str();
      38           0 : }
      39             : 
      40             : /// \brief Algorithm class for the computation of the local and global control flow graphs
      41             : class stategraph_algorithm
      42             : {
      43             :   public:
      44             :     // simplify and rewrite the guards of the pbes p
      45          27 :     void simplify(stategraph_pbes& p) const
      46             :     {
      47          89 :       for (stategraph_equation& equation: p.equations())
      48             :       {
      49         170 :         for (predicate_variable& predvar: equation.predicate_variables())
      50             :         {
      51         108 :           predvar.simplify_guard();
      52             :         }
      53             :       }
      54          27 :     }
      55             : 
      56             :   protected:
      57             :     // the pbes that is considered
      58             :     stategraph_pbes m_pbes;
      59             : 
      60             :     // a data rewriter
      61             :     data::rewriter m_datar;
      62             : 
      63             :     // determines how local control flow parameters are computed
      64             :     //
      65             :     // Keuze uit twee alternatieven voor de berekening van lokale CFPs.
      66             :     // <default>
      67             :     //  * Een parameter d^X[n] is een LCFP indien voor alle i waarvoor geldt pred(phi_X,i) = X, danwel:
      68             :     //          a. source(X,i,n) and target(X,i,n) zijn beide defined, of
      69             :     //          b. copy(X,i,n) is defined en gelijk aan n.
      70             :     //
      71             :     // <alternative>
      72             :     //  * Een parameter d^X[n] is een LCFP indien voor alle i waarvoor geldt pred(phi_X,i) = X, danwel:
      73             :     //          a. copy(X,i,n) is undefined en source(X,i,n) and target(X,i,n) zijn beide defined, of
      74             :     //          b. copy(X,i,n) is defined (en gelijk aan n) en source(X,i,n) en target(X,i,n) zijn beide undefined.
      75             :     //
      76             :     // De tweede definieert in feite een exclusive or, terwijl de eerste een standaard or is.
      77             :     bool m_use_alternative_lcfp_criterion;
      78             : 
      79             :     // determines how global control flow parameters are related
      80             :     //
      81             :     // Keuze uit twee alternatieven voor het relateren van CFPs.
      82             :     // <default>
      83             :     //  * Parameters d^X[n] and d^Y[m] zijn gerelateerd als danwel:
      84             :     //         a. er is een i z.d.d. copy(X, i, n) = m, of
      85             :     //         b. er is een i z.d.d. copy(Y, i, m) = n
      86             :     //
      87             :     // <alternative>
      88             :     //  * Parameters d^X[n] and d^Y[m] zijn gerelateerd als danwel:
      89             :     //         a. er is een i z.d.d. copy(X, i, n) = m, en target(X, i, m) is ongedefinieerd, of
      90             :     //         b. er is een i z.d.d. copy(Y, i, m) = n en target(Y, i, n) is ongedefinieerd.
      91             :     // Hier zit het verschil er dus in dat we, in het tweede geval, parameters alleen relateren als er een copy is
      92             :     // van de een naar de ander EN de target in dat geval ongedefinieerd is.
      93             :     bool m_use_alternative_gcfp_relation;
      94             : 
      95             :     // determines how global control flow parameters are selected
      96             :     //
      97             :     // Keuze voor de selectie van globale CFPs (of globale consistentie eisen).
      98             :     // <default>
      99             :     //  * Een set van CFPs is consistent als voor elke d^X[n], en voor alle Y in bnd(E)\{X} (dus in alle andere vergelijkingen), voor alle i waarvoor geldt pred(phi_Y, i) = X, danwel:
     100             :     //         a. target(Y, i, n) is gedefinieerd, of
     101             :     //         b. copy(Y, i, m) = n voor een of andere globale CFP d^Y[m]
     102             :     // Deze eis is in principe voldoende om globale CFPs te identificeren. Als we echter een strikte scheiding tussen control flow parameters en data parameters willen bewerkstelligen, dan moet hier optioneel de volgende eis aan toegevoegd worden:
     103             :     //
     104             :     // <alternative>
     105             :     //  * Een set van CFPs is consistent als de voorgaande eisen gelden, en bovendien voor elke d^X[n] geldt dat voor alle i waarvoor pred(phi_X, i) = Y != X, als d^X[n] affects data(phi_X, i)[m], dan is d^Y[m] een globale control flow parameter.
     106             :     // Waar de eerste gemarkeerd is als "detect conflicts for parameters of Y in equations of the form X(d) = ... Y(e)"
     107             :     // en de tweede als "detect conflicts for parameters of X in equations of the form X(d) = ... Y(e)".
     108             :     bool m_use_alternative_gcfp_consistency;
     109             : 
     110             :     // TODO: remove the three booleans above, since they are also present in m_options
     111             :     pbesstategraph_options m_options;
     112             : 
     113             :     // the local control flow parameters
     114             :     std::map<core::identifier_string, std::vector<bool> > m_is_LCFP;
     115             : 
     116             :     // the global control flow parameters
     117             :     std::map<core::identifier_string, std::vector<bool> > m_is_GCFP;
     118             : 
     119             :     // the vertices of the control flow graph
     120             :     GCFP_graph m_GCFP_graph;
     121             : 
     122             :     // the connected components in the control flow graph; a component contains the indices of vertices in the graph m_GCFP_graph
     123             :     std::vector<std::set<std::size_t> > m_connected_components;
     124             : 
     125             :     // the possible values of the connected components in the control flow graph
     126             :     std::vector<std::set<data::data_expression> > m_connected_components_values;
     127             : 
     128             :     // the local control flow graph(s)
     129             :     std::vector<local_control_flow_graph> m_local_control_flow_graphs;
     130             : 
     131             :     // for readability
     132           6 :     std::set<data::variable> FV(const data::data_expression& x) const
     133             :     {
     134           6 :       return data::find_free_variables(x);
     135             :     }
     136             : 
     137         142 :     void start_timer(const std::string& msg) const
     138             :     {
     139         142 :       if (m_options.timing_enabled())
     140             :       {
     141           0 :         m_options.timer->start(msg);
     142             :       }
     143         142 :     }
     144             : 
     145         142 :     void finish_timer(const std::string& msg) const
     146             :     {
     147         142 :       if (m_options.timing_enabled())
     148             :       {
     149           0 :         m_options.timer->finish(msg);
     150             :       }
     151         142 :     }
     152             : 
     153             :   public:
     154          27 :     void compute_control_flow_parameters()
     155             :     {
     156          27 :       start_timer("compute_local_control_flow_parameters");
     157          27 :       compute_local_control_flow_parameters();
     158          27 :       finish_timer("compute_local_control_flow_parameters");
     159             : 
     160          27 :       start_timer("compute_global_control_flow_parameters");
     161          27 :       compute_global_control_flow_parameters();
     162          27 :       finish_timer("compute_global_control_flow_parameters");
     163             : 
     164          27 :       start_timer("compute_related_GCFP_parameters");
     165          27 :       compute_related_GCFP_parameters();
     166          27 :       finish_timer("compute_related_GCFP_parameters");
     167             : 
     168          27 :       start_timer("compute_connected_components");
     169          27 :       compute_connected_components();
     170          27 :       finish_timer("compute_connected_components");
     171          27 :     }
     172             : 
     173             :     template <typename T>
     174           0 :     std::string print_control_flow_parameters(const std::string& msg, T& is_CFP)
     175             :     {
     176           0 :       std::ostringstream out;
     177           0 :       out << msg << std::endl;
     178           0 :       for (const stategraph_equation& equation: m_pbes.equations())
     179             :       {
     180           0 :         auto const& X = equation.variable().name();
     181           0 :         auto const& d_X = equation.parameters();
     182           0 :         const std::vector<bool>& cf = is_CFP[X];
     183           0 :         for (std::size_t i = 0; i < cf.size(); ++i)
     184             :         {
     185           0 :           if (cf[i])
     186             :           {
     187           0 :             out << "(" << X << ", " << i << ", " << d_X[i] << ")" << std::endl;
     188             :           }
     189             :         }
     190             :       }
     191           0 :       return out.str();
     192           0 :     }
     193             : 
     194           0 :     std::string print_LCFP()
     195             :     {
     196           0 :       return print_control_flow_parameters("--- computed LCFP parameters (before removing components) ---", m_is_LCFP);
     197             :     }
     198             : 
     199           0 :     std::string print_GCFP()
     200             :     {
     201           0 :       return print_control_flow_parameters("--- computed GCFP parameters ---", m_is_GCFP);
     202             :     }
     203             : 
     204             :     // returns true if m is not a key in the map
     205             :     template <typename Map>
     206         592 :     bool is_undefined(const Map& m, const typename Map::key_type& key) const
     207             :     {
     208         592 :       return m.find(key) == m.end();
     209             :     }
     210             : 
     211             :     // returns true if the mapping m maps key to value
     212             :     template <typename Map>
     213          90 :     bool is_mapped_to(const Map& m, const typename Map::key_type& key, const typename Map::mapped_type& value) const
     214             :     {
     215          90 :       auto i = m.find(key);
     216          90 :       return i != m.end() && i->second == value;
     217             :     }
     218             : 
     219         243 :     bool maps_to_and_is_GFCP(const std::map<std::size_t, std::size_t>& m, std::size_t value, const core::identifier_string& X)
     220             :     {
     221         758 :       for (const auto& i: m)
     222             :       {
     223         541 :         if (i.second == value && m_is_GCFP[X][i.first])
     224             :         {
     225          26 :           return true;
     226             :         }
     227             :       }
     228         217 :       return false;
     229             :     }
     230             : 
     231          27 :     void compute_local_control_flow_parameters()
     232             :     {
     233          27 :       mCRL2log(log::debug) << "=== computing local control flow parameters ===" << std::endl;
     234             : 
     235          27 :       auto const& equations = m_pbes.equations();
     236             : 
     237             :       // initialize all control flow parameters to true
     238          89 :       for (const stategraph_equation& equation: equations)
     239             :       {
     240          62 :         auto const& X = equation.variable().name();
     241          62 :         auto const& d_X = equation.parameters();
     242          62 :         m_is_LCFP[X] = std::vector<bool>(d_X.size(), true);
     243             :       }
     244             : 
     245          89 :       for (const stategraph_equation& equation: equations)
     246             :       {
     247          62 :         auto const& X = equation.variable().name();
     248          62 :         auto const& d_X = equation.parameters();
     249          62 :         auto const& predvars = equation.predicate_variables();
     250         170 :         for (const predicate_variable& Ye: predvars)
     251             :         {
     252         108 :           if (Ye.name() == X)
     253             :           {
     254         164 :             for (std::size_t n = 0; n < d_X.size(); n++)
     255             :             {
     256         127 :               if (m_use_alternative_lcfp_criterion)
     257             :               {
     258             :                 // Een parameter d^X[n] is een LCFP indien voor alle i waarvoor geldt pred(phi_X,i) = X, danwel:
     259             :                 // 1. copy(X,i,n) is undefined en source(X,i,n) and target(X,i,n) zijn beide defined, of
     260             :                 // 2. copy(X,i,n) is defined en source(X,i,n) en target(X,i,n) zijn beide undefined.
     261           0 :                 if (Ye.copy().find(n) == Ye.copy().end())
     262             :                 {
     263             :                   // copy(X,i,n) is undefined
     264           0 :                   if (is_undefined(Ye.source(), n) || is_undefined(Ye.target(), n))
     265             :                   {
     266           0 :                     mCRL2log(log::debug) << "parameter " << print_cfp(X, n) << " is not an LCFP because of predicate variable " << Ye << " in equation " << X << " (copy and source/target undefined)" << std::endl;
     267           0 :                     m_is_LCFP[X][n] = false;
     268             :                   }
     269             :                 }
     270             :                 else
     271             :                 {
     272             :                   // copy(X,i,n) is defined
     273           0 :                   if (!is_undefined(Ye.source(), n) || !is_undefined(Ye.target(), n))
     274             :                   {
     275           0 :                     mCRL2log(log::debug) << "parameter " << print_cfp(X, n) << " is not an LCFP because of predicate variable " << Ye << " in equation " << X << " (copy defined and source/target defined)" << std::endl;
     276           0 :                     m_is_LCFP[X][n] = false;
     277             :                   }
     278             :                 }
     279             :               }
     280             :               else
     281             :               {
     282         127 :                 if ((is_undefined(Ye.source(), n) || is_undefined(Ye.target(), n)) && !is_mapped_to(Ye.copy(), n, n))
     283             :                 {
     284          43 :                   mCRL2log(log::debug) << "parameter " << print_cfp(X, n) << " is not an LCFP due to " << Ye << "(source and target undefined, and no copy to self)" << std::endl;
     285          43 :                   m_is_LCFP[X][n] = false;
     286             :                 }
     287             :               }
     288             :             }
     289             :           }
     290             :         }
     291             :       }
     292          27 :       mCRL2log(log::debug) << print_LCFP();
     293          27 :     }
     294             : 
     295             :     // Computes the global control flow parameters. The result is stored in m_is_GCFP.
     296          27 :     void compute_global_control_flow_parameters()
     297             :     {
     298          27 :       mCRL2log(log::debug) << "=== computing global control flow parameters ===" << std::endl;
     299             : 
     300          27 :       m_is_GCFP = m_is_LCFP;
     301             : 
     302          27 :       auto const& equations = m_pbes.equations();
     303             : 
     304             :       bool changed;
     305          49 :       do
     306             :       {
     307          49 :         changed = false;
     308             : 
     309             :         // Detect conflicts for parameters of Y in equations of the form X(d) = ... Y(e)
     310         164 :         for (const stategraph_equation& equation: equations)
     311             :         {
     312         115 :           auto const& X = equation.variable().name();
     313         115 :           auto const& predvars = equation.predicate_variables();
     314         316 :           for (const predicate_variable& Ye: predvars)
     315             :           {
     316         201 :             auto const& Y = Ye.name();
     317         201 :             if (Y != X)
     318             :             {
     319         134 :               auto const& eq_Y = *find_equation(m_pbes, Y);
     320         134 :               auto const& d_Y = eq_Y.parameters();
     321         506 :               for (std::size_t n = 0; n < d_Y.size(); n++)
     322             :               {
     323         372 :                 if (is_undefined(Ye.target(), n) && (!maps_to_and_is_GFCP(Ye.copy(), n, X)))
     324             :                 {
     325         217 :                   if (m_is_GCFP[Y][n])
     326             :                   {
     327          64 :                     m_is_GCFP[Y][n] = false;
     328          64 :                     changed = true;
     329          64 :                     mCRL2log(log::debug) << "parameter " << print_cfp(Y, n) << " is not a GCFP because of predicate variable " << Ye << " in equation " << X << std::endl;
     330             :                   }
     331             :                 }
     332             :               }
     333             :             }
     334             :           }
     335             :         }
     336             : 
     337             :         // Detect conflicts for parameters of X in equations of the form X(d) = ... Y(e)
     338          49 :         if (m_use_alternative_gcfp_consistency)
     339             :         {
     340           0 :           for (const stategraph_equation& equation: equations)
     341             :           {
     342           0 :             auto const& X = equation.variable().name();
     343           0 :             auto const& predvars = equation.predicate_variables();
     344           0 :             auto const& d_X = equation.parameters();
     345           0 :             std::size_t M = d_X.size();
     346             : 
     347           0 :             for (const predicate_variable& Ye : predvars)
     348             :             {
     349           0 :               auto const& Y = Ye.name();
     350           0 :               if (Y == X)
     351             :               {
     352           0 :                 continue;
     353             :               }
     354           0 :               auto const& e = Ye.parameters();
     355           0 :               std::size_t n = 0;
     356           0 :               for (auto ei = e.begin(); ei != e.end(); ++ei, ++n)
     357             :               {
     358           0 :                 std::set<data::variable> V = FV(*ei);
     359           0 :                 for (std::size_t m = 0; m < M; m++)
     360             :                 {
     361           0 :                   if (m_is_GCFP[X][m] && !m_is_GCFP[Y][n] && (V.find(d_X[m]) != V.end()))
     362             :                   {
     363           0 :                     m_is_GCFP[X][m] = false;
     364           0 :                     changed = true;
     365           0 :                     mCRL2log(log::debug) << "parameter " << print_cfp(X, m) << " is not a GCFP because of predicate variable " << Ye << " in equation " << X << std::endl;
     366             :                   }
     367             :                 }
     368           0 :               }
     369             :             }
     370             :           }
     371             :         }
     372             :       }
     373             :       while (changed);
     374             : 
     375          27 :       mCRL2log(log::debug) << print_GCFP();
     376          27 :     }
     377             : 
     378             :     bool is_LCFP_parameter(const core::identifier_string& X, std::size_t i) const
     379             :     {
     380             :       auto j = m_is_LCFP.find(X);
     381             :       assert(j != m_is_LCFP.end());
     382             :       const std::vector<bool>& cf = j->second;
     383             :       assert(i < cf.size());
     384             :       return cf[i];
     385             :     }
     386             : 
     387         409 :     bool is_GCFP_parameter(const core::identifier_string& X, std::size_t i) const
     388             :     {
     389         409 :       auto j = m_is_GCFP.find(X);
     390         409 :       assert(j != m_is_GCFP.end());
     391         409 :       const std::vector<bool>& cf = j->second;
     392         409 :       assert(i < cf.size());
     393         818 :       return cf[i];
     394             :     }
     395             : 
     396           0 :     bool is_global_control_flow_parameter(const core::identifier_string& X, std::size_t i) const
     397             :     {
     398             :       using utilities::detail::contains;
     399           0 :       auto const& eq_X = *find_equation(m_pbes, X);
     400           0 :       const std::vector<std::size_t>& I = eq_X.control_flow_parameter_indices();
     401           0 :       return contains(I, i);
     402             :     }
     403             : 
     404             :     // relate (X, n) and (Y, m) in the dependency graph
     405             :     // \pre: the equation of X has a lower rank than the equation of Y
     406          48 :     void relate_GCFP_vertices(const core::identifier_string& X, std::size_t n, const core::identifier_string& Y, std::size_t m)
     407             :     {
     408          48 :       GCFP_vertex& u = m_GCFP_graph.find_vertex(X, n);
     409          48 :       GCFP_vertex& v = m_GCFP_graph.find_vertex(Y, m);
     410          48 :       u.neighbors().insert(&v);
     411          48 :       v.neighbors().insert(&u);
     412          48 :     }
     413             : 
     414           0 :     std::string print_cfp(const core::identifier_string& X, std::size_t i) const
     415             :     {
     416           0 :       auto const& eq_X = *find_equation(m_pbes, X);
     417           0 :       auto const& d = eq_X.parameters()[i];
     418           0 :       std::ostringstream out;
     419           0 :       out << "(" << X << ", " << i << ", " << d << ")";
     420           0 :       return out.str();
     421           0 :     }
     422             : 
     423           0 :     std::string log_related_parameters(const core::identifier_string& X,
     424             :                                        std::size_t n,
     425             :                                        const core::identifier_string& Y,
     426             :                                        std::size_t m,
     427             :                                        const predicate_variable& Ye,
     428             :                                        const std::string& reason = ""
     429             :                                       ) const
     430             :     {
     431           0 :       std::ostringstream out;
     432           0 :       if (X != Y || n != m)
     433             :       {
     434           0 :         out << print_cfp(X, n) << " and " << print_cfp(Y, m) << " are related " << "because of recursion " << Ye << " in the equation for " << X << reason;
     435             :       }
     436           0 :       return out.str();
     437           0 :     }
     438             : 
     439             :     // Determines which control flow parameters are related. This is done by assigning neighbors to the
     440             :     // vertices in m_GCFP_graph.
     441          27 :     void compute_related_GCFP_parameters()
     442             :     {
     443          27 :       mCRL2log(log::debug) << "=== computing related global control flow parameters ===" << std::endl;
     444          27 :       const std::vector<stategraph_equation>& equations = m_pbes.equations();
     445             : 
     446             :       // step 1: create vertices in m_GCFP_graph
     447          89 :       for (const stategraph_equation& equation: equations)
     448             :       {
     449          62 :         auto const& X = equation.variable().name();
     450          62 :         auto const& d_X = equation.parameters();
     451         231 :         for (std::size_t n = 0; n < d_X.size(); n++)
     452             :         {
     453         169 :           if (is_GCFP_parameter(X, n))
     454             :           {
     455          65 :             m_GCFP_graph.add_vertex(GCFP_vertex(X, n, d_X[n]));
     456             :           }
     457             :         }
     458             :       }
     459             : 
     460             :       // step 2: create edges between related vertices in m_GCFP_graph
     461          89 :       for (const stategraph_equation& equation: equations)
     462             :       {
     463          62 :         auto const& X = equation.variable().name();
     464          62 :         auto const& predvars = equation.predicate_variables();
     465         170 :         for (const predicate_variable& Ye: predvars)
     466             :         {
     467         108 :           auto const& Y = Ye.name();
     468         108 :           auto const& copy = Ye.copy();
     469         293 :           for (const auto& j: copy)
     470             :           {
     471         185 :             std::size_t n = j.first;
     472         185 :             std::size_t m = j.second;
     473         185 :             if (is_GCFP_parameter(X, n) && is_GCFP_parameter(Y, m))
     474             :             {
     475          48 :               if (m_use_alternative_gcfp_relation)
     476             :               {
     477             :                 // Twee parameters zijn alleen gerelateerd als er een copy is van de een naar de ander,
     478             :                 // EN dat de target in dat geval ongedefinieerd is (dus we weten echt geen concrete waarde
     479             :                 // voor de parameter op dat punt).
     480           0 :                 if (is_undefined(Ye.target(), m))
     481             :                 {
     482           0 :                   mCRL2log(log::debug) << log_related_parameters(X, n, Y, m, Ye) << std::endl;
     483           0 :                   relate_GCFP_vertices(X, n, Y, m);
     484             :                 }
     485             :               }
     486             :               else
     487             :               {
     488          48 :                 mCRL2log(log::debug) << log_related_parameters(X, n, Y, m, Ye, " (target is undefined)") << std::endl;
     489          48 :                 relate_GCFP_vertices(X, n, Y, m);
     490             :               }
     491             :             }
     492             :           }
     493             :         }
     494             :       }
     495          27 :     }
     496             : 
     497             :     // a connected component is valid if it does not contain two nodes (X, n) and (Y, m) with X == Y
     498          86 :     bool is_valid_connected_component(const std::set<std::size_t>& component) const
     499             :     {
     500          86 :       std::set<core::identifier_string> V;
     501         243 :       for (std::size_t i: component)
     502             :       {
     503         159 :         auto const& X = m_GCFP_graph.vertex(i).name();
     504         159 :         if (V.find(X) != V.end())
     505             :         {
     506           2 :           return false;
     507             :         }
     508         157 :         V.insert(X);
     509             :       }
     510          84 :       return true;
     511          86 :     }
     512             : 
     513           0 :     std::string print_connected_component(const std::set<std::size_t>& component) const
     514             :     {
     515           0 :       std::ostringstream out;
     516           0 :       out << "{";
     517           0 :       for (auto i = component.begin(); i != component.end(); ++i)
     518             :       {
     519           0 :         if (i != component.begin())
     520             :         {
     521           0 :           out << ", ";
     522             :         }
     523           0 :         out << m_GCFP_graph.vertex(*i);
     524             :       }
     525           0 :       out << "}";
     526           0 :       if (!is_valid_connected_component(component))
     527             :       {
     528           0 :         out << " (invalid)";
     529             :       }
     530           0 :       return out.str();
     531           0 :     }
     532             : 
     533          54 :     void print_connected_components() const
     534             :     {
     535         123 :       for (const std::set<std::size_t>& component: m_connected_components)
     536             :       {
     537          69 :         mCRL2log(log::debug) << print_connected_component(component) << std::endl;
     538             :       }
     539          54 :     }
     540             : 
     541             :     // compute the connected component belonging to vertex i in m_GCFP_graph
     542          36 :     std::set<std::size_t> compute_connected_component(std::size_t i, std::vector<bool>& done) const
     543             :     {
     544             :       using utilities::detail::pick_element;
     545             : 
     546          36 :       std::set<std::size_t> todo;
     547          36 :       std::set<std::size_t> component;
     548             : 
     549          36 :       todo.insert(i);
     550         101 :       while (!todo.empty())
     551             :       {
     552          65 :         std::size_t u_index = pick_element(todo);
     553          65 :         const GCFP_vertex& u = m_GCFP_graph.vertex(u_index);
     554          65 :         done[u_index] = true;
     555          65 :         component.insert(u_index);
     556             : 
     557         140 :         for (GCFP_vertex* w: u.neighbors())
     558             :         {
     559          75 :           std::size_t w_index = m_GCFP_graph.index(*w);
     560          75 :           if (!done[w_index])
     561             :           {
     562          35 :             todo.insert(w_index);
     563             :           }
     564             :         }
     565             :       }
     566          72 :       return component;
     567          36 :     }
     568             : 
     569          27 :     void compute_connected_components()
     570             :     {
     571          27 :       mCRL2log(log::debug) << "=== computing connected components ===" << std::endl;
     572             : 
     573             :       // done[i] means that vertex i in m_GCFP_graph has been processed
     574          27 :       std::vector<bool> done(m_GCFP_graph.vertices().size(), false);
     575             : 
     576          92 :       for (std::size_t i = 0; i < done.size(); i++)
     577             :       {
     578          65 :         if (done[i])
     579             :         {
     580          29 :           continue;
     581             :         }
     582          36 :         std::set<std::size_t> component = compute_connected_component(i, done);
     583          36 :         m_connected_components.push_back(component);
     584          36 :       }
     585          27 :       mCRL2log(log::debug) << "--- computed connected components ---" << std::endl;
     586          27 :       print_connected_components();
     587          27 :     }
     588             : 
     589             :     // removes the connected components V for which !is_valid_connected_component(V)
     590          27 :     void remove_invalid_connected_components()
     591             :     {
     592          27 :       auto i = std::remove_if(m_connected_components.begin(), m_connected_components.end(),
     593          36 :                               [this](const std::set<std::size_t>& component){ return !is_valid_connected_component(component); });
     594          27 :       m_connected_components.erase(i, m_connected_components.end());
     595          27 :     }
     596             : 
     597             :     // Returns true if d_X[m] is not only copied.
     598             :     //
     599             :     // A CFP d_X[m] is not only copied if
     600             :     //    (1) for some i    : source(X, i, m) is defined
     601             :     // or (2) for some Y, i : pred(phi_Y , i) = X and target(Y, i, m) is defined
     602          37 :     bool is_not_only_copied(const core::identifier_string& X, std::size_t m) const
     603             :     {
     604             :       // check (1)
     605          37 :       auto const& eq_X = *find_equation(m_pbes, X);
     606          37 :       auto const& predvars = eq_X.predicate_variables();
     607          52 :       for (const predicate_variable& predvar: predvars)
     608             :       {
     609          40 :         if (!is_undefined(predvar.source(), m))
     610             :         {
     611          25 :           return true;
     612             :         }
     613             :       }
     614             : 
     615             :       // check (2)
     616          30 :       for (const stategraph_equation& equation: m_pbes.equations())
     617             :       {
     618          50 :         for (const auto& predvar: equation.predicate_variables())
     619             :         {
     620          32 :           if (predvar.name() == X && !is_undefined(predvar.target(), m))
     621             :           {
     622           8 :             return true;
     623             :           }
     624             :         }
     625             :       }
     626           4 :       return false;
     627             :     }
     628             : 
     629             :     // Returns true if all CFPs in component are 'only copied'
     630          34 :     bool has_only_copied_CFPs(const std::set<std::size_t>& component) const
     631             :     {
     632          38 :       for (std::size_t i: component)
     633             :       {
     634          37 :         const GCFP_vertex& u = m_GCFP_graph.vertex(i);
     635          37 :         const auto& X = u.name();
     636          37 :         auto m = u.index();
     637          37 :         if (is_not_only_copied(X, m))
     638             :         {
     639          33 :           return false;
     640             :         }
     641             :       }
     642           1 :       return true;
     643             :     }
     644             : 
     645             :     // Removes the connected components V that consist of CFPs that are only copied.
     646          27 :     void remove_only_copy_components()
     647             :     {
     648          27 :       auto i = std::remove_if(m_connected_components.begin(), 
     649             :                               m_connected_components.end(), 
     650          34 :                               [this](const std::set<std::size_t>& component){ return has_only_copied_CFPs(component); });
     651          27 :       m_connected_components.erase(i, m_connected_components.end());
     652          27 :       mCRL2log(log::debug) << "--- connected components after removing 'only copy' ones ---" << std::endl;
     653          27 :       print_connected_components();
     654          27 :     }
     655             : 
     656             :     const std::vector<bool>& is_GCFP(const core::identifier_string& X) const
     657             :     {
     658             :       auto i = m_is_GCFP.find(X);
     659             :       assert (i != m_is_GCFP.end());
     660             :       return i->second;
     661             :     }
     662             : 
     663             :     // returns the control flow parameters of the propositional variable with name X
     664             :     std::set<data::variable> control_flow_parameters(const core::identifier_string& X) const
     665             :     {
     666             :       std::set<data::variable> result;
     667             :       const std::vector<bool>& b = is_GCFP(X);
     668             :       auto const& eq_X = *find_equation(m_pbes, X);
     669             :       auto const& d_X = eq_X.parameters();
     670             :       std::size_t index = 0;
     671             :       for (auto i = d_X.begin(); i != d_X.end(); ++i, index++)
     672             :       {
     673             :         if (b[index])
     674             :         {
     675             :           result.insert(*i);
     676             :         }
     677             :       }
     678             :       return result;
     679             :     }
     680             : 
     681             :     std::vector<std::size_t> control_flow_parameter_indices(const core::identifier_string& X) const
     682             :     {
     683             :       std::vector<std::size_t> result;
     684             :       auto const& eq_X = *find_equation(m_pbes, X);
     685             :       auto const& d_X = eq_X.parameters();
     686             :       for (std::size_t k = 0; k < d_X.size(); k++)
     687             :       {
     688             :         if (is_global_control_flow_parameter(X, k))
     689             :         {
     690             :           result.push_back(k);
     691             :         }
     692             :       }
     693             :       return result;
     694             :     }
     695             : 
     696             :     std::string print_data_parameters(const core::identifier_string& X, const std::set<std::size_t>& I) const
     697             :     {
     698             :       std::ostringstream out;
     699             :       out << "  data parameters for vertex " << X << ":";
     700             :       for (std::size_t q: I)
     701             :       {
     702             :         out << " " << print_cfp(X, q);
     703             :       }
     704             :       return out.str();
     705             :     }
     706             : 
     707             :     // set the control flow and data parameter information in p
     708          27 :     void set_parameters(const stategraph_pbes& p)
     709             :     {
     710             :       // set control flow parameters
     711          27 :       std::map<core::identifier_string, std::set<std::size_t> > CFP; // CFP["X"] is the set of indices of control flow parameters of equation "X"
     712          60 :       for (const std::set<std::size_t>& component: m_connected_components)
     713             :       {
     714          85 :         for (std::size_t j: component)
     715             :         {
     716          52 :           const GCFP_vertex& u = m_GCFP_graph.vertex(j);
     717          52 :           if (u.has_variable())
     718             :           {
     719          52 :             CFP[u.name()].insert(u.index());
     720             :           }
     721             :         }
     722             :       }
     723          76 :       for (auto& i: CFP)
     724             :       {
     725          49 :         auto const& X = i.first;
     726          49 :         auto const& eqn = *find_equation(p, X);
     727          49 :         eqn.set_control_flow_parameters(i.second);
     728             :       }
     729             : 
     730             :       // set data parameters
     731          89 :       for (const stategraph_equation& eq_X: m_pbes.equations())
     732             :       {
     733          62 :         auto const& X = eq_X.variable().name();
     734          62 :         std::set<std::size_t> I; // data parameters of equation eq_X
     735         231 :         for (std::size_t i = 0; i < eq_X.parameters().size(); ++i)
     736             :         {
     737         169 :           I.insert(i);
     738             :         }
     739         136 :         for (const std::set<std::size_t>& component : m_connected_components)
     740             :         {
     741         200 :           for (std::size_t j: component)
     742             :           {
     743         126 :             const GCFP_vertex& u = m_GCFP_graph.vertex(j);
     744         126 :             if (u.name() == X && u.index() != data::undefined_index())
     745             :             {
     746          52 :               I.erase(u.index());
     747             :             }
     748             :           }
     749             :         }
     750          62 :         eq_X.set_data_parameters(I);
     751          62 :       }
     752          27 :     }
     753             : 
     754             :     // prints all vertices of the connected components
     755          27 :     void print_final_control_flow_parameters() const
     756             :     {
     757          27 :       std::ostringstream out;
     758          27 :       mCRL2log(log::verbose) << "--- computed control flow parameters ---" << std::endl;
     759             : 
     760             :       // collect the control flow points in the map CFP
     761          27 :       std::map<core::identifier_string, std::set<const GCFP_vertex*> > CFP;
     762          60 :       for (const std::set<std::size_t>& component: m_connected_components)
     763             :       {
     764          85 :         for (std::size_t j: component)
     765             :         {
     766          52 :           const GCFP_vertex& u = m_GCFP_graph.vertex(j);
     767          52 :           if (u.has_variable())
     768             :           {
     769          52 :             CFP[u.name()].insert(&u);
     770             :           }
     771             :         }
     772             :       }
     773             : 
     774             :       // print the map CFP
     775          76 :       for (auto i = CFP.begin(); i != CFP.end(); ++i)
     776             :       {
     777          49 :         if (i != CFP.begin())
     778             :         {
     779          26 :           out << "\n";
     780             :         }
     781          49 :         auto const& V = i->second;
     782         101 :         for (auto j = V.begin(); j != V.end(); ++j)
     783             :         {
     784          52 :           if (j != V.begin())
     785             :           {
     786           3 :             out << ", ";
     787             :           }
     788          52 :           out << **j;
     789             :         }
     790             :       }
     791          27 :       mCRL2log(log::verbose) << out.str() << std::endl;
     792          27 :     }
     793             : 
     794             :     /// \brief Constructor.
     795          27 :     stategraph_algorithm(const pbes& p, const pbesstategraph_options& options)
     796          27 :       : m_datar(p.data(), options.rewrite_strategy),
     797          27 :         m_use_alternative_lcfp_criterion(options.use_alternative_lcfp_criterion),
     798          27 :         m_use_alternative_gcfp_relation(options.use_alternative_gcfp_relation),
     799          27 :         m_use_alternative_gcfp_consistency(options.use_alternative_gcfp_consistency),
     800          54 :         m_options(options)
     801             :     {
     802          27 :       m_pbes = stategraph_pbes(p, m_datar);
     803          27 :     }
     804             : 
     805             :     /// \brief Destructor.
     806          27 :     virtual ~stategraph_algorithm() = default;
     807             : 
     808             :     /// \brief Returns the connected components of the global control flow graph.
     809          26 :     const std::vector<std::set<std::size_t> >& connected_components() const
     810             :     {
     811          26 :       return m_connected_components;
     812             :     }
     813             : 
     814          50 :     std::string print(const GCFP_vertex& u) const
     815             :     {
     816          50 :       std::ostringstream out;
     817          50 :       out << '(' << u.name() << ", " << find_equation(m_pbes, u.name())->parameters()[u.index()].name() << ')';
     818         100 :       return out.str();
     819          50 :     }
     820             : 
     821             :     /// \brief Computes the values that the CFPs in component can attain.
     822          33 :     std::set<data::data_expression> compute_connected_component_values(const std::set<std::size_t>& component)
     823             :     {
     824          33 :       std::set<data::data_expression> result;
     825             : 
     826             :       // search for a node that corresponds to a variable in the init of the PBES
     827          33 :       const propositional_variable_instantiation& init = m_pbes.initial_state();
     828          33 :       auto const& Xinit = init.name();
     829             : 
     830          85 :       for (std::size_t j: component)
     831             :       {
     832          52 :         const GCFP_vertex& u = m_GCFP_graph.vertex(j);
     833          52 :         if (u.name() == Xinit)
     834             :         {
     835          20 :           const data::data_expression& d = nth_element(init.parameters(), u.index());
     836          20 :           result.insert(d);
     837             :         }
     838             :       }
     839             : 
     840             :       // source(X, i, k) = v
     841          85 :       for (std::size_t p: component)
     842             :       {
     843          52 :         const GCFP_vertex& u = m_GCFP_graph.vertex(p);
     844          52 :         auto const& X = u.name();
     845          52 :         std::size_t k = u.index();
     846          52 :         auto const& eq_X = *find_equation(m_pbes, X);
     847         145 :         for (const predicate_variable& predvar: eq_X.predicate_variables())
     848             :         {
     849          93 :           auto q = predvar.source().find(k);
     850          93 :           if (q != predvar.source().end())
     851             :           {
     852          77 :             const data::data_expression& v = q->second;
     853          77 :             result.insert(v);
     854             :           }
     855             :         }
     856             :       }
     857             : 
     858             :       // target(X, i, k) = v
     859          85 :       for (std::size_t p: component)
     860             :       {
     861          52 :         const GCFP_vertex& u = m_GCFP_graph.vertex(p);
     862          52 :         auto const& Y = u.name();
     863          52 :         std::size_t k = u.index();
     864          52 :         auto const& eq_Y = *find_equation(m_pbes, Y);
     865         145 :         for (const predicate_variable& predvar: eq_Y.predicate_variables())
     866             :         {
     867          93 :           if (predvar.name() != Y)
     868             :           {
     869          61 :             continue;
     870             :           }
     871          32 :           auto q = predvar.target().find(k);
     872          32 :           if (q != predvar.target().end())
     873             :           {
     874          31 :             const data::data_expression& v = q->second;
     875          31 :             result.insert(v);
     876             :           }
     877             :         }
     878             :       }
     879             : 
     880          33 :       return result;
     881           0 :     }
     882             : 
     883          27 :     void compute_connected_component_values()
     884             :     {
     885          27 :       mCRL2log(log::debug) << "=== computing values for the components" << std::endl;
     886          60 :       for (const std::set<std::size_t>& component: m_connected_components)
     887             :       {
     888          33 :         std::set<data::data_expression> values = compute_connected_component_values(component);
     889          33 :         m_connected_components_values.push_back(values);
     890          33 :         mCRL2log(log::debug) << print_connected_component(component) << " values = " << core::detail::print_set(values) << std::endl;
     891          33 :       }
     892          27 :     }
     893             : 
     894             :     // Returns the possible values of the vertex (X, j). N.B. Very inefficient!
     895             :     std::vector<data::data_expression> compute_values(const core::identifier_string& X, std::size_t j) const
     896             :     {
     897             :       // search for a graph that contains (X, j)
     898             :       for (std::size_t k = 0; k < m_local_control_flow_graphs.size(); k++)
     899             :       {
     900             :         auto const& Gk = m_local_control_flow_graphs[k];
     901             :         if (Gk.has_vertex(X, j))
     902             :         {
     903             :           auto const& values = m_connected_components_values[k];
     904             :           return std::vector<data::data_expression>(values.begin(), values.end());
     905             :         }
     906             :       }
     907             :       throw mcrl2::runtime_error("error in compute_values: vertex not found");
     908             :     }
     909             : 
     910             :     /// \brief Computes the control flow graph
     911          27 :     virtual void run()
     912             :     {
     913          27 :       simplify(m_pbes);
     914          27 :       m_pbes.compute_source_target_copy();
     915          27 :       mCRL2log(log::debug) << "--- source, target, copy ---\n" << m_pbes.print_source_target_copy() << std::endl;
     916          27 :       compute_control_flow_parameters();
     917          27 :       remove_invalid_connected_components();
     918          27 :       remove_only_copy_components();
     919          27 :       mCRL2log(log::trace) << "--- GCFP graph = ---\n" << m_GCFP_graph << std::endl;
     920          27 :       set_parameters(m_pbes);
     921          27 :       print_final_control_flow_parameters();
     922             : 
     923          27 :       start_timer("compute_connected_component_values");
     924          27 :       compute_connected_component_values();
     925          27 :       finish_timer("compute_connected_component_values");
     926          27 :     }
     927             : 
     928           0 :     const stategraph_pbes& get_pbes() const
     929             :     {
     930           0 :       return m_pbes;
     931             :     }
     932             : 
     933          31 :     const GCFP_graph& GCFP() const
     934             :     {
     935          31 :       return m_GCFP_graph;
     936             :     }
     937             : 
     938             :     const std::vector<local_control_flow_graph>& local_graphs() const
     939             :     {
     940             :       return m_local_control_flow_graphs;
     941             :     }
     942             : };
     943             : 
     944             : } // namespace detail
     945             : 
     946             : } // namespace pbes_system
     947             : 
     948             : } // namespace mcrl2
     949             : 
     950             : #endif // MCRL2_PBES_DETAIL_STATEGRAPH_ALGORITHM_H

Generated by: LCOV version 1.14