LCOV - code coverage report
Current view: top level - pbes/include/mcrl2/pbes/detail - ppg_rewriter.h (source / functions) Hit Total Coverage
Test: mcrl2_coverage.info.cleaned Lines: 123 247 49.8 %
Date: 2024-04-19 03:43:27 Functions: 9 15 60.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Author(s): Gijs Kant
       2             : // Copyright: see the accompanying file COPYING or copy at
       3             : // https://github.com/mCRL2org/mCRL2/blob/master/COPYING
       4             : //
       5             : // Distributed under the Boost Software License, Version 1.0.
       6             : // (See accompanying file LICENSE_1_0.txt or copy at
       7             : // http://www.boost.org/LICENSE_1_0.txt)
       8             : //
       9             : /// \file mcrl2/pbes/detail/ppg_traverser.h
      10             : /// \brief Traverser class for Parameterised Parity Games (PPG), PBES expressions of the form:
      11             : /// PPG :== /\_{i: I} f_i && /\_{j: J} forall v: D_j . ( g_j => X_j(e_j) )
      12             : ///       | \/_{i: I} f_i || \/_{j: J} exists v: D_j . ( g_j && X_j(e_j) ).
      13             : #ifndef MCRL2_PBES_DETAIL_PPG_REWRITER_H
      14             : #define MCRL2_PBES_DETAIL_PPG_REWRITER_H
      15             : 
      16             : #include "mcrl2/pbes/algorithms.h"
      17             : #include "mcrl2/pbes/join.h"
      18             : #include "mcrl2/pbes/pbes_functions.h"
      19             : 
      20             : namespace mcrl2 {
      21             : 
      22             : namespace pbes_system {
      23             : 
      24             : namespace detail {
      25             : 
      26             : struct fresh_variable_name_generator
      27             : {
      28             :   /// \brief The set of variable names already in use.
      29             :   std::set<std::string> variable_names;
      30             :   /// \brief A map from variable name prefix to the last suffix that has been added.
      31             :   std::map<std::string,int> variable_name_suffix;
      32             : 
      33             :   template <typename Container>
      34           1 :   fresh_variable_name_generator(const Container& equations)
      35           1 :   {
      36           2 :     for (typename Container::const_iterator eqn = equations.begin(); eqn != equations.end(); ++eqn) {
      37           1 :       propositional_variable var = (*eqn).variable();
      38           1 :       variable_names.insert(std::string(var.name()));
      39             :     }
      40           1 :   }
      41             : 
      42             :   /// \brief Generates a fresh variable name, based on s (extending s).
      43             :   /// \param s A string.
      44             :   /// \return a fresh variable name.
      45           2 :   std::string generate_name(const std::string& s) {
      46             :     //std::clog << "fresh_variable_name: ";
      47           2 :     std::string base; std::string name;
      48           2 :     name = base = s;
      49           2 :     int suffix = 1;
      50           4 :     while (variable_names.find(name)!=variable_names.end()) {
      51           2 :       if (variable_name_suffix.find(base) != variable_name_suffix.end()) {
      52           1 :         suffix = variable_name_suffix[base] + 1;
      53             :       }
      54           2 :       variable_name_suffix[base] = suffix;
      55           2 :       std::stringstream ss;
      56           2 :       ss << base << "_" << suffix;
      57           2 :       ss >> name;
      58           2 :     }
      59           2 :     variable_names.insert(name);
      60             :     //std::clog << name << std::endl;
      61           4 :     return name;
      62           2 :   }
      63             : };
      64             : 
      65             : /// \cond INTERNAL_DOCS
      66             : /// \brief Traverser that rewrites the given PBES to PPG format.
      67             : struct ppg_rewriter: public pbes_expression_traverser<ppg_rewriter>
      68             : {
      69             :   typedef pbes_expression_traverser<ppg_rewriter> super;
      70             :   using super::enter;
      71             :   using super::leave;
      72             :   using super::apply;
      73             : 
      74             :   enum expression_mode {
      75             :     CONJUNCTIVE, UNIVERSAL,
      76             :     DISJUNCTIVE, EXISTENTIAL,
      77             :     UNDETERMINED
      78             :   };
      79             : 
      80             :   std::vector<pbes_equation> equations;
      81             :   std::stack<expression_mode> mode_stack;
      82             :   std::stack<fixpoint_symbol> symbol_stack;
      83             :   std::stack<propositional_variable> variable_stack;
      84             :   std::stack<data::variable_list> quantifier_variable_stack;
      85             :   std::stack<pbes_expression> expression_stack;
      86             :   fresh_variable_name_generator name_generator;
      87             : 
      88             :   template <typename Container>
      89           1 :   ppg_rewriter(const Container& equations)
      90           1 :     : name_generator(equations)
      91           1 :   {}
      92             : 
      93           0 :   void apply(const not_& x)
      94             :   {
      95           0 :     throw mcrl2::runtime_error("Unexpected negation in PPG rewriter: " + pp(x));
      96             :   }
      97             : 
      98           0 :   void apply(const imp& x)
      99             :   {
     100           0 :     throw mcrl2::runtime_error("Unexpected implication in PPG rewriter: " + pp(x));
     101             :   }
     102             : 
     103           0 :   void enter(const data::data_expression& x)
     104             :   {
     105           0 :     expression_stack.push(x);
     106           0 :   }
     107             : 
     108           0 :   void enter(const propositional_variable_instantiation& x)
     109             :   {
     110           0 :     expression_stack.push(x);
     111           0 :   }
     112             : 
     113           2 :   propositional_variable_instantiation split_here(const pbes_expression& x)
     114             :   {
     115           2 :     fixpoint_symbol symbol = symbol_stack.top();
     116           2 :     propositional_variable variable = variable_stack.top();
     117           4 :     core::identifier_string fresh_varname = core::identifier_string(name_generator.generate_name(variable.name()));
     118           2 :     data::variable_list variable_parameters = variable.parameters() + quantifier_variable_stack.top();
     119             :     // Create fresh propositional variable.
     120             :     propositional_variable fresh_var =
     121           2 :         propositional_variable(fresh_varname, variable_parameters);
     122           2 :     pbes_equation new_eqn = pbes_equation(symbol, fresh_var, x);
     123           2 :     this->apply(new_eqn);
     124             :     propositional_variable_instantiation fresh_var_instantiation =
     125           2 :         propositional_variable_instantiation(fresh_varname, atermpp::container_cast<data::data_expression_list>(variable_parameters));
     126           4 :     return fresh_var_instantiation;
     127           2 :   }
     128             : 
     129           0 :   void apply(const pbes_system::forall& x)
     130             :   {
     131           0 :     this->enter(x);
     132           0 :     bool simple_body = is_simple_expression(x.body());
     133           0 :     if (simple_body)
     134             :     {
     135           0 :       expression_stack.push(x);
     136             :     }
     137             :     else
     138             :     {
     139           0 :       expression_mode mode = mode_stack.top();
     140           0 :       switch(mode)
     141             :       {
     142           0 :       case UNDETERMINED:
     143             :       case CONJUNCTIVE:
     144           0 :         mode = UNIVERSAL;
     145             :         [[fallthrough]];
     146           0 :       case UNIVERSAL:
     147             :       {
     148           0 :         quantifier_variable_stack.push(quantifier_variable_stack.top() + x.variables());
     149           0 :         mode_stack.push(mode);
     150           0 :         this->apply(x.body());
     151           0 :         mode_stack.pop();
     152           0 :         pbes_expression body = expression_stack.top();
     153           0 :         expression_stack.pop();
     154           0 :         pbes_expression expr = forall(x.variables(), body);
     155           0 :         expression_stack.push(expr);
     156           0 :         quantifier_variable_stack.pop();
     157           0 :         break;
     158           0 :       }
     159           0 :       case DISJUNCTIVE:
     160             :       case EXISTENTIAL:
     161           0 :         expression_stack.push(split_here(x));
     162           0 :         break;
     163           0 :       default:
     164           0 :         std::clog << "mode = " << mode << std::endl;
     165           0 :         throw std::runtime_error("unexpected forall");
     166             :         break;
     167             :       }
     168             :     }
     169           0 :     this->leave(x);
     170           0 :   }
     171             : 
     172           4 :   void apply(const pbes_system::exists& x)
     173             :   {
     174           4 :     this->enter(x);
     175           4 :     bool simple_body = is_simple_expression(x.body());
     176           4 :     if (simple_body)
     177             :     {
     178           0 :       expression_stack.push(x);
     179             :     }
     180             :     else
     181             :     {
     182           4 :       expression_mode mode = mode_stack.top();
     183           4 :       switch(mode)
     184             :       {
     185           2 :       case UNDETERMINED:
     186             :       case DISJUNCTIVE:
     187           2 :         mode = EXISTENTIAL;
     188             :         [[fallthrough]];
     189           2 :       case EXISTENTIAL:
     190             :       {
     191           2 :         quantifier_variable_stack.push(quantifier_variable_stack.top() + x.variables());
     192           2 :         mode_stack.push(mode);
     193           2 :         this->apply(x.body());
     194           2 :         mode_stack.pop();
     195           2 :         pbes_expression body = expression_stack.top();
     196           2 :         expression_stack.pop();
     197           2 :         pbes_expression expr = exists(x.variables(), body);
     198           2 :         expression_stack.push(expr);
     199           2 :         quantifier_variable_stack.pop();
     200           2 :         break;
     201           2 :       }
     202           2 :       case CONJUNCTIVE:
     203             :       case UNIVERSAL:
     204           2 :         expression_stack.push(split_here(x));
     205           2 :         break;
     206           0 :       default:
     207           0 :         std::clog << "mode = " << mode << std::endl;
     208           0 :         throw std::runtime_error("unexpected exists");
     209             :         break;
     210             :       }
     211             :     }
     212           4 :     this->leave(x);
     213           4 :   }
     214             : 
     215           3 :   void apply(const pbes_system::and_& x)
     216             :   {
     217           3 :     this->enter(x);
     218           3 :     bool is_simple = is_simple_expression(x);
     219           3 :     if (is_simple)
     220             :     {
     221           0 :       expression_stack.push(x);
     222             :     }
     223             :     else
     224             :     {
     225           3 :       expression_mode mode = mode_stack.top();
     226           3 :       switch(mode)
     227             :       {
     228           1 :       case UNDETERMINED:
     229           1 :         mode = CONJUNCTIVE;
     230             :         [[fallthrough]];
     231           1 :       case CONJUNCTIVE:
     232             :       {
     233           1 :         mode_stack.push(mode);
     234           1 :         this->apply(x.left());
     235           1 :         this->apply(x.right());
     236           1 :         mode_stack.pop();
     237           1 :         pbes_expression r = expression_stack.top();
     238           1 :         expression_stack.pop();
     239           1 :         pbes_expression l = expression_stack.top();
     240           1 :         expression_stack.pop();
     241           1 :         pbes_expression expr = and_(l, r);
     242           1 :         expression_stack.push(expr);
     243           1 :         break;
     244           1 :       }
     245           0 :       case UNIVERSAL:
     246           0 :         expression_stack.push(split_here(x));
     247           0 :         break;
     248           2 :       case EXISTENTIAL:
     249             :       case DISJUNCTIVE:
     250             :       {
     251           2 :         std::vector<pbes_expression> conjuncts = split_conjuncts(x);
     252           2 :         bool split = false;
     253           2 :         std::size_t count = 0;
     254           7 :         for(const pbes_expression& conjunct: conjuncts)
     255             :         {
     256           5 :           if (!is_simple_expression(conjunct))
     257             :           {
     258           2 :             count++;
     259           2 :             if (count > 1 || !is_propositional_variable_instantiation(conjunct))
     260             :             {
     261           0 :               split = true;
     262           0 :               break;
     263             :             }
     264             :           }
     265             :         }
     266           2 :         if (split)
     267             :         {
     268           0 :           std::vector<pbes_expression> simple_conjuncts;
     269           0 :           std::vector<pbes_expression> new_conjuncts;
     270           0 :           for(const pbes_expression& conjunct : conjuncts)
     271             :           {
     272           0 :             if (is_simple_expression(conjunct))
     273             :             {
     274           0 :               simple_conjuncts.push_back(conjunct);
     275             :             }
     276             :             else
     277             :             {
     278           0 :               new_conjuncts.push_back(conjunct);
     279             :             }
     280             :           }
     281           0 :           pbes_expression new_conj = join_and(new_conjuncts.begin(), new_conjuncts.end());
     282           0 :           pbes_expression expr = split_here(new_conj);
     283           0 :           if (simple_conjuncts.size() > 0)
     284             :           {
     285           0 :             pbes_expression simple_conj = join_and(simple_conjuncts.begin(), simple_conjuncts.end());
     286           0 :             expr = and_(simple_conj, expr);
     287           0 :           }
     288           0 :           expression_stack.push(expr);
     289           0 :         }
     290             :         else
     291             :         {
     292           2 :           expression_stack.push(x);
     293             :         }
     294           2 :         break;
     295           2 :       }
     296           0 :       default:
     297           0 :         std::clog << "mode = " << mode << std::endl;
     298           0 :         throw std::runtime_error("unexpected and");
     299             :         break;
     300             :       }
     301             :     }
     302           3 :     this->leave(x);
     303           3 :   }
     304             : 
     305           0 :   void apply(const pbes_system::or_& x)
     306             :   {
     307           0 :     this->enter(x);
     308           0 :     bool is_simple = is_simple_expression(x);
     309           0 :     if (is_simple)
     310             :     {
     311           0 :       expression_stack.push(x);
     312             :     }
     313             :     else
     314             :     {
     315           0 :       expression_mode mode = mode_stack.top();
     316           0 :       switch(mode)
     317             :       {
     318           0 :       case UNDETERMINED:
     319           0 :         mode = DISJUNCTIVE;
     320             :         [[fallthrough]];
     321           0 :       case DISJUNCTIVE:
     322             :       {
     323           0 :         mode_stack.push(mode);
     324           0 :         this->apply(x.left());
     325           0 :         this->apply(x.right());
     326           0 :         mode_stack.pop();
     327           0 :         pbes_expression r = expression_stack.top();
     328           0 :         expression_stack.pop();
     329           0 :         pbes_expression l = expression_stack.top();
     330           0 :         expression_stack.pop();
     331           0 :         pbes_expression expr = or_(l, r);
     332           0 :         expression_stack.push(expr);
     333           0 :         break;
     334           0 :       }
     335           0 :       case EXISTENTIAL:
     336           0 :         expression_stack.push(split_here(x));
     337           0 :         break;
     338           0 :       case UNIVERSAL:
     339             :       case CONJUNCTIVE:
     340             :       {
     341           0 :         std::vector<pbes_expression> disjuncts = split_disjuncts(x);
     342           0 :         bool split = false;
     343           0 :         std::size_t count = 0;
     344           0 :         for(const pbes_expression& disjunct: disjuncts)
     345             :         {
     346           0 :           if (!is_simple_expression(disjunct))
     347             :           {
     348           0 :             count++;
     349           0 :             if (count > 1 || !is_propositional_variable_instantiation(disjunct))
     350             :             {
     351           0 :               split = true;
     352           0 :               break;
     353             :             }
     354             :           }
     355             :         }
     356           0 :         if (split)
     357             :         {
     358           0 :           std::vector<pbes_expression> simple_disjuncts;
     359           0 :           std::vector<pbes_expression> new_disjuncts;
     360           0 :           for(const pbes_expression& disjunct : disjuncts)
     361             :           {
     362           0 :             if (is_simple_expression(disjunct))
     363             :             {
     364           0 :               simple_disjuncts.push_back(disjunct);
     365             :             }
     366             :             else
     367             :             {
     368           0 :               new_disjuncts.push_back(disjunct);
     369             :             }
     370             :           }
     371           0 :           pbes_expression new_disj = join_or(new_disjuncts.begin(), new_disjuncts.end());
     372           0 :           pbes_expression expr = split_here(new_disj);
     373           0 :           if (simple_disjuncts.size() > 0)
     374             :           {
     375           0 :             pbes_expression simple_disj = join_or(simple_disjuncts.begin(), simple_disjuncts.end());
     376           0 :             expr = or_(simple_disj, expr);
     377           0 :           }
     378           0 :           expression_stack.push(expr);
     379             : 
     380           0 :         }
     381             :         else
     382             :         {
     383           0 :           expression_stack.push(x);
     384             :         }
     385           0 :         break;
     386           0 :       }
     387           0 :       default:
     388           0 :         std::clog << "mode = " << mode << std::endl;
     389           0 :         throw std::runtime_error("unexpected or");
     390             :         break;
     391             :       }
     392             :     }
     393           0 :     this->leave(x);
     394           0 :   }
     395             : 
     396           3 :   void enter(const pbes_equation& x)
     397             :   {
     398           3 :     symbol_stack.push(x.symbol());
     399           3 :     variable_stack.push(x.variable());
     400           3 :     data::variable_list l;
     401           3 :     quantifier_variable_stack.push(l);
     402           3 :     mode_stack.push(UNDETERMINED);
     403           3 :   }
     404             : 
     405             : #ifndef NDEBUG
     406           3 :   void leave(const pbes_equation& x)
     407             : #else
     408             :   void leave(const pbes_equation&)
     409             : #endif
     410             :   {
     411           3 :     fixpoint_symbol symbol = symbol_stack.top();
     412           3 :     symbol_stack.pop();
     413           3 :     assert(symbol==x.symbol());
     414           3 :     propositional_variable variable = variable_stack.top();
     415           3 :     variable_stack.pop();
     416           3 :     assert(variable==x.variable());
     417           3 :     mode_stack.pop();
     418           3 :     pbes_expression expr = expression_stack.top();
     419           3 :     pbes_equation e(symbol, variable, expr);
     420           3 :     equations.push_back(e);
     421           3 :     expression_stack.pop();
     422           3 :   }
     423             : 
     424             : };
     425             : /// \endcond
     426             : 
     427             : /// \brief Rewrites a PBES to a PPG.
     428             : /// \param x a PBES
     429             : /// \return a PPG.
     430             : inline
     431           1 : pbes to_ppg(pbes x)
     432             : {
     433           1 :   algorithms::normalize(x);
     434           1 :   ppg_rewriter f(x.equations());
     435           1 :   f.apply(x);
     436             :   pbes result(
     437           1 :       x.data(),
     438             :       f.equations,
     439           2 :       x.initial_state());
     440           2 :   return result;
     441           1 : }
     442             : 
     443             : } // namespace detail
     444             : 
     445             : } // namespace pbes_system
     446             : 
     447             : } // namespace mcrl2
     448             : 
     449             : #endif // MCRL2_PBES_DETAIL_PPG_REWRITER_H

Generated by: LCOV version 1.14