LCOV - code coverage report
Current view: top level - pbes/include/mcrl2/pbes - bisimulation.h (source / functions) Hit Total Coverage
Test: mcrl2_coverage.info.cleaned Lines: 428 428 100.0 %
Date: 2024-04-21 03:44:01 Functions: 37 37 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Author(s): Wieger Wesselink
       2             : // Copyright: see the accompanying file COPYING or copy at
       3             : // https://github.com/mCRL2org/mCRL2/blob/master/COPYING
       4             : //
       5             : // Distributed under the Boost Software License, Version 1.0.
       6             : // (See accompanying file LICENSE_1_0.txt or copy at
       7             : // http://www.boost.org/LICENSE_1_0.txt)
       8             : //
       9             : /// \file mcrl2/pbes/bisimulation.h
      10             : /// \brief Bisimulation algorithms.
      11             : 
      12             : #ifndef MCRL2_PBES_BISIMULATION_H
      13             : #define MCRL2_PBES_BISIMULATION_H
      14             : 
      15             : #include "mcrl2/data/merge_data_specifications.h"
      16             : #include "mcrl2/lps/replace.h"
      17             : #include "mcrl2/pbes/detail/lps2pbes_utility.h"
      18             : #include "mcrl2/pbes/join.h"
      19             : 
      20             : namespace mcrl2
      21             : {
      22             : 
      23             : namespace pbes_system
      24             : {
      25             : 
      26             : /// \brief Base class for bisimulation algorithms.
      27             : class bisimulation_algorithm
      28             : {
      29             :   public:
      30             :     /// \brief The iterator type for non-delta summands
      31             :     typedef lps::action_summand_vector::const_iterator my_iterator;
      32             : 
      33             :   protected:
      34             :     /// \brief A map type for mapping summands to strings.
      35             :     typedef std::map<const lps::action_summand*, std::string> name_map;
      36             : 
      37             :     /// \brief Maps summands to strings.
      38             :     name_map summand_names;
      39             : 
      40             :     /// \brief Store the address of the model.
      41             :     const lps::linear_process* model_ptr = nullptr;
      42             : 
      43             :     /// \brief Generates a name for an action_list.
      44             :     /// \param l A sequence of actions
      45             :     /// \return A string representation of the list \p l
      46         288 :     std::string action_list_name(const process::action_list& l) const
      47             :     {
      48         288 :       std::ostringstream out;
      49         536 :       for (auto i = l.begin(); i != l.end(); ++i)
      50             :       {
      51         248 :         out << (i != l.begin() ? "-" : "") << std::string(i->label().name());
      52             :       }
      53         288 :       std::string result = out.str();
      54         288 :       if (result.empty())
      55             :       {
      56          40 :         result = "tau";
      57             :       }
      58         576 :       return result;
      59         288 :     }
      60             : 
      61             :     /// \brief Returns the name of a summand
      62             :     /// \param i A summand iterator
      63             :     /// \return The name of the summand referred to by \p i
      64         792 :     std::string summand_name(my_iterator i) const
      65             :     {
      66         792 :       const lps::action_summand* t = &(*i);
      67         792 :       auto j = summand_names.find(t);
      68         792 :       assert(j != summand_names.end());
      69        1584 :       return j->second;
      70             :     }
      71             : 
      72             :     /// \brief Returns true if p is the linear process of the model.
      73             :     /// \param p A linear process
      74             :     /// \return True if p is the linear process of the model.
      75        7904 :     bool is_from_model(const lps::linear_process& p) const
      76             :     {
      77        7904 :       return &p == model_ptr;
      78             :     }
      79             : 
      80             :     /// \brief Returns a name of a linear process.
      81             :     /// \param p A linear process
      82             :     /// \return The name of the linear process.
      83        7840 :     std::string process_name(const lps::linear_process& p) const
      84             :     {
      85        7840 :       if (is_from_model(p))
      86             :       {
      87        3920 :         return "m";
      88             :       }
      89             :       else
      90             :       {
      91        3920 :         return "s";
      92             :       }
      93             :     }
      94             : 
      95             :     /// \brief Used for initializing summand names.
      96             :     /// \param p A linear process
      97          64 :     void set_summand_names(const lps::linear_process& p)
      98             :     {
      99          64 :       data::set_identifier_generator generator;
     100         352 :       for (const lps::action_summand& s: p.action_summands())
     101             :       {
     102         576 :         std::string name = generator(action_list_name(s.multi_action().actions()));
     103         288 :         summand_names[&s] = name;
     104         288 :       }
     105          64 :     }
     106             : 
     107             :     // creates the substitution v[i] := e[i]
     108             :     // pre: v.size() == e.size()
     109        1370 :     void make_substitution(const data::variable_list& v, const data::data_expression_list& e, data::mutable_map_substitution<>& result) const
     110             :     {
     111        1370 :       assert(v.size() == e.size());
     112        1370 :       auto vi = v.begin();
     113        1370 :       auto ei = e.begin();
     114       12008 :       for (; vi != v.end(); ++vi, ++ei)
     115             :       {
     116       10638 :         result[*vi] = *ei;
     117             :       }
     118        1370 :     }
     119             : 
     120             :   public:
     121             :     /// \brief Creates a name for the propositional variable Xpq
     122             :     /// \param p A linear process
     123             :     /// \param q A linear process
     124             :     /// \return The name for the propositional variable Xpq
     125        3128 :     core::identifier_string X(const lps::linear_process& p, const lps::linear_process& q) const
     126             :     {
     127        6256 :       std::string s = "X" + process_name(p) + process_name(q);
     128        6256 :       return core::identifier_string(s);
     129        3128 :     }
     130             : 
     131             :     /// \brief Creates a name for the propositional variable Ypq
     132             :     /// \param p A linear process
     133             :     /// \param q A linear process
     134             :     /// \return The name for the propositional variable Ypq
     135             :     core::identifier_string Y(const lps::linear_process& p, const lps::linear_process& q) const
     136             :     {
     137             :       std::string s = "Y" + process_name(p) + process_name(q);
     138             :       return core::identifier_string(s);
     139             :     }
     140             : 
     141             :     /// \brief Creates a name for the propositional variable Ypqi
     142             :     /// \pre The iterator i must be in p.action_summands().
     143             :     /// \param p A linear process
     144             :     /// \param q A linear process
     145             :     /// \param i A summand iterator
     146             :     /// \return The name for the propositional variable Ypqi
     147         344 :     core::identifier_string Y(const lps::linear_process& p, const lps::linear_process& q, my_iterator i) const
     148             :     {
     149         688 :       std::string s = "Y" + process_name(p) + process_name(q) + "_" + summand_name(i);
     150         688 :       return core::identifier_string(s);
     151         344 :     }
     152             : 
     153             :     /// \brief Creates a name for the propositional variable Y1pqi
     154             :     /// \pre The iterator i must be in p.action_summands().
     155             :     /// \param p A linear process
     156             :     /// \param q A linear process
     157             :     /// \param i A summand iterator
     158             :     /// \return The name for the propositional variable Y1pqi
     159         172 :     core::identifier_string Y1(const lps::linear_process& p, const lps::linear_process& q, my_iterator i) const
     160             :     {
     161         344 :       std::string s = "Y1" + process_name(p) + process_name(q) + "_" + summand_name(i);
     162         344 :       return core::identifier_string(s);
     163         172 :     }
     164             : 
     165             :     /// \brief Creates a name for the propositional variable Y2pqi
     166             :     /// \pre The iterator i must be in p.action_summands().
     167             :     /// \param p A linear process
     168             :     /// \param q A linear process
     169             :     /// \param i A summand iterator
     170             :     /// \return The name for the propositional variable Y2pqi
     171         276 :     core::identifier_string Y2(const lps::linear_process& p, const lps::linear_process& q, my_iterator i) const
     172             :     {
     173         552 :       std::string s = "Y2" + process_name(p) + process_name(q) + "_" + summand_name(i);
     174         552 :       return core::identifier_string(s);
     175         276 :     }
     176             : 
     177             :     /// \brief Creates a propositional variable.
     178             :     /// \param name A
     179             :     /// \param parameters A sequence of data variables
     180             :     /// \return The created propositional variable
     181         392 :     propositional_variable_instantiation var(const core::identifier_string& name, const data::variable_list& parameters) const
     182             :     {
     183         392 :       return propositional_variable_instantiation(name, atermpp::down_cast<data::data_expression_list>(static_cast<const atermpp::aterm&>(parameters)));
     184             :     }
     185             : 
     186             :     /// \brief Creates a propositional variable.
     187             :     /// \param name A
     188             :     /// \param parameters A sequence of data expressions
     189             :     /// \return The created propositional variable
     190        3144 :     propositional_variable_instantiation var(const core::identifier_string& name, const data::data_expression_list& parameters) const
     191             :     {
     192        3144 :       return propositional_variable_instantiation(name, parameters);
     193             :     }
     194             : 
     195             :     /// \brief Returns a pbes expression that expresses equality of the multi-actions a and b.
     196             :     /// \param a A sequence of actions
     197             :     /// \param b A sequence of actions
     198             :     /// \return Necessary conditions for the equality of a and b
     199        2196 :     pbes_expression equals(const lps::multi_action& a, const lps::multi_action& b) const
     200             :     {
     201        2196 :       return lps::equal_multi_actions(a, b);
     202             :     }
     203             : 
     204             :     /// \brief Returns the fixpoint symbol mu.
     205             :     /// \return The fixpoint symbol mu.
     206         288 :     fixpoint_symbol mu() const
     207             :     {
     208         288 :       return fixpoint_symbol::mu();
     209             :     }
     210             : 
     211             :     /// \brief Returns the fixpoint symbol nu.
     212             :     /// \return The fixpoint symbol nu.
     213          64 :     fixpoint_symbol nu() const
     214             :     {
     215          64 :       return fixpoint_symbol::nu();
     216             :     }
     217             : 
     218             :     /// \brief Returns a substitution of variables in q such that there are no name clashes
     219             :     /// between p and q.
     220             :     /// \param p A linear process specification
     221             :     /// \param q A linear process specification
     222             :     /// \return A substitution that should be applied to q to remove name clashes between p and q.
     223             :     /// \details After this substitution the following holds:
     224             :     /// \f[ ((param(p)\cup glob(p))\cap ((param(q)\cup glob(q))=\emptyset \f]
     225             :     /// where param(p) denotes p.process().process_parameters() and glob(p) denotes p.global_variables().
     226          32 :     data::mutable_map_substitution<> compute_process_parameter_name_clashes(const lps::specification& p, const lps::specification& q) const
     227             :     {
     228          32 :        data::mutable_map_substitution<> result;
     229             : 
     230             :       // put the names of variables appearing in p and q in an identifier generator
     231          32 :       std::set<data::variable> context = lps::find_all_variables(p);
     232          32 :       std::set<data::variable> vars = lps::find_all_variables(q);
     233          32 :       context.insert(vars.begin(), vars.end());
     234          32 :       data::set_identifier_generator generator;
     235         164 :       for (const data::variable& v: context)
     236             :       {
     237         132 :         generator.add_identifier(v.name());
     238             :       }
     239             : 
     240             :       // generate renamings for variables appearing in qvars
     241         120 :       for (const data::variable& w: q.process().process_parameters())
     242             :       {
     243         176 :         data::variable v(generator(w.name()), w.sort());
     244          88 :         if (v != w)
     245             :         {
     246          88 :           result[w] = v;
     247             :         }
     248          88 :       }
     249          64 :       return result;
     250          32 :     }
     251             : 
     252             :     /// \brief Returns a substitution of variables in q such that there are no name clashes
     253             :     /// between the summation variables of p and q.
     254             :     /// \param p A linear process specification
     255             :     /// \param q A linear process specification
     256             :     /// \return A substitution that should be applied to q to remove name clashes between p and q.
     257          32 :     data::mutable_map_substitution<> compute_summand_variable_name_clashes(const lps::specification& p, const lps::specification& q) const
     258             :     {
     259          32 :       data::mutable_map_substitution<> result;
     260             : 
     261             :       // put the names of variables appearing in p and q in an identifier generator
     262          32 :       std::set<data::variable> context = lps::find_all_variables(p);
     263          32 :       std::set<data::variable> vars = lps::find_all_variables(q);
     264          32 :       context.insert(vars.begin(), vars.end());
     265          32 :       data::set_identifier_generator generator;
     266         244 :       for (const data::variable& v: context)
     267             :       {
     268         212 :         generator.add_identifier(v.name());
     269             :       }
     270             : 
     271             :       // put the summation variables of q in qvars
     272          32 :       std::set<data::variable> qvars;
     273         176 :       for (const lps::action_summand& s: q.process().action_summands())
     274             :       {
     275         144 :         const data::variable_list& v = s.summation_variables();
     276         144 :         qvars.insert(v.begin(), v.end());
     277             :       }
     278          52 :       for (const lps::deadlock_summand& s: q.process().deadlock_summands())
     279             :       {
     280          20 :         const data::variable_list& v = s.summation_variables();
     281          20 :         qvars.insert(v.begin(), v.end());
     282             :       }
     283             : 
     284             :       // generate renamings for variables appearing in qvars
     285          56 :       for (const data::variable& w: qvars)
     286             :       {
     287          48 :         data::variable v(generator(w.name()), w.sort());
     288          24 :         if (v != w)
     289             :         {
     290          24 :           result[w] = v;
     291             :         }
     292          24 :       }
     293          64 :       return result;
     294          32 :     }
     295             : 
     296             :     /// \brief Resolves name clashes between model and spec.
     297          32 :     void resolve_name_clashes(const lps::specification& model, lps::specification& spec, bool include_summand_variables = false)
     298             :     {
     299          32 :       data::mutable_map_substitution<> sigma = compute_process_parameter_name_clashes(model, spec);
     300          32 :       lps::replace_process_parameters(spec, sigma);
     301          32 :       if (include_summand_variables)
     302             :       {
     303          32 :         sigma = compute_summand_variable_name_clashes(model, spec);
     304          32 :         lps::replace_summand_variables(spec, sigma);
     305             :       }
     306          32 :       mCRL2log(log::debug) << "bisimulation spec after resolving name clashes:\n" << lps::pp(spec) << std::endl;
     307          32 :     }
     308             : 
     309             :     /// \brief Initializes the name lookup table.
     310             :     /// \param model A linear process
     311             :     /// \param spec A linear process
     312             :     /// \pre model and spec must have the same data specification
     313          32 :     void init(const lps::linear_process& model, const lps::linear_process& spec)
     314             :     {
     315          32 :       summand_names.clear();
     316          32 :       set_summand_names(model);
     317          32 :       set_summand_names(spec);
     318          32 :       model_ptr = &model;
     319          32 :       assert(is_from_model(model));
     320          32 :       assert(!is_from_model(spec));
     321          32 :     }
     322             : 
     323             :     /// \brief Builds a pbes from the given equations.
     324             :     /// \param equations A sequence of pbes equations
     325             :     /// \param M A specification
     326             :     /// \param S A specification
     327             :     /// \return The constructed pbes
     328          32 :     pbes build_pbes(const std::vector<pbes_equation>& equations,
     329             :                     const lps::specification& M,
     330             :                     const lps::specification& S
     331             :                    )
     332             :     {
     333          32 :       const lps::linear_process& m = M.process();
     334          32 :       const lps::linear_process& s = S.process();
     335             : 
     336          64 :       propositional_variable_instantiation init(X(m, s), M.initial_process().expressions() + S.initial_process().expressions());
     337             : 
     338          32 :       pbes result(M.data(), equations, init);
     339          32 :       assert(result.is_closed());
     340          64 :       return result;
     341          32 :     }
     342             : };
     343             : 
     344             : //--------------------------------------------------------------//
     345             : //                 branching bisimulation
     346             : //--------------------------------------------------------------//
     347             : 
     348             : /// \brief Algorithm class for branching bisimulation.
     349             : class branching_bisimulation_algorithm : public bisimulation_algorithm
     350             : {
     351             :   public:
     352             :     /// \brief The match function.
     353             :     /// \param p A linear process
     354             :     /// \param q A linear process
     355             :     /// \return The function result
     356          32 :     pbes_expression match(const lps::linear_process& p, const lps::linear_process& q) const
     357             :     {
     358          32 :       std::vector<pbes_expression> result;
     359         176 :       for (auto i = p.action_summands().begin(); i != p.action_summands().end(); ++i)
     360             :       {
     361         144 :         data::data_expression ci = i->condition();
     362         144 :         const data::variable_list& d  = p.process_parameters();
     363         144 :         data::variable_list e  = i->summation_variables();
     364         144 :         const data::variable_list& d1 = q.process_parameters();
     365         144 :         pbes_expression expr;
     366         144 :         optimized_imp(expr, ci, var(Y(p, q, i), d + d1 + e));
     367         144 :         expr = make_forall_(e, expr);
     368         144 :         result.push_back(expr);
     369         144 :       }
     370          64 :       return optimized_join_and(result.begin(), result.end());
     371          32 :     }
     372             : 
     373             :     /// \brief The step function.
     374             :     /// \param p A linear process
     375             :     /// \param q A linear process
     376             :     /// \param i A summand iterator
     377             :     /// \return The function result
     378         144 :     pbes_expression step(const lps::linear_process& p, const lps::linear_process& q, my_iterator i) const
     379             :     {
     380         144 :       const data::variable_list& d1 = q.process_parameters();
     381         144 :       data::data_expression_list gi = i->next_state(p.process_parameters());
     382         144 :       if (i->is_tau())
     383             :       {
     384          20 :         std::vector<pbes_expression> v;
     385          20 :         pbes_expression expr;
     386          76 :         for (auto j = q.action_summands().begin(); j != q.action_summands().end(); ++j)
     387             :         {
     388          56 :           if (!j->is_tau())
     389             :           {
     390          40 :             continue;
     391             :           }
     392          16 :           data::data_expression cj = j->condition();
     393          16 :           data::variable_list e1 = j->summation_variables();
     394          16 :           data::data_expression_list gj = j->next_state(q.process_parameters());
     395          16 :           optimized_and(expr, cj, var(X(p, q), gi + gj));
     396          16 :           expr = make_exists_(e1, expr);
     397          16 :           v.push_back(expr);
     398          16 :         }
     399          20 :         optimized_or(expr, optimized_join_or(v.begin(), v.end()), var(X(p, q), gi + d1));
     400          20 :         return expr;
     401          20 :       }
     402             :       else
     403             :       {
     404         124 :         std::vector<pbes_expression> v;
     405        1208 :         for (auto j = q.action_summands().begin(); j != q.action_summands().end(); ++j)
     406             :         {
     407        1084 :           data::data_expression cj = j->condition();
     408        1084 :           data::variable_list e1 = j->summation_variables();
     409        1084 :           data::data_expression_list gj = j->next_state(q.process_parameters());
     410        1084 :           lps::multi_action ai = i->multi_action();
     411        1084 :           lps::multi_action aj = j->multi_action();
     412        1084 :           pbes_expression expr; 
     413        1084 :           optimized_and(expr, cj, equals(ai, aj));
     414        1084 :           optimized_and(expr, expr, var(X(p, q), gi + gj));
     415        1084 :           expr = make_exists_(e1, expr);
     416        1084 :           v.push_back(expr);
     417        1084 :         }
     418         124 :         return optimized_join_or(v.begin(), v.end());
     419         124 :       }
     420         144 :     }
     421             : 
     422             :     /// \brief The close function.
     423             :     /// \param p A linear process
     424             :     /// \param q A linear process
     425             :     /// \param i A summand iterator
     426             :     /// \return The function result
     427         144 :     pbes_expression close(const lps::linear_process& p, const lps::linear_process& q, my_iterator i) const
     428             :     {
     429         144 :       std::vector<pbes_expression> v;
     430         144 :       pbes_expression expr;
     431         144 :       const data::variable_list& d  = p.process_parameters();
     432         144 :       const data::variable_list& d1 = q.process_parameters();
     433         144 :       data::variable_list e  = i->summation_variables();
     434        1284 :       for (auto j = q.action_summands().begin(); j != q.action_summands().end(); ++j)
     435             :       {
     436        1140 :         if (!j->is_tau())
     437             :         {
     438        1084 :           continue;
     439             :         }
     440          56 :         data::data_expression cj = j->condition();
     441          56 :         data::variable_list e1 = j->summation_variables();
     442          56 :         data::data_expression_list  gj = j->next_state(q.process_parameters());
     443          56 :         optimized_and(expr, cj, var(Y(p, q, i), 
     444          56 :                             variable_list_to_data_expression_list(d) + 
     445         112 :                                 gj + 
     446          56 :                             data::variable_list_to_data_expression_list(e)));
     447          56 :         expr = make_exists_(e1, expr);
     448          56 :         v.push_back(expr);
     449          56 :       }
     450             :      
     451         144 :       optimized_and(expr, var(X(p, q), d + d1), step(p, q, i));
     452         144 :       optimized_or(expr, optimized_join_or(v.begin(), v.end()), expr);
     453         288 :       return expr;
     454         144 :     }
     455             : 
     456             :     /// \brief Returns a pbes that expresses branching bisimulation between
     457             :     /// two specifications.
     458             :     /// \param model A linear process specification
     459             :     /// \param spec A linear process specification
     460             :     /// \return A pbes that expresses branching bisimulation between the
     461             :     /// two specifications.
     462           8 :     pbes run(const lps::specification& model, const lps::specification& spec)
     463             :     {
     464             :       // resolve name clashes, and merge the data specifications of model and spec
     465           8 :       data::data_specification dataspec = data::merge_data_specifications(model.data(), spec.data());
     466           8 :       lps::specification spec1 = spec;
     467           8 :       lps::specification model1 = model;
     468           8 :       resolve_name_clashes(model1, spec1, true);
     469           8 :       model1.data() = dataspec;
     470           8 :       spec1.data() = dataspec;
     471           8 :       lps::normalize_sorts(model1, model1.data());
     472           8 :       lps::normalize_sorts(spec1, spec1.data());
     473             : 
     474           8 :       const lps::linear_process& m = model1.process();
     475           8 :       const lps::linear_process& s = spec1.process();
     476           8 :       init(m, s);
     477             : 
     478           8 :       const data::variable_list& d  = m.process_parameters();
     479           8 :       const data::variable_list& d1 = s.process_parameters();
     480           8 :       std::vector<pbes_equation> equations;
     481             : 
     482             : 
     483             :       // E1
     484           8 :       pbes_expression expr;
     485           8 :       optimized_and(expr, match(m, s), match(s, m));
     486           8 :       equations.emplace_back(nu(), propositional_variable(X(m, s), d + d1), expr);
     487           8 :       equations.emplace_back(nu(), propositional_variable(X(s, m), d1 + d), var(X(m, s), d + d1));
     488             : 
     489             :       // E2
     490          44 :       for (auto i = m.action_summands().begin(); i != m.action_summands().end(); ++i)
     491             :       {
     492          36 :         data::variable_list e  = i->summation_variables();
     493          72 :         pbes_equation e1(mu(), propositional_variable(Y(m, s, i), d + d1 + e), close(m, s, i));
     494          36 :         equations.push_back(e1);
     495          36 :       }
     496          44 :       for (auto i = s.action_summands().begin(); i != s.action_summands().end(); ++i)
     497             :       {
     498          36 :         data::variable_list e  = i->summation_variables();
     499          72 :         pbes_equation e1(mu(), propositional_variable(Y(s, m, i), d1 + d + e), close(s, m, i));
     500          36 :         equations.push_back(e1);
     501          36 :       }
     502             : 
     503          16 :       return build_pbes(equations, model1, spec1);
     504           8 :     }
     505             : };
     506             : 
     507             : /// \brief Returns a pbes that expresses branching bisimulation between two specifications.
     508             : /// \param model A linear process specification
     509             : /// \param spec A linear process specification
     510             : /// \return A pbes that expresses branching bisimulation between the two specifications.
     511             : inline
     512           8 : pbes branching_bisimulation(const lps::specification& model, const lps::specification& spec)
     513             : {
     514          16 :   return branching_bisimulation_algorithm().run(model, spec);
     515             : }
     516             : 
     517             : //--------------------------------------------------------------//
     518             : //                 strong bisimulation
     519             : //--------------------------------------------------------------//
     520             : 
     521             : /// \brief Algorithm class for strong bisimulation.
     522             : class strong_bisimulation_algorithm : public bisimulation_algorithm
     523             : {
     524             :   public:
     525             :     /// \brief The match function.
     526             :     /// \param p A linear process
     527             :     /// \param q A linear process
     528             :     /// \return The function result
     529          16 :     pbes_expression match(const lps::linear_process& p, const lps::linear_process& q) const
     530             :     {
     531          16 :       std::vector<pbes_expression> result;
     532          88 :       for (auto i = p.action_summands().begin(); i != p.action_summands().end(); ++i)
     533             :       {
     534          72 :         data::data_expression ci = i->condition();
     535          72 :         data::variable_list e = i->summation_variables();
     536          72 :         pbes_expression  expr;
     537          72 :         optimized_imp(expr, ci, step(p, q, i));
     538          72 :         expr = make_forall_(e, expr);
     539          72 :         result.push_back(expr);
     540          72 :       }
     541          32 :       return optimized_join_and(result.begin(), result.end());
     542          16 :     }
     543             : 
     544             :     /// \brief The step function.
     545             :     /// \param p A linear process
     546             :     /// \param q A linear process
     547             :     /// \param i A summand iterator
     548             :     /// \return The function result
     549          72 :     pbes_expression step(const lps::linear_process& p, const lps::linear_process& q, my_iterator i) const
     550             :     {
     551          72 :       data::data_expression_list gi = i->next_state(p.process_parameters());
     552             : 
     553          72 :       std::vector<pbes_expression> result;
     554         642 :       for (auto j = q.action_summands().begin(); j != q.action_summands().end(); ++j)
     555             :       {
     556         570 :         data::data_expression cj = j->condition();
     557         570 :         data::variable_list e1 = j->summation_variables();
     558         570 :         data::data_expression_list gj = j->next_state(q.process_parameters());
     559         570 :         lps::multi_action ai = i->multi_action();
     560         570 :         lps::multi_action aj = j->multi_action();
     561         570 :         pbes_expression expr;
     562         570 :         optimized_and(expr, cj, equals(ai, aj));
     563         570 :         optimized_and(expr, expr, var(X(p, q), gi + gj));
     564         570 :         expr = make_exists_(e1, expr);
     565         570 :         result.push_back(expr);
     566         570 :       }
     567         144 :       return optimized_join_or(result.begin(), result.end());
     568          72 :     }
     569             : 
     570             :     /// \brief Runs the algorithm
     571             :     /// \param model A linear process specification
     572             :     /// \param spec A linear process specification
     573             :     /// \return A pbes that expresses strong bisimulation between stwo specifications.
     574           8 :     pbes run(const lps::specification& model, const lps::specification& spec)
     575             :     {
     576           8 :       lps::specification spec1 = spec;
     577           8 :       resolve_name_clashes(model, spec1, true);
     578           8 :       const lps::linear_process& m = model.process();
     579           8 :       const lps::linear_process& s = spec1.process();
     580           8 :       init(m, s);
     581             : 
     582           8 :       const data::variable_list& d  = m.process_parameters();
     583           8 :       const data::variable_list& d1 = s.process_parameters();
     584           8 :       std::vector<pbes_equation> equations;
     585             : 
     586             : 
     587             :       // E
     588           8 :       pbes_expression expr;
     589           8 :       optimized_and(expr, match(m, s), match(s, m));
     590           8 :       equations.emplace_back(nu(), propositional_variable(X(m, s), d + d1), expr);
     591           8 :       equations.emplace_back(nu(), propositional_variable(X(s, m), d1 + d), var(X(m, s), d + d1));
     592             : 
     593          16 :       return build_pbes(equations, model, spec1);
     594           8 :     }
     595             : };
     596             : 
     597             : /// \brief Returns a pbes that expresses strong bisimulation between two specifications.
     598             : /// \param model A linear process specification
     599             : /// \param spec A linear process specification
     600             : /// \return A pbes that expresses strong bisimulation between the two specifications.
     601             : inline
     602           8 : pbes strong_bisimulation(const lps::specification& model, const lps::specification& spec)
     603             : {
     604          16 :   return strong_bisimulation_algorithm().run(model, spec);
     605             : }
     606             : 
     607             : //--------------------------------------------------------------//
     608             : //                 weak bisimulation
     609             : //--------------------------------------------------------------//
     610             : 
     611             : /// \brief Algorithm class for weak bisimulation.
     612             : class weak_bisimulation_algorithm : public bisimulation_algorithm
     613             : {
     614             :   protected:
     615             :     mutable data::set_identifier_generator m_generator;
     616             : 
     617             :   public:
     618             :     /// \brief The match function.
     619             :     /// \param p A linear process
     620             :     /// \param q A linear process
     621             :     /// \return The function result
     622          16 :     pbes_expression match(const lps::linear_process& p, const lps::linear_process& q) const
     623             :     {
     624          16 :       std::vector<pbes_expression> result;
     625          88 :       for (auto i = p.action_summands().begin(); i != p.action_summands().end(); ++i)
     626             :       {
     627          72 :         data::data_expression ci = i->condition();
     628          72 :         const data::variable_list& d  = p.process_parameters();
     629          72 :         data::variable_list e  = i->summation_variables();
     630          72 :         const data::variable_list& d1 = q.process_parameters();
     631          72 :         pbes_expression expr;
     632          72 :         optimized_imp(expr, ci, var(Y1(p, q, i), d + d1 + e));
     633          72 :         expr = make_forall_(e, expr);
     634          72 :         result.push_back(expr);
     635          72 :       }
     636          32 :       return optimized_join_and(result.begin(), result.end());
     637          16 :     }
     638             : 
     639             :     /// \brief The step function.
     640             :     /// \param p A linear process
     641             :     /// \param q A linear process
     642             :     /// \param i A summand iterator
     643             :     /// \return The function result
     644          72 :     pbes_expression step(const lps::linear_process& p, const lps::linear_process& q, my_iterator i) const
     645             :     {
     646          72 :       const data::variable_list& d1 = q.process_parameters();
     647          72 :       data::data_expression_list gi = i->next_state(p.process_parameters());
     648          72 :       lps::multi_action ai(i->multi_action().actions());
     649          72 :       if (i->is_tau())
     650             :       {
     651          20 :         return close2(p, q, i, gi, data::data_expression_list(d1.begin(), d1.end()));
     652             :       }
     653             :       else
     654             :       {
     655          62 :         std::vector<pbes_expression> v;
     656         604 :         for (auto j = q.action_summands().begin(); j != q.action_summands().end(); ++j)
     657             :         {
     658         542 :           data::data_expression cj = j->condition();
     659         542 :           data::variable_list e1 = j->summation_variables();
     660         542 :           data::data_expression_list gj = j->next_state(q.process_parameters());
     661         542 :           lps::multi_action aj(j->multi_action().actions());
     662         542 :           pbes_expression expr;
     663         542 :           optimized_and(expr, cj, equals(ai, aj)), close2(p, q, i, gi, gj);
     664         542 :           optimized_and(expr, expr, close2(p, q, i, gi, gj));
     665         542 :           expr = make_exists_(e1, expr);
     666         542 :           v.push_back(expr);
     667         542 :         }
     668          62 :         return optimized_join_or(v.begin(), v.end());
     669          62 :       }
     670          72 :     }
     671             : 
     672             :     /// \brief The close1 function.
     673             :     /// \param p A linear process
     674             :     /// \param q A linear process
     675             :     /// \param i A summand iterator
     676             :     /// \return The function result
     677          72 :     pbes_expression close1(const lps::linear_process& p, const lps::linear_process& q, my_iterator i) const
     678             :     {
     679          72 :       std::vector<pbes_expression> v;
     680          72 :       pbes_expression expr;
     681          72 :       data::variable_list e = i->summation_variables();
     682          72 :       const data::variable_list& d = p.process_parameters();
     683          72 :       const data::variable_list& d1 = q.process_parameters();
     684         642 :       for (auto j = q.action_summands().begin(); j != q.action_summands().end(); ++j)
     685             :       {
     686         570 :         if (!j->is_tau())
     687             :         {
     688         542 :           continue;
     689             :         }
     690          28 :         data::data_expression cj = j->condition();
     691          28 :         data::variable_list e1 = j->summation_variables();
     692          28 :         data::data_expression_list gj = j->next_state(d1);
     693          28 :         optimized_and(expr, cj, var(Y1(p, q, i), 
     694          28 :                                     data::variable_list_to_data_expression_list(d) + 
     695          56 :                                     gj + 
     696          28 :                                     data::variable_list_to_data_expression_list(e)));
     697          28 :         expr = make_exists_(e1, expr);
     698          28 :         v.push_back(expr);
     699          28 :       }
     700          72 :       optimized_or(expr, optimized_join_or(v.begin(), v.end()), step(p, q, i));
     701         144 :       return expr;
     702          72 :     }
     703             : 
     704             :     /// \brief The close function.
     705             :     /// \param p A linear process
     706             :     /// \param q A linear process
     707             :     /// \param i A summand iterator
     708             :     /// \param d A sequence of data expressions
     709             :     /// \param d1 A sequence of data expressions
     710             :     /// \return The function result
     711        1166 :     pbes_expression close2(const lps::linear_process& p, const lps::linear_process& q, my_iterator i, const data::data_expression_list& d, const data::data_expression_list& d1) const
     712             :     {
     713        1166 :       const data::variable_list& parameters = q.process_parameters();
     714        1166 :       data::mutable_map_substitution<> sigma; // q.process_parameters() := d1
     715        1166 :       make_substitution(parameters, d1, sigma);
     716        1166 :       data::set_identifier_generator id_generator;
     717        8868 :       for (const data::variable& v: data::find_free_variables(d1))
     718             :       {
     719        7702 :         id_generator.add_identifier(v.name());
     720        1166 :       }
     721             : 
     722        1166 :       std::vector<pbes_expression> v;
     723        1166 :       pbes_expression expr;
     724             : 
     725       15864 :       for (auto j = q.action_summands().begin(); j != q.action_summands().end(); ++j)
     726             :       {
     727       14698 :         if (!j->is_tau())
     728             :         {
     729       14494 :           continue;
     730             :         }
     731             :         // d' == q.process_parameters()
     732             :         // e' == j->summand_variables()
     733         204 :         data::data_expression cj = j->condition();                        // cj == cj(d',e')
     734         204 :         data::data_expression_list gj = j->next_state(q.process_parameters()); // gj == gj(d',e')
     735         204 :         data::variable_list e1 = j->summation_variables();              // e1 == e'
     736             : 
     737             :         // replace d' by d1 (if needed)
     738         204 :         if (d1 != data::data_expression_list(parameters.begin(), parameters.end()))
     739             :         {
     740         168 :           cj = data::replace_variables_capture_avoiding(cj, sigma, id_generator);
     741         168 :           gj = data::replace_variables_capture_avoiding(gj, sigma, id_generator);
     742             :         }
     743             : 
     744             :         // replace e' (e1) by fresh variables e'' (e11)
     745         204 :         std::vector<data::variable> tmp;
     746         232 :         for (const data::variable& w: e1)
     747             :         {
     748          28 :           tmp.emplace_back(m_generator(std::string(w.name())), w.sort());
     749             :         }
     750         204 :         data::variable_list e11(tmp.begin(), tmp.end());
     751             : 
     752         204 :         data::mutable_map_substitution<> sigma1;
     753         204 :         make_substitution(e1, atermpp::container_cast<data::data_expression_list>(e11), sigma1);
     754         232 :         for (const data::variable& w: e11)
     755             :         {
     756          28 :           id_generator.add_identifier(w.name());
     757             :         }
     758         204 :         data::data_expression cj_new = data::replace_variables_capture_avoiding(cj, sigma1, id_generator);
     759         204 :         data::data_expression_list gj_new = data::replace_variables_capture_avoiding(gj, sigma1, id_generator);
     760             : 
     761         204 :         optimized_and(expr, cj_new, var(Y2(p, q, i), d + gj_new));
     762         204 :         expr = make_exists_(e11, expr);
     763         204 :         v.push_back(expr);
     764         204 :       }
     765        1166 :       optimized_or(expr, var(X(p, q), d + d1), optimized_join_or(v.begin(), v.end()));
     766        2332 :       return expr;
     767        1166 :     }
     768             : 
     769             :     /// \brief Runs the algorithm
     770             :     /// \param model A linear process specification
     771             :     /// \param spec A linear process specification
     772             :     /// \return A pbes that expresses weak bisimulation between two specifications.
     773           8 :     pbes run(const lps::specification& model, const lps::specification& spec)
     774             :     {
     775           8 :       lps::specification spec1 = spec;
     776           8 :       resolve_name_clashes(model, spec1, true);
     777           8 :       const lps::linear_process& m = model.process();
     778           8 :       const lps::linear_process& s = spec1.process();
     779           8 :       init(m, s);
     780             : 
     781           8 :       m_generator.clear_context();
     782           8 :       m_generator.add_identifiers(data::function_and_mapping_identifiers(model.data()));
     783           8 :       m_generator.add_identifiers(data::function_and_mapping_identifiers(spec.data()));
     784           8 :       m_generator.add_identifiers(lps::find_identifiers(model));
     785           8 :       m_generator.add_identifiers(lps::find_identifiers(spec));
     786             : 
     787           8 :       data::variable_list const& d  = m.process_parameters();
     788           8 :       data::variable_list const& d1 = s.process_parameters();
     789           8 :       std::vector<pbes_equation> equations;
     790             : 
     791             :       // E1
     792           8 :       pbes_expression expr;
     793           8 :       optimized_and(expr, match(m, s), match(s, m));
     794           8 :       equations.emplace_back(nu(), propositional_variable(X(m, s), d + d1), expr);
     795           8 :       equations.emplace_back(nu(), propositional_variable(X(s, m), d1 + d), var(X(m, s), d + d1));
     796             : 
     797             :       // E2
     798          44 :       for (auto i = m.action_summands().begin(); i != m.action_summands().end(); ++i)
     799             :       {
     800          36 :         data::variable_list e  = i->summation_variables();
     801          72 :         pbes_equation e1(mu(), propositional_variable(Y1(m, s, i), d + d1 + e), close1(m, s, i));
     802          72 :         pbes_equation e2(mu(), propositional_variable(Y2(m, s, i), d + d1), close2(m, s, i, data::data_expression_list(d.begin(), d.end()), data::data_expression_list(d1.begin(), d1.end())));
     803          36 :         equations.push_back(e1);
     804          36 :         equations.push_back(e2);
     805          36 :       }
     806          44 :       for (auto i = s.action_summands().begin(); i != s.action_summands().end(); ++i)
     807             :       {
     808          36 :         data::variable_list e  = i->summation_variables();
     809          72 :         pbes_equation e1(mu(), propositional_variable(Y1(s, m, i), d1 + d + e), close1(s, m, i));
     810          72 :         pbes_equation e2(mu(), propositional_variable(Y2(s, m, i), d1 + d), close2(s, m, i, data::data_expression_list(d1.begin(), d1.end()), data::data_expression_list(d.begin(), d.end())));
     811          36 :         equations.push_back(e1);
     812          36 :         equations.push_back(e2);
     813          36 :       }
     814             : 
     815          16 :       return build_pbes(equations, model, spec1);
     816           8 :     }
     817             : };
     818             : 
     819             : /// \brief Returns a pbes that expresses weak bisimulation between two specifications.
     820             : /// \param model A linear process specification
     821             : /// \param spec A linear process specification
     822             : /// \return A pbes that expresses weak bisimulation between the two specifications.
     823             : inline
     824           8 : pbes weak_bisimulation(const lps::specification& model, const lps::specification& spec)
     825             : {
     826          16 :   return weak_bisimulation_algorithm().run(model, spec);
     827             : }
     828             : 
     829             : //--------------------------------------------------------------//
     830             : //                 branching simulation equivalence
     831             : //--------------------------------------------------------------//
     832             : 
     833             : /// \brief Algorithm class for branching simulation equivalence.
     834             : class branching_simulation_equivalence_algorithm : public branching_bisimulation_algorithm
     835             : {
     836             :   public:
     837             :     /// \brief Runs the algorithm
     838             :     /// \param model A linear process specification
     839             :     /// \param spec A linear process specification
     840             :     /// \return A pbes that expresses branching simulation equivalence between two specifications.
     841           8 :     pbes run(const lps::specification& model, const lps::specification& spec)
     842             :     {
     843           8 :       lps::specification spec1 = spec;
     844           8 :       resolve_name_clashes(model, spec1, true);
     845           8 :       const lps::linear_process& m = model.process();
     846           8 :       const lps::linear_process& s = spec1.process();
     847           8 :       init(m, s);
     848             : 
     849           8 :       data::variable_list const& d  = m.process_parameters();
     850           8 :       data::variable_list const& d1 = s.process_parameters();
     851           8 :       std::vector<pbes_equation> equations;
     852             : 
     853             : 
     854             :       // E1
     855           8 :       pbes_expression expr;
     856           8 :       optimized_and(expr, match(m, s), match(s, m));
     857           8 :       equations.emplace_back(nu(), propositional_variable(X(m, s), d + d1), expr);
     858           8 :       equations.emplace_back(nu(), propositional_variable(X(s, m), d1 + d), var(X(m, s), d + d1));
     859             : 
     860             :       // E2
     861          44 :       for (auto i = m.action_summands().begin(); i != m.action_summands().end(); ++i)
     862             :       {
     863          36 :         data::variable_list e  = i->summation_variables();
     864          72 :         pbes_equation e1(mu(), propositional_variable(Y(m, s, i), d + d1 + e), close(m, s, i));
     865          36 :         equations.push_back(e1);
     866          36 :       }
     867          44 :       for (auto i = s.action_summands().begin(); i != s.action_summands().end(); ++i)
     868             :       {
     869          36 :         data::variable_list e  = i->summation_variables();
     870          72 :         pbes_equation e1(mu(), propositional_variable(Y(s, m, i), d1 + d + e), close(s, m, i));
     871          36 :         equations.push_back(e1);
     872          36 :       }
     873             : 
     874          16 :       return build_pbes(equations, model, spec1);
     875           8 :     }
     876             : };
     877             : 
     878             : /// \brief Returns a pbes that expresses branching simulation equivalence between two specifications.
     879             : /// \param model A linear process specification
     880             : /// \param spec A linear process specification
     881             : /// \return A pbes that expresses branching simulation equivalence between the two specifications.
     882             : inline
     883           8 : pbes branching_simulation_equivalence(const lps::specification& model, const lps::specification& spec)
     884             : {
     885          16 :   return branching_simulation_equivalence_algorithm().run(model, spec);
     886             : }
     887             : 
     888             : } // namespace pbes_system
     889             : 
     890             : } // namespace mcrl2
     891             : 
     892             : #endif // MCRL2_PBES_BISIMULATION_H

Generated by: LCOV version 1.14