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

          Line data    Source code
       1             : // Author(s): Jan Friso Groote, Wieger Wesselink
       2             : // Copyright: see the accompanying file COPYING or copy at
       3             : // https://github.com/mCRL2org/mCRL2/blob/master/COPYING
       4             : //
       5             : // Distributed under the Boost Software License, Version 1.0.
       6             : // (See accompanying file LICENSE_1_0.txt or copy at
       7             : // http://www.boost.org/LICENSE_1_0.txt)
       8             : //
       9             : /// \file mcrl2/lps/action_rename.h
      10             : /// \brief Action rename specifications.
      11             : 
      12             : #ifndef MCRL2_LPS_ACTION_RENAME_H
      13             : #define MCRL2_LPS_ACTION_RENAME_H
      14             : 
      15             : #include <regex>
      16             : 
      17             : #include "mcrl2/core/parse.h"
      18             : 
      19             : #include "mcrl2/data/rewriter.h"
      20             : #include "mcrl2/data/substitutions/mutable_map_substitution.h"
      21             : 
      22             : #include "mcrl2/lps/stochastic_specification.h"
      23             : #include "mcrl2/process/normalize_sorts.h"
      24             : #include "mcrl2/process/replace.h"
      25             : #include "mcrl2/process/translate_user_notation.h"
      26             : 
      27             : // //Action rename rules
      28             : // <ActionRenameRules>
      29             : //                ::= ActionRenameRules(<ActionRenameRule>*)
      30             : //
      31             : // //Action rename rule
      32             : // <ActionRenameRule>
      33             : //                ::= ActionRenameRule(<DataVarId>*, <DataExprOrNil>,
      34             : //                      <ParamIdOrAction>, <ActionRenameRuleRHS>)
      35             : //
      36             : // //Right-hand side of an action rename rule
      37             : // <ActionRenameRuleRHS>
      38             : //                ::= <ParamId>                                             [- tc]
      39             : //                  | <Action>                                              [+ tc]
      40             : //                  | Delta
      41             : //                  | Tau
      42             : //
      43             : // //Action rename action_rename_specification
      44             : // <ActionRenameSpec>
      45             : //                ::= ActionRenameSpec(<DataSpec>, <ActSpec>, <ActionRenameRules>)
      46             : 
      47             : namespace mcrl2
      48             : {
      49             : 
      50             : namespace lps
      51             : {
      52             : 
      53             : //                ::= ActionRenameRule(<DataVarId>*, <DataExprOrNil>,
      54             : //                      <ParamIdOrAction>, <ActionRenameRuleRHS>)
      55             : 
      56             : /// \brief Action rename rule
      57             : class action_rename_rule
      58             : {
      59             :   protected:
      60             :     /// \brief The data variables of the rule
      61             :     data::variable_list m_variables;
      62             : 
      63             :     /// \brief The condition of the rule
      64             :     data::data_expression    m_condition;
      65             : 
      66             :     /// \brief The left hand side of the rule
      67             :     process::action         m_lhs;
      68             : 
      69             :     /// \brief right hand side of the rule. Can only be an action, tau or delta.
      70             :     process::process_expression   m_rhs;
      71             : 
      72          80 :     bool check_that_rhs_is_tau_delta_or_an_action() const
      73             :     {
      74          80 :       return is_delta(m_rhs) || is_tau(m_rhs) || process::is_action(m_rhs);
      75             :     }
      76             : 
      77             :   public:
      78             :     /// \brief Constructor.
      79             :     action_rename_rule()
      80             :     { }
      81             : 
      82             :     /// \brief Constructor.
      83             :     /// \param t A term
      84             :     action_rename_rule(const atermpp::aterm_appl& t)
      85             :     {
      86             :       assert(core::detail::check_rule_ActionRenameRule(t));
      87             :       atermpp::aterm_appl::iterator i = t.begin();
      88             :       m_variables       = atermpp::down_cast<data::variable_list>(*i++);
      89             :       m_condition       = data::data_expression(*i++);
      90             :       m_lhs             = process::action(*i++);
      91             :       m_rhs             = process::process_expression(*i);
      92             :       assert(check_that_rhs_is_tau_delta_or_an_action());
      93             :     }
      94             : 
      95             :     /// \brief Constructor.
      96             :     /// \param t1 A term
      97             :     explicit action_rename_rule(const atermpp::aterm& t1)
      98             :     {
      99             :       const atermpp::aterm_appl t=atermpp::down_cast<atermpp::aterm_appl>(t1);
     100             :       assert(core::detail::check_rule_ActionRenameRule(t));
     101             :       atermpp::aterm_appl::iterator i = t.begin();
     102             :       m_variables       = atermpp::down_cast<data::variable_list>(*i++);
     103             :       m_condition       = data::data_expression(*i++);
     104             :       m_lhs             = process::action(*i++);
     105             :       m_rhs             = process::process_expression(*i);
     106             :       assert(check_that_rhs_is_tau_delta_or_an_action());
     107             :     }
     108             : 
     109             :     /// \brief Constructor.
     110          40 :     action_rename_rule(const data::variable_list&   variables,
     111             :                        const data::data_expression& condition,
     112             :                        const process::action&       lhs,
     113             :                        const process::process_expression& rhs)
     114          40 :       : m_variables(variables), m_condition(condition), m_lhs(lhs), m_rhs(rhs)
     115             :     {
     116          40 :       assert(check_that_rhs_is_tau_delta_or_an_action());
     117          40 :     }
     118             : 
     119             :     /// \brief Returns the variables of the rule.
     120             :     /// \return The variables of the rule.
     121          30 :     const data::variable_list& variables() const
     122             :     {
     123          30 :       return m_variables;
     124             :     }
     125             : 
     126             :     /// \brief Returns the variables of the rule.
     127             :     /// \return The variables of the rule.
     128          30 :     data::variable_list& variables()
     129             :     {
     130          30 :       return m_variables;
     131             :     }
     132             : 
     133             :     /// \brief Returns the condition of the rule.
     134             :     /// \return The condition of the rule.
     135          20 :     const data::data_expression& condition() const
     136             :     {
     137          20 :       return m_condition;
     138             :     }
     139             : 
     140             :     /// \brief Returns the condition of the rule.
     141             :     /// \return The condition of the rule.
     142          20 :     data::data_expression& condition()
     143             :     {
     144          20 :       return m_condition;
     145             :     }
     146             : 
     147             :     /// \brief Returns the left hand side of the rule.
     148             :     /// \return The left hand side of the rule.
     149          50 :     const process::action& lhs() const // Type should be action, but as it can be a ParamId(identifier_string,data_expression_list),
     150             :                                     // which is not accepted by the typechecker, this is a temporary fix, until this option
     151             :                                     // is added to an action.
     152             :     {
     153          50 :       return m_lhs;
     154             :     }
     155             : 
     156             :     /// \brief Returns the right hand side of the rule.
     157             :     /// \return The right hand side of the rule.
     158          40 :     const process::process_expression& rhs() const
     159             :     {
     160          40 :       assert(check_that_rhs_is_tau_delta_or_an_action());
     161          40 :       return m_rhs;
     162             :     }
     163             : };
     164             : 
     165             : 
     166             : /// \brief Read-only singly linked list of action rename rules
     167             : // typedef atermpp::term_list<action_rename_rule> action_rename_rule_list;
     168             : 
     169             : /// \brief Action rename specification
     170             : class action_rename_specification
     171             : {
     172             :   protected:
     173             : 
     174             :     /// \brief The data specification of the action rename specification
     175             :     data::data_specification m_data;
     176             : 
     177             :     /// \brief The action labels of the action rename specification
     178             :     process::action_label_list        m_action_labels;
     179             : 
     180             :     /// \brief The action rename rules of the action rename specification
     181             :     std::vector <action_rename_rule>  m_rules;
     182             : 
     183             :   public:
     184             :     /// \brief Constructor.
     185           6 :     action_rename_specification()
     186           6 :     { }
     187             : 
     188             :     /// \brief Constructor.
     189             :     /// \param t A term
     190             :     action_rename_specification(atermpp::aterm_appl t)
     191             :     {
     192             :       assert(core::detail::check_rule_ActionRenameSpec(t));
     193             :       atermpp::aterm_appl::iterator i = t.begin();
     194             :       m_data            = atermpp::down_cast<atermpp::aterm_appl>(*i++);
     195             :       m_action_labels   = atermpp::down_cast<process::action_label_list>(atermpp::down_cast<atermpp::aterm_appl>(*i++)[0]);
     196             : 
     197             :       atermpp::aterm_list rules_list = atermpp::down_cast<atermpp::aterm_list>(atermpp::down_cast<atermpp::aterm_appl>(*i)[0]);
     198             :       for (const atermpp::aterm& r: rules_list)
     199             :       {
     200             :         m_rules.push_back(action_rename_rule(r));
     201             :       }
     202             :     }
     203             : 
     204             :     /// \brief Constructor.
     205             :     /// \param data A data specification
     206             :     /// \param action_labels A sequence of action labels
     207             :     /// \param rules A sequence of action rename rules
     208           6 :     action_rename_specification(
     209             :       const data::data_specification& data,
     210             :       const process::action_label_list& action_labels,
     211             :       const std::vector <action_rename_rule>& rules)
     212           6 :       :
     213           6 :       m_data(data),
     214           6 :       m_action_labels(action_labels),
     215           6 :       m_rules(rules)
     216           6 :     { }
     217             : 
     218             :     /// \brief Returns the data action_rename_specification.
     219             :     /// \return The data action_rename_specification.
     220          12 :     const data::data_specification& data() const
     221             :     {
     222          12 :       return m_data;
     223             :     }
     224             : 
     225             :     /// \brief Returns the data specification.
     226          70 :     data::data_specification& data()
     227             :     {
     228          70 :       return m_data;
     229             :     }
     230             : 
     231             :     /// \brief Returns the sequence of action labels
     232             :     /// \return A sequence of action labels containing all action
     233             :     /// labels occurring in the action_rename_specification (but it can have more).
     234          57 :     const process::action_label_list& action_labels() const
     235             :     {
     236          57 :       return m_action_labels;
     237             :     }
     238             : 
     239             :     /// \brief Returns the sequence of action labels
     240          26 :     process::action_label_list& action_labels()
     241             :     {
     242          26 :       return m_action_labels;
     243             :     }
     244             : 
     245             :     /// \brief Returns the action rename rules.
     246             :     /// \return The action rename rules.
     247           6 :     const std::vector<action_rename_rule>& rules() const
     248             :     {
     249           6 :       return m_rules;
     250             :     }
     251             : 
     252             :     /// \brief Returns the action rename rules.
     253          38 :     std::vector<action_rename_rule>& rules()
     254             :     {
     255          38 :       return m_rules;
     256             :     }
     257             : 
     258             :     /// \brief Indicates whether the action_rename_specification is well typed.
     259             :     /// \return Always returns true.
     260             :     bool is_well_typed() const
     261             :     {
     262             :       return true;
     263             :     }
     264             : };
     265             : 
     266             : inline
     267             : atermpp::aterm_appl action_rename_rule_to_aterm(const action_rename_rule& rule)
     268             : {
     269             :   return atermpp::aterm_appl(core::detail::function_symbol_ActionRenameRule(), rule.variables(), rule.condition(), rule.lhs(), rule.rhs());
     270             : }
     271             : 
     272             : inline
     273             : atermpp::aterm_appl action_rename_specification_to_aterm(const action_rename_specification& spec)
     274             : {
     275             :   std::vector<atermpp::aterm_appl> rules;
     276             :   for (const action_rename_rule& r: spec.rules())
     277             :   {
     278             :     rules.push_back(action_rename_rule_to_aterm(r));
     279             :   }
     280             :   return atermpp::aterm_appl(core::detail::function_symbol_ActionRenameSpec(),
     281             :     data::detail::data_specification_to_aterm(spec.data()),
     282             :     atermpp::aterm_appl(core::detail::function_symbol_ActSpec(), spec.action_labels()),
     283             :     atermpp::aterm_appl(core::detail::function_symbol_ActionRenameRules(), atermpp::aterm_list(rules.begin(), rules.end()))
     284             :   );
     285             : }
     286             : 
     287             : }
     288             : }
     289             : 
     290             : 
     291             : namespace mcrl2
     292             : {
     293             : 
     294             : namespace lps
     295             : {
     296             : 
     297             : /// \cond INTERNAL_DOCS
     298             : namespace detail
     299             : {
     300             : // Put the equalities t==u in the replacement map as u:=t.
     301          11 : inline void fill_replacement_map(const data::data_expression& equalities_in_conjunction, 
     302             :                                  std::map<data::data_expression, data::data_expression>& replacement_map)
     303             : {
     304          11 :   if (equalities_in_conjunction==data::sort_bool::true_())
     305             :   {
     306           0 :     return;
     307             :   }
     308          11 :   if (data::sort_bool::is_and_application(equalities_in_conjunction))
     309             :   {
     310           2 :     fill_replacement_map(data::sort_bool::left(equalities_in_conjunction),replacement_map);
     311           2 :     fill_replacement_map(data::sort_bool::right(equalities_in_conjunction),replacement_map);
     312           2 :     return;
     313             :   }
     314           9 :   if(is_equal_to_application(equalities_in_conjunction))
     315             :   { 
     316           6 :     const data::application a=atermpp::down_cast<data::application>(equalities_in_conjunction);
     317           6 :     if (a[1]!=a[0])
     318             :     {
     319           3 :       replacement_map[a[1]]=a[0];
     320             :     }
     321           6 :   }
     322             : }
     323             : 
     324             : // Replace expressions in e according to the replacement map.
     325             : // Assume that e only consists of and, not and equality applied to terms. 
     326          30 : inline data::data_expression replace_expressions(const data::data_expression& e, 
     327             :                                     const std::map<data::data_expression, data::data_expression>& replacement_map)
     328             : {
     329          30 :   if (data::sort_bool::is_and_application(e))
     330             :   {
     331           8 :     return data::sort_bool::and_(replace_expressions(data::sort_bool::left(e),replacement_map),
     332          12 :                            replace_expressions(data::sort_bool::right(e),replacement_map));
     333             :   }
     334          26 :   if (data::sort_bool::is_not_application(e))
     335             :   {
     336           1 :     return data::sort_bool::not_(replace_expressions(data::sort_bool::arg(e),replacement_map));
     337             :   }
     338          25 :   if (is_equal_to_application(e))
     339             :   {
     340           7 :     const data::application a=atermpp::down_cast<data::application>(e);
     341          14 :     return data::application(a.head(),
     342          14 :                        replace_expressions(a[0],replacement_map),
     343          21 :                        replace_expressions(a[1],replacement_map));
     344           7 :   }
     345          18 :   const std::map<data::data_expression, data::data_expression>::const_iterator i=replacement_map.find(e);
     346          18 :   if (i!=replacement_map.end()) // found;
     347             :   {
     348           0 :     return i->second;
     349             :   }
     350          18 :   return e;
     351             : }
     352             : 
     353             : // Substitute the equalities in equalities_in_conjunction from right to left in e. 
     354           7 : inline data::data_expression substitute_equalities(const data::data_expression& e, const data::data_expression& equalities_in_conjunction)
     355             : {
     356           7 :   std::map<data::data_expression, data::data_expression> replacement_map;
     357           7 :   fill_replacement_map(equalities_in_conjunction, replacement_map);
     358          14 :   return replace_expressions(e,replacement_map);
     359           7 : }
     360             : 
     361             : /// \brief Renames variables
     362             : /// \param rcond A data expression
     363             : /// \param rleft An action
     364             : /// \param rright An action
     365             : /// \param generator A generator for fresh identifiers
     366             : template <typename IdentifierGenerator>
     367          10 : void rename_renamerule_variables(data::data_expression& rcond, process::action& rleft, process::action& rright, IdentifierGenerator& generator)
     368             : {
     369          10 :   data::mutable_map_substitution<> renamings;
     370             : 
     371          10 :   std::set< data::variable > new_vars = data::find_all_variables(rleft.arguments());
     372             : 
     373          17 :   for (const data::variable& v: new_vars)
     374             :   {
     375           7 :     mcrl2::core::identifier_string new_name = generator(std::string(v.name()));
     376             : 
     377           7 :     if (new_name != v.name())
     378             :     {
     379           2 :       renamings[v] = data::variable(new_name, v.sort());
     380             :     }
     381             :   }
     382             : 
     383          10 :   data::set_identifier_generator id_generator;
     384          12 :   for (const data::variable& v: data::substitution_variables(renamings))
     385             :   {
     386           2 :     id_generator.add_identifier(v.name());
     387             :   }
     388          10 :   rcond = data::replace_variables_capture_avoiding(rcond, renamings, id_generator);
     389          10 :   rleft = process::replace_variables_capture_avoiding(rleft, renamings, id_generator);
     390          10 :   rright = process::replace_variables_capture_avoiding(rright, renamings, id_generator);
     391          10 : }
     392             : 
     393             : /* ------------------------------------------ Normalise sorts ------------------------------------------ */
     394             : 
     395             : inline
     396           6 : void normalize_sorts(action_rename_specification& arspec)
     397             : {
     398           6 :   arspec.action_labels()=process::normalize_sorts(arspec.action_labels(), arspec.data());
     399             : 
     400          16 :   for (action_rename_rule& rule: arspec.rules())
     401             :   {
     402          20 :     rule = action_rename_rule(data::normalize_sorts(rule.variables(), arspec.data()),
     403          20 :                               data::normalize_sorts(rule.condition(), arspec.data()),
     404          20 :                               process::normalize_sorts(rule.lhs(), arspec.data()),
     405          30 :                               process::normalize_sorts(rule.rhs(), arspec.data()));
     406             :   }
     407           6 : }
     408             : 
     409             : 
     410             : /* ------------------------------------------ Translate user notation ------------------------------------------ */
     411             : 
     412             : inline
     413           6 : void translate_user_notation(action_rename_specification& arspec)
     414             : {
     415          16 :   for (action_rename_rule& rule: arspec.rules())
     416             :   {
     417          20 :     rule = action_rename_rule(rule.variables(),
     418          20 :                               data::translate_user_notation(rule.condition()),
     419          20 :                               process::translate_user_notation(rule.lhs()),
     420          30 :                               process::translate_user_notation(rule.rhs()));
     421             :   }
     422           6 : }
     423             : 
     424             : } // namespace detail
     425             : /// \endcond
     426             : 
     427             : /// \brief  Rename the actions in a linear specification using a given action_rename_spec
     428             : /// \details The actions in a linear specification are renamed according to a given
     429             : ///         action rename specification.
     430             : ///         Note that the rules are applied in the order they appear in the specification.
     431             : ///         This yield quite elaborate conditions in the resulting lps, as a latter rule
     432             : ///         can only be applied if an earlier rule is not applicable. Note also that
     433             : ///         there is always a default summand, where the action is not renamed. Using
     434             : ///         sum elimination and rewriting a substantial reduction of the conditions that
     435             : ///         are generated can be obtained, often allowing many summands to be removed.
     436             : /// \param  action_rename_spec The action_rename_specification to be used.
     437             : /// \param  lps_old_spec The input linear specification.
     438             : /// \param  rewr A data rewriter.
     439             : /// \return The lps_old_spec where all actions have been renamed according
     440             : ///         to action_rename_spec.
     441             : inline
     442           6 : lps::stochastic_specification action_rename(
     443             :   const action_rename_specification& action_rename_spec,
     444             :   const lps::stochastic_specification& lps_old_spec,
     445             :   const data::rewriter& rewr,
     446             :   const bool enable_rewriting)
     447             : {
     448             :   using namespace mcrl2::core;
     449             :   using namespace mcrl2::data;
     450             :   using namespace mcrl2::lps;
     451             : 
     452           6 :   const std::vector <action_rename_rule>& rename_rules = action_rename_spec.rules();
     453           6 :   stochastic_action_summand_vector lps_old_action_summands = lps_old_spec.process().action_summands();
     454           6 :   deadlock_summand_vector lps_deadlock_summands = lps_old_spec.process().deadlock_summands();
     455           6 :   process::action_list lps_new_actions;
     456             : 
     457           6 :   data::set_identifier_generator generator;
     458           6 :   generator.add_identifiers(lps::find_identifiers(lps_old_spec));
     459           6 :   generator.add_identifiers(data::function_and_mapping_identifiers(lps_old_spec.data()));
     460             : 
     461             :   //go through the rename rules of the rename file
     462           6 :   mCRL2log(log::debug) << "Rename rules found: " << rename_rules.size() << "\n";
     463          16 :   for (const action_rename_rule& r: rename_rules)
     464             :   {
     465          10 :     stochastic_action_summand_vector lps_new_action_summands;
     466             : 
     467          10 :     data_expression rule_condition = r.condition();
     468          10 :     process::action rule_old_action = r.lhs();
     469          10 :     process::action rule_new_action;
     470          10 :     process::process_expression new_element = r.rhs();
     471          10 :     if (!is_tau(new_element) && !is_delta(new_element))
     472             :     {
     473           6 :       rule_new_action =  atermpp::down_cast<process::action>(new_element);
     474             :     }
     475             : 
     476          10 :     const bool to_tau = is_tau(new_element);
     477          10 :     const bool to_delta = is_delta(new_element);
     478             : 
     479             :     // Check here that the arguments of the rule_old_action only consist
     480             :     // of uniquely occurring variables or closed terms. Furthermore, check that the variables
     481             :     // in rule_new_action and in rule_condition are a subset of those in
     482             :     // rule_old_action. This check ought to be done in the static checking
     483             :     // part of the renaming rules, but as yet it has nog been done. Ultimately
     484             :     // this check should be moved there.
     485             : 
     486             :     // first check that the arguments of rule_old_action are variables or closed
     487             :     // terms.
     488             : 
     489          22 :     for (const data_expression& rule_old_argument_i: rule_old_action.arguments())
     490             :     {
     491          17 :       if (!is_variable(rule_old_argument_i) &&
     492          17 :           (!(data::find_all_variables(rule_old_argument_i).empty())))
     493             :       {
     494           0 :         throw mcrl2::runtime_error("The arguments of the lhs " + process::pp(rule_old_action) +
     495           0 :                                    " are not variables or closed expressions");
     496             :       }
     497             :     }
     498             : 
     499             :     // Check whether the variables in rhs are included in the lefthandside.
     500          10 :     std::set < variable > variables_in_old_rule = process::find_free_variables(rule_old_action);
     501          10 :     std::set < variable > variables_in_new_rule = process::find_free_variables(rule_new_action);
     502             : 
     503          10 :     if (!includes(variables_in_old_rule.begin(),variables_in_old_rule.end(),
     504             :                   variables_in_new_rule.begin(),variables_in_new_rule.end()))
     505             :     {
     506           0 :       throw mcrl2::runtime_error("There are variables occurring in rhs " + process::pp(rule_new_action) +
     507           0 :                                  " of a rename rule not occurring in lhs " + process::pp(rule_old_action));
     508             :     }
     509             : 
     510             :     // Check whether the variables in condition are included in the lefthandside.
     511          10 :     std::set < variable > variables_in_condition = data::find_free_variables(rule_condition);
     512          10 :     if (!includes(variables_in_old_rule.begin(),variables_in_old_rule.end(),
     513             :                   variables_in_condition.begin(),variables_in_condition.end()))
     514             :     {
     515           0 :       throw mcrl2::runtime_error("There are variables occurring in the condition " + data::pp(rule_condition) +
     516           0 :                                  " of a rename rule not occurring in lhs " + process::pp(rule_old_action));
     517             :     }
     518             : 
     519             :     // check for double occurrences of variables in the lhs. Note that variables_in_old_rule
     520             :     // is empty at the end.
     521          22 :     for (const data_expression& d: rule_old_action.arguments())
     522             :     {
     523          12 :       if (is_variable(d))
     524             :       {
     525           7 :         const variable& v = atermpp::down_cast<variable>(d);
     526           7 :         if (variables_in_old_rule.find(v)==variables_in_old_rule.end())
     527             :         {
     528           0 :           throw mcrl2::runtime_error("Variable " + data::pp(v) + " occurs more than once in lhs " +
     529           0 :                                      process::pp(rule_old_action) + " of an action rename rule");
     530             :         }
     531             :         else
     532             :         {
     533           7 :           variables_in_old_rule.erase(v);
     534             :         }
     535             :       }
     536             :     }
     537          10 :     assert(variables_in_old_rule.empty());
     538             : 
     539             : 
     540             :     //go through the summands of the old lps
     541          10 :     mCRL2log(log::debug) << "Action summands found: " << lps_old_action_summands.size() << "\n";
     542          35 :     for (const stochastic_action_summand& lps_old_action_summand: lps_old_action_summands)
     543             :     {
     544          25 :       process::action_list lps_old_actions = lps_old_action_summand.multi_action().actions();
     545             : 
     546             :       /* For each individual action in the multi-action, for which the
     547             :          rename rule applies, two new summands must be made, namely one
     548             :          where the rule does not match with the parameters of the action,
     549             :          and one where it actually does. This means that for a multiaction
     550             :          with k summands 2^k new summands can result. */
     551             : 
     552             :       std::vector < variable_list >
     553          25 :       lps_new_sum_vars(1,lps_old_action_summand.summation_variables());
     554          25 :       std::vector < data_expression > lps_new_condition(1,lps_old_action_summand.condition());
     555             :       std::vector < process::action_list >
     556          50 :       lps_new_actions(1,process::action_list());
     557          25 :       std::vector < bool > lps_new_actions_is_delta(1,false);
     558             : 
     559          25 :       mCRL2log(log::debug) << "Actions in summand found: " << lps_old_actions.size() << "\n";
     560          50 :       for (const process::action& lps_old_action: lps_old_actions)
     561             :       {
     562          25 :         if (equal_signatures(lps_old_action, rule_old_action))
     563             :         {
     564          10 :           mCRL2log(log::debug) << "Renaming action " << rule_old_action << "\n";
     565             : 
     566             :           //rename all previously used variables.
     567          10 :           data_expression renamed_rule_condition=rule_condition;
     568          10 :           process::action renamed_rule_old_action=rule_old_action;
     569          10 :           process::action renamed_rule_new_action=rule_new_action;
     570          10 :           detail::rename_renamerule_variables(renamed_rule_condition, renamed_rule_old_action, renamed_rule_new_action, generator);
     571             : 
     572             :           //go through the arguments of the action.
     573          10 :           data_expression_list::iterator lps_old_argument_i = lps_old_action.arguments().begin();
     574          10 :           data_expression new_equalities_condition=sort_bool::true_();
     575          22 :           for (const data_expression& rule_old_argument_i: renamed_rule_old_action.arguments())
     576             :           {
     577          12 :             if (is_variable(rule_old_argument_i))
     578             :             {
     579          14 :               new_equalities_condition=lazy::and_(new_equalities_condition,
     580          21 :                                                   data::equal_to(rule_old_argument_i, *lps_old_argument_i));
     581             :             }
     582             :             else
     583             :             {
     584           5 :               assert((data::find_all_variables(rule_old_argument_i).empty())); // the argument must be closed, which is checked above.
     585             :               renamed_rule_condition=
     586          10 :                   lazy::and_(renamed_rule_condition,
     587          15 :                            data::equal_to(rule_old_argument_i, *lps_old_argument_i));
     588           5 :               if (enable_rewriting) renamed_rule_condition=rewr(renamed_rule_condition);  // Make sure that renamed_rule_condition is as simple as possible. 
     589             :             }
     590          12 :             lps_old_argument_i++;
     591             :           }
     592             : 
     593             :           /* insert the new equality condition in all the newly generated summands */
     594          20 :           for (data_expression& d: lps_new_condition)
     595             :           {
     596          10 :             d=lazy::and_(d,new_equalities_condition);
     597             :           }
     598             : 
     599             :           /* insert the new sum variables in all the newly generated summands */
     600          10 :           std::set<variable> new_vars = find_all_variables(renamed_rule_old_action);
     601          17 :           for (const variable& sdvi: new_vars)
     602             :           {
     603          14 :             for (variable_list& l: lps_new_sum_vars)
     604             :             {
     605           7 :               l.push_front(sdvi);
     606             :             }
     607             :           }
     608             : 
     609          10 :           if (enable_rewriting) renamed_rule_condition=rewr(renamed_rule_condition);  // Make sure that renamed_rule_condition is as simple as possible. 
     610          10 :           if (renamed_rule_condition==sort_bool::true_())
     611             :           {
     612           3 :             if (to_delta)
     613             :             {
     614           0 :               std::vector < bool >::iterator i_is_delta=lps_new_actions_is_delta.begin();
     615           0 :               for (process::action_list& l: lps_new_actions)
     616             :               {
     617           0 :                 l=process::action_list(); // the action becomes delta
     618           0 :                 *i_is_delta=true;
     619           0 :                 ++i_is_delta;
     620             :               }
     621             :             }
     622           3 :             else if (!to_tau)
     623             :             {
     624           3 :               std::vector < bool >::iterator i_is_delta=lps_new_actions_is_delta.begin();
     625           6 :               for (process::action_list& l: lps_new_actions)
     626             :               {
     627           3 :                 if (!*i_is_delta) // the action is not delta
     628             :                 {
     629           3 :                   l.push_front(renamed_rule_new_action);
     630             :                 }
     631           3 :                 ++i_is_delta;
     632             :               }
     633             :             }
     634             :           }
     635           7 :           else if (renamed_rule_condition==sort_bool::false_())
     636             :           {
     637           0 :             std::vector < bool >::iterator i_is_delta=lps_new_actions_is_delta.begin();
     638           0 :             for (process::action_list& l: lps_new_actions)
     639             :             {
     640           0 :               if (!*i_is_delta) // The action does not equal delta.
     641             :               {
     642           0 :                 l.push_front(lps_old_action);
     643             :               }
     644           0 :               ++i_is_delta;
     645             :             }
     646             : 
     647             :           }
     648             :           else
     649             :           {
     650             :             /* Duplicate summands, one where the renaming is applied, and one where it is not
     651             :                applied. */
     652             : 
     653           7 :             std::vector < process::action_list > lps_new_actions_temp(lps_new_actions);
     654             : 
     655           7 :             if (!to_tau) // if the new element is tau, we do not insert it in the multi-action.
     656             :             {
     657           6 :               std::vector < bool >::iterator i_is_delta=lps_new_actions_is_delta.begin();
     658          12 :               for (process::action_list& l: lps_new_actions)
     659             :               {
     660           6 :                 if (to_delta)
     661             :                 {
     662           3 :                   l=process::action_list();
     663           3 :                   *i_is_delta=true;
     664             :                 }
     665             :                 else
     666             :                 {
     667           3 :                   l.push_front(renamed_rule_new_action);
     668           3 :                   *i_is_delta=false;
     669             :                 }
     670           6 :                 ++i_is_delta;
     671             :               }
     672             :             }
     673             : 
     674          14 :             for (process::action_list& l: lps_new_actions_temp)
     675             :             {
     676           7 :               lps_new_actions_is_delta.push_back(false); // A non renamed action is not delta;
     677           7 :               l.push_front(lps_old_action);
     678             :             }
     679             : 
     680           7 :             lps_new_actions.insert(lps_new_actions.end(),
     681             :                                    lps_new_actions_temp.begin(),
     682             :                                    lps_new_actions_temp.end());
     683           7 :             assert(lps_new_actions_is_delta.size()==lps_new_actions.size());
     684             : 
     685             :             /* lps_new_condition_temp will contain the conditions in conjunction with
     686             :                the negated new_condition. It will be concatenated to lps_new_condition,
     687             :                in which the terms will be conjoined with the non-negated new_condition */
     688             : 
     689           7 :             std::vector < data_expression > lps_new_condition_temp(lps_new_condition);
     690             : 
     691          14 :             for (data_expression& d: lps_new_condition)
     692             :             {
     693             :               // substitute the equalities in d in renamed_rule_condition. 
     694           7 :               d=lazy::and_(renamed_rule_condition,detail::substitute_equalities(d,renamed_rule_condition));
     695             :             }
     696             : 
     697          14 :             for (const data_expression& d: lps_new_condition_temp)
     698             :             {
     699             : 
     700           7 :               lps_new_condition.push_back(lazy::and_(d,sort_bool::not_(renamed_rule_condition)));
     701             :             }
     702             : 
     703             :             // Replace lps_new_sum_vars with two consecutive copies of itself. 
     704             :             // The clumsily looking method below is required, to avoid problems with vector reallocation.
     705           7 :             std::size_t size=lps_new_sum_vars.size();
     706           7 :             lps_new_sum_vars.reserve(2*size);
     707          14 :             for(std::size_t i=0; i<size; ++i)
     708             :             {
     709           7 :               lps_new_sum_vars.push_back(lps_new_sum_vars[i]);
     710             :             }
     711           7 :           }
     712          10 :         }//end if(equal_signatures(...))
     713             :         else
     714             :         {
     715          30 :           for (process::action_list& l: lps_new_actions)
     716             :           {
     717          15 :             l.push_front(lps_old_action);
     718             :           }
     719             :         }
     720          25 :         mCRL2log(log::debug) << "Action done\n";
     721             : 
     722             :       } //end of action list iterator
     723             : 
     724             :       /* Add the summands to lps_new_action_summands or to the deadlock summands*/
     725             : 
     726          25 :       std::vector < process::action_list > :: iterator i_act=lps_new_actions.begin();
     727          25 :       std::vector < bool > :: iterator i_act_is_delta=lps_new_actions_is_delta.begin();
     728          25 :       std::vector < variable_list > :: iterator i_sumvars=lps_new_sum_vars.begin();
     729          57 :       for (const data_expression& cond: lps_new_condition)
     730             :       {
     731             :         //create a summand for the new lps
     732          32 :         if (*i_act_is_delta)
     733             :         {
     734             :           // Create a deadlock summand.
     735           3 :           const deadlock_summand d(*i_sumvars,
     736             :                                    cond,
     737           9 :                                    deadlock(lps_old_action_summand.multi_action().time()));
     738           3 :           lps_deadlock_summands.push_back(d);
     739           3 :         }
     740             :         else
     741             :         {
     742             :           // create an action summand.
     743          29 :           stochastic_action_summand lps_new_summand(*i_sumvars,
     744             :                                                     cond,
     745          58 :                                                     multi_action(reverse(*i_act), lps_old_action_summand.multi_action().time()),
     746             :                                                     lps_old_action_summand.assignments(),
     747          58 :                                                     lps_old_action_summand.distribution());
     748          29 :           lps_new_action_summands.push_back(lps_new_summand);
     749          29 :         }
     750          32 :         i_act++;
     751          32 :         i_sumvars++;
     752          32 :         ++i_act_is_delta;
     753             :       }
     754          25 :     } // end of summand list iterator
     755          10 :     lps_old_action_summands = lps_new_action_summands;
     756          10 :   } //end of rename rule iterator
     757             : 
     758           6 :   mCRL2log(log::debug) << "Simplifying the result...\n";
     759             : 
     760           6 :   stochastic_linear_process new_process(lps_old_spec.process().process_parameters(),
     761             :                                         lps_deadlock_summands,
     762           6 :                                         lps_old_action_summands);
     763             : 
     764             :   // add action_rename_spec.action_labels to action_rename_spec.action_labels without adding duplicates.
     765           6 :   process::action_label_list all=action_rename_spec.action_labels();
     766          21 :   for (const process::action_label& a: lps_old_spec.action_labels())
     767             :   {
     768          15 :     if (std::find(action_rename_spec.action_labels().begin(),
     769          30 :                   action_rename_spec.action_labels().end(),a)==action_rename_spec.action_labels().end())
     770             :     {
     771             :       // Not found;
     772          15 :       all.push_front(a);
     773             :     }
     774             :   }
     775             :   stochastic_specification lps_new_spec(action_rename_spec.data(), // This contains the data of the lps and the rename file.
     776             :                                         all,
     777             :                                         lps_old_spec.global_variables(),
     778             :                                         new_process,
     779           6 :                                         lps_old_spec.initial_process());
     780             : 
     781           6 :   mCRL2log(log::debug) << "New lps complete\n";
     782          12 :   return lps_new_spec;
     783           6 : } //end of rename(...)
     784             : 
     785             : namespace detail
     786             : {
     787             : 
     788             : inline
     789          30 : process::action_label rename_action_label(const process::action_label& act, const std::regex& matching_regex, const std::string& replacing_fmt)
     790             : {
     791          60 :   return process::action_label(std::regex_replace(std::string(act.name()), matching_regex, replacing_fmt), act.sorts());
     792             : }
     793             : 
     794             : } // namespace detail
     795             : 
     796             : /**
     797             :  * \brief Rename actions in given specification based on a regular expression and
     798             :  * a string that specifies how the replacement should be formatted.
     799             :  */
     800             : inline
     801           4 : stochastic_specification action_rename(
     802             :   const std::regex& matching_regex,
     803             :   const std::string& replacing_fmt,
     804             :   const stochastic_specification& lps_old_spec)
     805             : {
     806             :   // Use a set to store the new action labels to avoid duplicates
     807           4 :   std::set<process::action_label> new_actions_set;
     808           4 :   process::action_label_list new_actions;
     809          21 :   for(const process::action_label& act: lps_old_spec.action_labels())
     810             :   {
     811          17 :     process::action_label new_action_label(detail::rename_action_label(act, matching_regex, replacing_fmt));
     812          17 :     if (std::string(new_action_label.name()).empty())
     813             :     {
     814           0 :       throw mcrl2::runtime_error("After renaming the action " + std::string(act.name()) + " becomes empty, which is not allowed.");
     815             :     }
     816          48 :     if(std::string(new_action_label.name()) != "delta" && std::string(new_action_label.name()) != "tau" &&
     817          31 :         new_actions_set.find(new_action_label) == new_actions_set.end())
     818             :     {
     819             :       // The list of actions should not contain delta and tau actions and also no duplicates.
     820          13 :       new_actions_set.insert(new_action_label);
     821          13 :       new_actions.push_front(new_action_label);
     822             :     }
     823          17 :   }
     824           4 :   new_actions = reverse(new_actions);
     825             : 
     826             :   // The list of new actions summands is initially empty
     827           4 :   std::vector<stochastic_action_summand> new_action_summands;
     828             :   // The list of new deadlock summands is initialised to the existing list, we will only add new deadlock summands
     829           4 :   std::vector<deadlock_summand> new_deadlock_summands(lps_old_spec.process().deadlock_summands());
     830          15 :   for(const stochastic_action_summand& as: lps_old_spec.process().action_summands())
     831             :   {
     832          11 :     process::action_list new_action_list;
     833          11 :     bool becomes_deadlock_summand = false;
     834          23 :     for(const process::action& act: as.multi_action().actions())
     835             :     {
     836          13 :       process::action_label new_action_label(detail::rename_action_label(act.label(), matching_regex, replacing_fmt));
     837          13 :       if(std::string(new_action_label.name()) == "delta")
     838             :       {
     839             :         // delta is the absorbing element for multi action concatenation
     840             :         // Therefore, this summand now becomes a deadlock summand
     841           1 :         becomes_deadlock_summand = true;
     842           1 :         break;
     843             :       }
     844             :       // tau is the identity for multi action concatenation
     845             :       // therefore, we should not add it to a multi action
     846          12 :       if(std::string(new_action_label.name()) != "tau")
     847             :       {
     848          10 :         new_action_list.push_front(process::action(new_action_label, act.arguments()));
     849             :       }
     850          13 :     }
     851             : 
     852          11 :     if(!becomes_deadlock_summand)
     853             :     {
     854          10 :       new_action_list = reverse(new_action_list);
     855          10 :       multi_action new_multi_action(new_action_list, as.multi_action().time());
     856             : 
     857             :       // Copy most of the old information, only the multi action has changed
     858          10 :       stochastic_action_summand new_summand(as.summation_variables(), as.condition(), new_multi_action, as.assignments(), as.distribution());
     859          10 :       new_action_summands.push_back(new_summand);
     860          10 :     }
     861             :     else
     862             :     {
     863             :       // Add a new deadlock summand, copying most of the information for the old action summand
     864           1 :       new_deadlock_summands.push_back(deadlock_summand(as.summation_variables(), as.condition(), deadlock(as.multi_action().time())));
     865             :     }
     866          11 :   }
     867             : 
     868           4 :   stochastic_linear_process new_process(lps_old_spec.process().process_parameters(),
     869             :                                         new_deadlock_summands,
     870           4 :                                         new_action_summands);
     871             :   stochastic_specification lps_new_spec(lps_old_spec.data(),
     872             :                                         new_actions,
     873             :                                         lps_old_spec.global_variables(),
     874             :                                         new_process,
     875           4 :                                         lps_old_spec.initial_process());
     876           8 :   return lps_new_spec;
     877           4 : }
     878             : 
     879             : } // namespace lps
     880             : 
     881             : } // namespace mcrl2
     882             : 
     883             : namespace std
     884             : {
     885             : /// \brief Output an action_rename_rule to ostream. 
     886             : /// \param out An output stream
     887             : /// \return The output stream
     888             : // Currently, the variables are not printed. The shape is also not parseable. This may be mended. 
     889             : inline
     890             : std::ostream& operator<<(std::ostream& out, const mcrl2::lps::action_rename_rule& r)
     891             : {
     892             :   return out << "(" << r.condition() << ") -> " << r.lhs() << " => " << r.rhs();
     893             : }
     894             : 
     895             : /// \brief Output a action_rename_rule to ostream. 
     896             : /// \param out An output stream
     897             : /// \return The output stream
     898             : // Currently, the data declaration and the action declaration are not printed. 
     899             : inline
     900             : std::ostream& operator<<(std::ostream& out, const mcrl2::lps::action_rename_specification& s)
     901             : {
     902             :   for(const mcrl2::lps::action_rename_rule& r: s.rules())
     903             :   {
     904             :     out << r << "\n";
     905             :   }
     906             :   return out;
     907             : }
     908             : 
     909             : 
     910             : }  // end namespace std
     911             : 
     912             : 
     913             : #endif // MCRL2_LPS_ACTION_RENAME_H

Generated by: LCOV version 1.14