LCOV - code coverage report
Current view: top level - lps/include/mcrl2/lps - binary.h (source / functions) Hit Total Coverage
Test: mcrl2_coverage.info.cleaned Lines: 153 162 94.4 %
Date: 2024-04-21 03:44:01 Functions: 13 25 52.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Author(s): Jeroen Keiren
       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 binary.h
      10             : /// \brief The binary algorithm.
      11             : 
      12             : #ifndef MCRL2_LPS_BINARY_H
      13             : #define MCRL2_LPS_BINARY_H
      14             : 
      15             : #include "mcrl2/data/enumerator.h"
      16             : #include "mcrl2/lps/detail/lps_algorithm.h"
      17             : #include "mcrl2/lps/detail/parameter_selection.h"
      18             : 
      19             : namespace mcrl2
      20             : {
      21             : 
      22             : namespace lps
      23             : {
      24             : 
      25             : // Compute the number of booleans needed to represent a set of size n.
      26             : inline
      27          13 : std::size_t nr_of_booleans_for_elements(std::size_t n)
      28             : {
      29          13 :   if(n == 1)
      30             :   {
      31           0 :     return 1;
      32             :   }
      33             :   else
      34             :   {
      35          13 :     return utilities::ceil_log2(n-1);
      36             :   }
      37             : }
      38             : 
      39             : /// \brief Algorithm class that can be used to apply the binary algorithm
      40             : ///
      41             : /// All parameters of finite data types are replaced with a vector of
      42             : /// booleans.
      43             : template<typename DataRewriter, typename Specification>
      44             : class binary_algorithm: public detail::lps_algorithm<Specification>
      45             : {
      46             :   typedef data::enumerator_list_element_with_substitution<> enumerator_element;
      47             :   typedef typename detail::lps_algorithm<Specification> super;
      48             :   typedef typename Specification::process_type process_type;
      49             :   typedef typename process_type::action_summand_type action_summand_type;
      50             :   using super::m_spec;
      51             : 
      52             :   protected:
      53             :     /// Rewriter
      54             :     DataRewriter m_rewriter;
      55             : 
      56             :     const std::string m_parameter_selection;
      57             : 
      58             :     /// Mapping of finite variables to boolean vectors
      59             :     std::map<data::variable, std::vector<data::variable> > m_new_parameters;
      60             : 
      61             :     /// Mapping of variables to all values they can be assigned
      62             :     std::map<data::variable, std::vector<data::data_expression> > m_enumerated_elements;
      63             : 
      64             :     /// Mapping of variables to corresponding if-tree
      65             :     data::mutable_map_substitution<> m_if_trees;
      66             : 
      67             :     /// Contains the names of variables appearing in rhs of m_if_trees
      68             :     data::set_identifier_generator m_if_trees_generator;
      69             : 
      70             :     /// Identifier generator for the enumerator
      71             :     data::enumerator_identifier_generator m_id_generator;
      72             : 
      73             :     /// \brief Build an if-then-else tree of enumerated elements in terms
      74             :     ///        of new parameters.
      75             :     /// \pre enumerated_elements.size() <= 2^new_parameters.size()
      76             :     /// \return if then else tree from enumerated_elements in terms of new_parameters
      77         107 :     data::data_expression make_if_tree(data::variable_vector new_parameters,
      78             :                                        const data::data_expression_vector& enumerated_elements)
      79             :     {
      80         107 :       data::data_expression result;
      81             : 
      82         107 :       if (new_parameters.empty())
      83             :       {
      84          60 :         result = enumerated_elements.front();
      85             :       }
      86             :       else
      87             :       {
      88          47 :         std::size_t n = enumerated_elements.size();
      89          47 :         std::size_t m = static_cast<std::size_t>(1) << (new_parameters.size() - 1);  //m == 2^(new_parameters.size() - 1)
      90             : 
      91          47 :         if (m > n)
      92             :         {
      93           3 :           m = n;
      94             :         }
      95             : 
      96          47 :         data::data_expression_vector left_list(enumerated_elements.begin(), enumerated_elements.begin() + m);
      97          47 :         data::data_expression_vector right_list;
      98          47 :         if (m == n)
      99             :         {
     100          10 :           right_list = data::data_expression_vector(enumerated_elements.begin() + m - 1, enumerated_elements.end());
     101             :         }
     102             :         else
     103             :         {
     104          37 :           right_list = data::data_expression_vector(enumerated_elements.begin() + m, enumerated_elements.end());
     105             :         }
     106             : 
     107          47 :         data::data_expression condition = new_parameters.back();
     108          47 :         new_parameters.pop_back();
     109          47 :         result = if_(condition,
     110             :                      make_if_tree(new_parameters, right_list),
     111             :                      make_if_tree(new_parameters, left_list));
     112          47 :       }
     113             : 
     114         107 :       return result;
     115           0 :     }
     116             : 
     117             :     /// \brief Determine which variables should be replaced, based on parameter_selection
     118             :     /// \return A subset of the process parameters, with a finite sort that is not Bool
     119           9 :     std::set<data::variable> select_parameters(const std::string parameter_selection) const
     120             :     {
     121           9 :       const data::variable_list& process_parameters = m_spec.process().process_parameters();
     122           9 :       bool use_selection = !parameter_selection.empty();
     123             : 
     124           9 :       std::list<data::variable> selected_params;
     125           9 :       if (use_selection)
     126             :       {
     127           1 :         const data::variable_vector sel = 
     128           1 :                    detail::parse_lps_parameter_selection(process_parameters, m_spec.data(), parameter_selection);
     129           1 :         selected_params = std::list<data::variable>(sel.begin(), sel.end());
     130           1 :       }
     131             :       else
     132             :       {
     133           8 :         selected_params = std::list<data::variable>(process_parameters.begin(), process_parameters.end());
     134             :       }
     135           9 :       selected_params.remove_if([&](const data::variable& v)
     136             :         {
     137          22 :           bool cannot_replace = v.sort() == data::sort_bool::bool_() || !m_spec.data().is_certainly_finite(v.sort());
     138          22 :           if (cannot_replace && use_selection)
     139             :           {
     140           0 :             mCRL2log(log::info) << "Not selecting " << v  << ":" << v.sort() << " since it is already Bool, or its type is not finite." << std::endl;
     141             :           }
     142          22 :           return cannot_replace;
     143             :         }
     144             :       );
     145             : 
     146           9 :       if (use_selection && selected_params.empty())
     147             :       {
     148           0 :         mCRL2log(log::info) << "No parameters were selected to be replaced." << std::endl;
     149             :       }
     150             : 
     151          18 :       return std::set<data::variable>(selected_params.begin(), selected_params.end());
     152           9 :     }
     153             : 
     154             :     /// \brief Take a specification and calculate a vector of boolean variables for each process
     155             :     /// parameter in selected_params. A mapping variable -> vector of booleans is stored in new_parameters_table
     156             :     /// a mapping variable -> enumerated elements is stored in enumerated_elements_table
     157             :     /// \pre all elements in selected_params should not be of type Bool and should have a finite type
     158             :     /// \return data variable list with the new process parameters (i.e. with all variables of a
     159             :     /// finite type != bool replaced by a vector of boolean variables.
     160           9 :     void replace_enumerated_parameters(const std::set<data::variable>& selected_params)
     161             :     {
     162           9 :       data::variable_list process_parameters = m_spec.process().process_parameters();
     163           9 :       data::variable_vector new_parameters;
     164             : 
     165           9 :       mCRL2log(log::debug) << "Original process parameters: " << data::pp(process_parameters) << std::endl;
     166             : 
     167           9 :       data::set_identifier_generator generator;
     168           9 :       generator.add_identifiers(lps::find_identifiers(m_spec));
     169           9 :       generator.add_identifiers(data::function_and_mapping_identifiers(m_spec.data()));
     170           9 :       bool accept_solutions_with_variables = false;
     171           9 :       data::enumerator_algorithm<> enumerator(m_rewriter, m_spec.data(), m_rewriter, m_id_generator, accept_solutions_with_variables);
     172             : 
     173             :       // Transpose all process parameters, and replace those that are finite, and not bool with boolean variables.
     174          42 :       for (const data::variable& par: process_parameters)
     175             :       {
     176          24 :         if (selected_params.find(par) != selected_params.end())
     177             :         {
     178             :           //Get all constructors for par
     179          13 :           data::data_expression_vector enumerated_elements; // List to store enumerated elements of a parameter
     180             : 
     181          13 :           data::mutable_indexed_substitution<> local_sigma;
     182          26 :           const data::variable_list vl{ par };
     183          13 :           enumerator.enumerate(enumerator_element(vl, data::sort_bool::true_()),
     184             :                                local_sigma,
     185         100 :                                [&](const enumerator_element& p)
     186             :                                {
     187          50 :                                  p.add_assignments(vl, local_sigma, m_rewriter);
     188          50 :                                  enumerated_elements.push_back(local_sigma(par));
     189          50 :                                  return false;
     190             :                                }
     191             :           );
     192          13 :           m_enumerated_elements[par] = enumerated_elements;
     193             : 
     194             :           //Calculate the number of booleans needed to encode par
     195          13 :           std::size_t n = nr_of_booleans_for_elements(enumerated_elements.size());
     196             : 
     197             :           //Set hint for fresh variable names
     198          13 :           std::string par_name = par.name();
     199             : 
     200             :           // Temp list for storage
     201          13 :           data::variable_vector new_pars;
     202             :           //Create new parameters and add them to the parameter list.
     203          36 :           for (std::size_t i = 0; i<n; ++i)
     204             :           {
     205          23 :             data::variable v(generator(par_name), data::sort_bool::bool_());
     206          23 :             new_parameters.push_back(v);
     207          23 :             new_pars.push_back(v);
     208             :           }
     209             :           // n = new_pars.size() && new_pars.size() = ceil(log_2(j)) && new_pars.size() = ceil(log_2(enumerated_elements.size()))
     210             : 
     211          13 :           mCRL2log(log::verbose) << "Parameter " << data::pp(par) << ":" << data::pp(par.sort()) << " has been replaced by " << new_pars.size() << " parameter(s) " << data::pp(new_pars) << " of sort Bool" << std::endl;
     212             : 
     213             :           //Store new parameters in a hastable
     214          13 :           m_new_parameters[par]=new_pars;
     215             : 
     216          13 :           m_if_trees[par]=make_if_tree(new_pars,
     217             :                                        enumerated_elements);
     218          13 :         }
     219             :         else
     220             :         {
     221          11 :           new_parameters.push_back(par);
     222             :         }
     223             :       }
     224             : 
     225           9 :       mCRL2log(log::debug) << "New process parameter(s): " << data::pp(new_parameters) << std::endl;
     226             : 
     227           9 :       m_spec.process().process_parameters() = data::variable_list(new_parameters.begin(),new_parameters.end());
     228          32 :       for (const data::variable& v: data::substitution_variables(m_if_trees))
     229             :       {
     230          23 :         m_if_trees_generator.add_identifier(v.name());
     231             :       }
     232           9 :     }
     233             : 
     234             :     /// \brief Replace expressions in v that are of a finite sort with a
     235             :     ///        vector of assignments to Boolean variables.
     236           9 :     data::data_expression_list replace_enumerated_parameters_in_initial_expressions(
     237             :                                  const data::variable_list& vl,
     238             :                                  const data::data_expression_list& el)
     239             :     {
     240             :       // We use replace_variables, to make sure that the binding variables of assignments are ignored.
     241             :       // Note that this operation is safe because the generated fresh variables can not clash with other
     242             :       // binding variables.
     243           9 :       const data::data_expression_list el_ = data::replace_variables(el, m_if_trees);
     244             : 
     245           9 :       data::data_expression_vector result;
     246           9 :       data::variable_list::const_iterator i=vl.begin();
     247          42 :       for (const data::data_expression& a: el_)
     248             :       {
     249          24 :         const data::variable par= *i;
     250          24 :         i++;
     251          24 :         if (m_new_parameters.find(par) == m_new_parameters.end())   // This parameter is not replaced by a boolean parameters.
     252             :         {
     253          11 :           result.push_back(a);
     254             :         }
     255             :         else
     256             :         {
     257          13 :           data::variable_vector new_parameters = m_new_parameters[par];
     258          13 :           data::data_expression_vector elements = m_enumerated_elements[par];
     259             : 
     260          13 :           mCRL2log(log::debug) << "Found " << new_parameters.size() << " new parameter(s) for parameter " << data::pp(par) << std::endl;
     261             : 
     262          36 :           for (std::size_t j = 0; j < new_parameters.size(); ++j)
     263             :           {
     264          23 :             data::data_expression_vector disjuncts;
     265             : 
     266          23 :             data::data_expression_vector::iterator k = elements.begin();
     267          65 :             while (k != elements.end())
     268             :             {
     269             :               // Elements that get boolean value false
     270          42 :               std::ptrdiff_t count(static_cast<std::ptrdiff_t>(1) << j);
     271          42 :               if (std::distance(k, elements.end()) < count)
     272             :               {
     273           2 :                 k = elements.end();
     274             :               }
     275             :               else
     276             :               {
     277          40 :                 std::advance(k, count);
     278             :               }
     279             : 
     280             :               // Elements that get value true
     281          95 :               for (std::ptrdiff_t l = 0; l < count && k != elements.end(); ++l)
     282             :               {
     283          53 :                 disjuncts.push_back(data::equal_to(a, *k++));
     284             :               }
     285             :             }
     286          23 :             result.push_back(data::lazy::join_or(disjuncts.begin(), disjuncts.end()));
     287             :           }
     288          13 :         }
     289             :       }
     290             : 
     291           9 :       mCRL2log(log::debug) << "Replaced expression(s) " << data::pp(el_) << " in the initial state with expression(s) " << data::pp(result) << std::endl;
     292             : 
     293          18 :       return data::data_expression_list(result.begin(),result.end());
     294           9 :     }
     295             : 
     296             :     /// \brief Replace assignments in v that are of a finite sort with a
     297             :     ///        vector of assignments to Boolean variables.
     298          19 :     data::assignment_list replace_enumerated_parameters_in_assignments(data::assignment_list v)
     299             :     {
     300             :       // We use replace_variables, to make sure that the binding variables of assignments are ignored.
     301             :       // Note that this operation is safe because the generated fresh variables can not clash with other
     302             :       // binding variables.
     303          19 :       v = data::replace_variables(v, m_if_trees);
     304             : 
     305          19 :       data::assignment_vector result;
     306          88 :       for (const data::assignment& a: v)
     307             :       {
     308          50 :         if (m_new_parameters.find(a.lhs()) == m_new_parameters.end())
     309             :         {
     310          29 :           result.push_back(a);
     311             :         }
     312             :         else
     313             :         {
     314          21 :           data::variable_vector new_parameters = m_new_parameters[a.lhs()];
     315          21 :           data::data_expression_vector elements = m_enumerated_elements[a.lhs()];
     316             : 
     317          21 :           mCRL2log(log::debug) << "Found " << new_parameters.size() << " new parameter(s) for parameter " << data::pp(a.lhs()) << std::endl;
     318             : 
     319          50 :           for (std::size_t j = 0; j < new_parameters.size(); ++j)
     320             :           {
     321          29 :             data::data_expression_vector disjuncts;
     322             : 
     323          29 :             data::data_expression_vector::iterator k = elements.begin();
     324          74 :             while (k != elements.end())
     325             :             {
     326             :               // Elements that get boolean value false
     327          45 :               std::ptrdiff_t count(static_cast<std::ptrdiff_t>(1) << j);
     328          45 :               if (std::distance(k, elements.end()) < count)
     329             :               {
     330           2 :                 k = elements.end();
     331             :               }
     332             :               else
     333             :               {
     334          43 :                 std::advance(k, count);
     335             :               }
     336             : 
     337             :               // Elements that get value true
     338         100 :               for (std::ptrdiff_t l = 0; l < count && k != elements.end(); ++l)
     339             :               {
     340          55 :                 disjuncts.push_back(data::equal_to(a.rhs(), *k++));
     341             :               }
     342             :             }
     343          29 :             result.push_back(data::assignment(new_parameters[j], data::lazy::join_or(disjuncts.begin(), disjuncts.end())));
     344             :           }
     345             : 
     346          21 :         }
     347             :       }
     348             : 
     349          19 :       mCRL2log(log::debug) << "Replaced assignment(s) " << data::pp(v) << " with assignment(s) " << data::pp(result) << std::endl;
     350             : 
     351          38 :       return data::assignment_list(result.begin(),result.end());
     352          19 :     }
     353             : 
     354             :     /// \brief Update an action summand with the new Boolean parameters
     355          19 :     void update_action_summand(action_summand& s)
     356             :     {
     357          19 :       s.condition() = data::replace_variables_capture_avoiding(s.condition(), m_if_trees, m_if_trees_generator);
     358          19 :       s.multi_action()=lps::replace_variables_capture_avoiding(s.multi_action(), m_if_trees, m_if_trees_generator);
     359          19 :       s.assignments() = replace_enumerated_parameters_in_assignments(s.assignments());
     360          19 :     }
     361             : 
     362             :     /// \brief Update an action summand with the new Boolean parameters
     363             :     void update_action_summand(stochastic_action_summand& s)
     364             :     {
     365             :       update_action_summand(static_cast<action_summand&>(s));
     366             :       s.distribution() = lps::replace_variables_capture_avoiding(s.distribution(), m_if_trees, m_if_trees_generator);
     367             :     }
     368             : 
     369             :     /// \brief Update a deadlock summand with the new Boolean parameters
     370           2 :     void update_deadlock_summand(deadlock_summand& s)
     371             :     {
     372           2 :       s.condition() = data::replace_variables_capture_avoiding(s.condition(), m_if_trees, m_if_trees_generator);
     373           2 :       lps::replace_variables_capture_avoiding(s.deadlock(), m_if_trees, m_if_trees_generator);
     374           2 :     }
     375             : 
     376           9 :     process_initializer update_initial_process(const data::variable_list& parameters, const process_initializer& init)
     377             :     {
     378           9 :       return process_initializer(replace_enumerated_parameters_in_initial_expressions(parameters, init.expressions()));
     379             :     }
     380             : 
     381           0 :     stochastic_process_initializer update_initial_process(const data::variable_list& parameters, const stochastic_process_initializer& init)
     382             :     {
     383             :       /* return stochastic_process_initializer(replace_enumerated_parameters_in_initial_expressions(parameters, init.expressions()),
     384             :                                             lps::replace_variables_capture_avoiding(init.distribution(), m_if_trees, m_if_trees_generator)
     385             :                                            ); */
     386           0 :       data::data_expression_list d = replace_enumerated_parameters_in_initial_expressions(parameters, init.expressions());
     387           0 :       const stochastic_distribution dist = lps::replace_variables_capture_avoiding(init.distribution(), d, m_if_trees, m_if_trees_generator);
     388           0 :       return stochastic_process_initializer(d, dist);
     389           0 :     }
     390             : 
     391             :   public:
     392             :     /// \brief Constructor for binary algorithm
     393             :     /// \param spec Specification to which the algorithm should be applied
     394             :     /// \param r a rewriter for data
     395           9 :     binary_algorithm(Specification& spec,
     396             :                      DataRewriter& r,
     397             :                      const std::string parameter_selection = "")
     398             :       : detail::lps_algorithm<Specification>(spec),
     399           9 :         m_rewriter(r),
     400          18 :         m_parameter_selection(parameter_selection)
     401           9 :     {}
     402             : 
     403             :     /// \brief Apply the algorithm to the specification passed in the
     404             :     ///        constructor
     405           9 :     void run()
     406             :     {
     407           9 :       data::variable_list old_parameters = m_spec.process().process_parameters();
     408           9 :       const std::set<data::variable> to_replace = select_parameters(m_parameter_selection);
     409           9 :       replace_enumerated_parameters(to_replace);
     410             : 
     411             :       // Initial process
     412           9 :       mCRL2log(log::debug) << "Updating process initializer" << std::endl;
     413           9 :       m_spec.initial_process() = update_initial_process(old_parameters, m_spec.initial_process());
     414             : 
     415             :       // Summands
     416           9 :       mCRL2log(log::debug) << "Updating summands" << std::endl;
     417             : 
     418          28 :       for (action_summand& a: m_spec.process().action_summands())
     419             :       {
     420          19 :         update_action_summand(a);
     421             :       }
     422             : 
     423          11 :       for (deadlock_summand& d: m_spec.process().deadlock_summands())
     424             :       {
     425           2 :         update_deadlock_summand(d);
     426             :       }
     427           9 :     }
     428             : };
     429             : 
     430             : } // namespace lps
     431             : 
     432             : } // namespace mcrl2
     433             : 
     434             : #endif // MCRL2_LPS_BINARY_H

Generated by: LCOV version 1.14