LCOV - code coverage report
Current view: top level - pbes/include/mcrl2/pbes/detail - bqnf_quantifier_rewriter.h (source / functions) Hit Total Coverage
Test: mcrl2_coverage.info.cleaned Lines: 66 189 34.9 %
Date: 2024-04-19 03:43:27 Functions: 4 9 44.4 %
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/bqnf_quantifier_rewriter.h
      10             : /// \brief Replaces universal quantifier over conjuncts with conjuncts over universal quantifiers:
      11             : /// rewrite_bqnf_expression(forall x . /\_i phi_i) =
      12             : ///   /\_i forall (x intersection free(phi_i)) . phi_i.
      13             : /// This rewriter is experimental.
      14             : #ifndef MCRL2_PBES_DETAIL_BQNF_QUANTIFIER_REWRITER_H
      15             : #define MCRL2_PBES_DETAIL_BQNF_QUANTIFIER_REWRITER_H
      16             : 
      17             : #include "mcrl2/pbes/detail/bqnf_visitor.h"
      18             : 
      19             : namespace mcrl2 {
      20             : 
      21             : namespace pbes_system {
      22             : 
      23             : namespace detail {
      24             : 
      25             : struct bqnf_quantifier_rewriter: public bqnf_visitor
      26             :   {
      27             :     /// \brief Constructor.
      28           1 :     bqnf_quantifier_rewriter()
      29           1 :     {
      30           1 :     }
      31             : 
      32             : 
      33             :     /// \brief Filters the expression e such that subexpressions that are data expression that
      34             :     /// do not refer to variables in the set d are discarded:
      35             :     /// filter(e, d) = e if e is a data expression and the intersection of free(e) and d is not empty;
      36             :     /// filter(e1 'op' e2, d) = filter(e1, d) 'op' filter(e2, d).
      37             :     /// \param e a simple PBES expression.
      38             :     /// \param d a set of variables.
      39             :     /// \return the filtered expression.
      40           0 :     virtual pbes_expression filter(const pbes_expression& e, const std::set<data::variable>& d)
      41             :     {
      42           0 :       assert(is_simple_expression(e));
      43           0 :       pbes_expression empty;
      44           0 :       if (is_data(e))
      45             :       {
      46           0 :         std::vector<data::variable> intersection;
      47           0 :         for (const data::variable& var: pbes_system::find_free_variables(e))
      48             :         {
      49           0 :           if (d.find(var) != d.end())
      50             :           {
      51           0 :             intersection.push_back(var);
      52             :           }
      53           0 :         }
      54           0 :         if (intersection.empty())
      55             :         {
      56           0 :           return e;
      57             :         }
      58             :         else
      59             :         {
      60           0 :           return empty;
      61             :         }
      62           0 :       }
      63           0 :       else if (is_and(e) || is_or(e) || is_imp(e))
      64             :       {
      65           0 :         pbes_expression l = filter(pbes_system::accessors::left(e), d);
      66           0 :         pbes_expression r = filter(pbes_system::accessors::right(e), d);
      67           0 :         if (l==empty && r==empty)
      68             :         {
      69           0 :           return empty;
      70             :         }
      71           0 :         else if (l==empty)
      72             :         {
      73           0 :           return r;
      74             :         }
      75           0 :         else if (r==empty)
      76             :         {
      77           0 :           if (is_imp(e))
      78             :           {
      79           0 :             return not_(l);
      80             :           }
      81             :           else
      82             :           {
      83           0 :             return l;
      84             :           }
      85             :         }
      86             :         else
      87             :         {
      88           0 :           if (is_and(e))
      89             :           {
      90           0 :             return and_(l, r);
      91             :           }
      92           0 :           else if (is_or(e))
      93             :           {
      94           0 :             return or_(l, r);
      95             :           }
      96             :           else // is_imp(e)
      97             :           {
      98           0 :             return imp(l, r);
      99             :           }
     100             :         }
     101           0 :       }
     102             :       else
     103             :       {
     104           0 :         std::clog << "filter: Unexpected expression: " << pp(e) << std::endl;
     105           0 :         throw(std::runtime_error("filter: Unexpected expression."));
     106             :       }
     107           0 :     }
     108             : 
     109             : 
     110             : 
     111             :     /// \brief Filters a 'guard' g with respect to a set of variables d and
     112             :     /// an expression phi_i such that parts of g that not relevant for phi_i
     113             :     /// are discarded.
     114             :     /// filter_guard(g, phi_i, d) = ( exists_{d intersects (free(g) - free(phi_i))} . filter(g, {d - free(phi_i)))
     115             :     ///   && filter(g, d intersects free(phi_i)).
     116             :     /// \param g a simple expression that functions as guard.
     117             :     /// \param phi_i a PBES expression.
     118             :     /// \param d a set of relevant variables.
     119             :     /// \return the expression g filtered with respect to phi_i and d.
     120           0 :     virtual pbes_expression filter_guard(const pbes_expression& g, const pbes_expression& phi_i, const data::variable_list& d)
     121             :     {
     122           0 :       pbes_expression result = true_();
     123           0 :       data::variable_list free_g = free_variables(g);
     124           0 :       std::set<data::variable> free_phi_i;
     125           0 :       for (const data::variable& v: pbes_system::find_free_variables(phi_i))
     126             :       {
     127           0 :         free_phi_i.insert(v);
     128           0 :       }
     129           0 :       std::set<data::variable> free_g_minus_free_phi_i;
     130           0 :       for (const data::variable& var: free_g)
     131             :       {
     132           0 :         if (free_phi_i.find(var)==free_phi_i.end()) { // !free_phi_i.contains(v)
     133           0 :           free_g_minus_free_phi_i.insert(var);
     134             :         }
     135             :       }
     136           0 :       std::vector<data::variable> d_intersects_free_g_minus_free_phi_i;
     137           0 :       std::set<data::variable> d_minus_free_phi_i;
     138           0 :       std::set<data::variable> d_intersects_free_phi_i;
     139           0 :       for (const data::variable& var: d)
     140             :       {
     141           0 :         if (free_g_minus_free_phi_i.find(var) != free_g_minus_free_phi_i.end()) // free_g_minus_free_phi_i.contains(v)
     142             :         {
     143           0 :           d_intersects_free_g_minus_free_phi_i.push_back(var);
     144             :         }
     145           0 :         if (free_phi_i.find(var) != free_phi_i.end()) // free_phi_i.contains(v)
     146             :         {
     147           0 :           d_intersects_free_phi_i.insert(var);
     148             :         }
     149             :         else
     150             :         {
     151           0 :           d_minus_free_phi_i.insert(var);
     152             :         }
     153             :       }
     154             :       // Now I have the sets I need; let's generate terms.
     155           0 :       pbes_expression e_1 = filter(g, d_minus_free_phi_i);
     156           0 :       if (!d_intersects_free_g_minus_free_phi_i.empty())
     157             :       {
     158             :         e_1 =
     159             : // data::exists(    // N.B. Removing this, since it does not make sense to convert a pbes_system::exists to a data::exists (Wieger).
     160           0 :             make_exists_(
     161           0 :             data::variable_list(d_intersects_free_g_minus_free_phi_i.begin(), d_intersects_free_g_minus_free_phi_i.end()),
     162           0 :             e_1)
     163             : // )
     164             :            ;
     165             :       }
     166           0 :       pbes_expression e_2 = filter(g, d_intersects_free_phi_i);
     167           0 :       pbes_expression empty;
     168           0 :       if (e_1 == empty)
     169             :       {
     170           0 :         if (e_2 != empty)
     171             :         {
     172           0 :           result = e_2;
     173             :         }
     174             :       }
     175             :       else
     176             :       {
     177           0 :         if (e_2 == empty)
     178             :         {
     179           0 :           result = e_1;
     180             :         }
     181             :         else
     182             :         {
     183           0 :           result = and_(e_1, e_2);
     184             :         }
     185             :       }
     186           0 :       return result;
     187           0 :     }
     188             : 
     189             : 
     190             :     /// \brief Rewrites a bounded universal quantifier expression.
     191             :     /// If the subexpression is a conjunction, the quantifier over the conjunction
     192             :     /// is transformed to a conjunction of quantifier expressions.
     193             :     /// rewrite_bounded_forall(forall x . phi => /\_i psi_i) =
     194             :     ///   /\_i forall (x intersection free(psi_i)) .
     195             :     ///   filter_guard(phi, psi_i, x) => rewrite_bqnf_expression(psi_i).
     196             :     /// \param e a PBES expression
     197             :     /// \return the expression resulting from the transformation.
     198           1 :     virtual pbes_expression rewrite_bounded_forall(const pbes_expression& e)
     199             :     {
     200             :       //std::clog << "rewrite_bounded_forall: " << pp(e) << std::endl;
     201           1 :       assert(is_forall(e));
     202           1 :       data::variable_list qvars = quantifier_variables(e);
     203           1 :       pbes_expression qexpr = pbes_system::accessors::arg(e);
     204           1 :       while (is_forall(qexpr)) {
     205           0 :         qvars = qvars + quantifier_variables(qexpr);
     206           0 :         qexpr = pbes_system::accessors::arg(qexpr);
     207             :       }
     208             :       // forall qvars . qexpr
     209           1 :       pbes_expression result;
     210           1 :       if (is_propositional_variable_instantiation(qexpr) || is_simple_expression(qexpr)) {
     211             :         // forall d . phi | forall d . X(e)
     212           0 :         result = e;
     213             :       } else {
     214           1 :         pbes_expression phi = is_or(qexpr) ? static_cast<const pbes_expression&>(true_()) : static_cast<const pbes_expression&>(false_());
     215           1 :         pbes_expression psi = qexpr;
     216           1 :         if (is_or(qexpr) || is_imp(qexpr)) {
     217           0 :           pbes_expression l = pbes_system::accessors::left(qexpr);
     218           0 :           pbes_expression r = pbes_system::accessors::right(qexpr);
     219           0 :           if (is_simple_expression(l)) {
     220           0 :             phi = l;
     221           0 :             psi = r;
     222             :           }
     223           0 :         }
     224           1 :         if (is_propositional_variable_instantiation(psi)) {
     225             :           // forall d . phi => X(e)
     226           0 :           result = e;
     227           1 :         } else if (!qvars.empty() || !(is_or(qexpr) ? is_true(phi) : is_false(phi))) {
     228             :           // forall d . phi => psi
     229           1 :           std::vector<pbes_expression> conjuncts;
     230           1 :           if (is_and(psi)) {
     231           1 :             conjuncts = split_conjuncts(psi);
     232             :           } else {
     233           0 :             conjuncts.push_back(psi);
     234             :           }
     235           1 :           pbes_expression conjunction = true_();
     236           3 :           for (std::vector<pbes_expression>::const_iterator c = conjuncts.begin(); c != conjuncts.end(); ++c) {
     237           2 :             pbes_expression phi_i = *c;
     238           2 :             pbes_expression r = rewrite_bqnf_expression(phi_i);
     239           2 :             if (is_or(qexpr)) {
     240           0 :               if (!is_true(phi)) {
     241           0 :                 phi = filter_guard(phi, r, qvars);
     242           0 :                 r = or_(phi, r);
     243             :               }
     244             :             } else {
     245           2 :               if (!is_false(phi)) {
     246           0 :                 phi = filter_guard(phi, r, qvars);
     247           0 :                 r = imp(phi, r);
     248             :               }
     249             :             }
     250           2 :             std::vector<data::variable> qvars_i;
     251           2 :             std::set<data::variable> free_phi_i;
     252           4 :             for (const data::variable& v : pbes_system::find_free_variables(phi_i))
     253             :             {
     254           2 :               free_phi_i.insert(v);
     255           2 :             }
     256           4 :             for (const data::variable& var: qvars)
     257             :             {
     258           2 :               if (free_phi_i.find(var) != free_phi_i.end()) // free_phi_i.contains(v)
     259             :               {
     260           2 :                 qvars_i.push_back(var);
     261             :               }
     262             :             }
     263             :             // qvars_i = qvars intersects free(phi_i)
     264           2 :             if (!qvars_i.empty()) {
     265           2 :               r = make_forall_(data::variable_list(qvars_i.begin(), qvars_i.end()), r);
     266             :             }
     267           2 :             if (is_true(conjunction)) {
     268           1 :               conjunction = r;
     269             :             } else {
     270           1 :               conjunction = and_(conjunction, r);
     271             :             }
     272           2 :           }
     273           1 :           result = conjunction;
     274           1 :         } else {
     275             :           // qexpr not of the form phi => psi
     276             :           //std::clog << "rewrite_bounded_forall: unexpected qexpr = " << pp(qexpr) << std::endl;
     277           0 :           throw(std::runtime_error("rewrite_bounded_forall: unexpected qexpr."));
     278             :         }
     279           1 :       }
     280           2 :       return result;
     281           1 :     }
     282             : 
     283             : 
     284             : 
     285             :     /// \brief Rewrites a bounded existential quantifier expression.
     286             :     /// rewrite_bounded_exists(exists v . phi) = exists v. rewrite_bqnf_expression(phi)
     287             :     /// \param e a PBES expression
     288             :     /// \return the expression resulting from the transformation.
     289           0 :     virtual pbes_expression rewrite_bounded_exists(const pbes_expression& e)
     290             :     {
     291             :       //std::clog << "rewrite_bounded_exists" << pp(e) << std::endl;
     292           0 :       assert(is_exists(e));
     293           0 :       pbes_expression qexpr = pbes_system::accessors::arg(e);
     294           0 :       data::variable_list qvars = quantifier_variables(e);
     295           0 :       while (is_exists(qexpr)) {
     296           0 :         qvars = qvars + quantifier_variables(qexpr);
     297           0 :         qexpr = pbes_system::accessors::arg(qexpr);
     298             :       }
     299           0 :       pbes_expression r = rewrite_bqnf_expression(qexpr);
     300           0 :       pbes_expression result = make_exists_(qvars, r);
     301           0 :       return result;
     302           0 :     }
     303             : 
     304             : 
     305             :     /// \brief Rewrites a conjunctive expression.
     306             :     /// rewrite_imp(/\_i phi_i) = /\_i rewrite_bqnf_expression(phi_i).
     307             :     /// \param e a PBES expression
     308             :     /// \return the expression resulting from the transformation.
     309           0 :     virtual pbes_expression rewrite_and(const pbes_expression& e)
     310             :     {
     311             :       //std::clog << "rewrite_and: " << pp(e) << std::endl;
     312           0 :       pbes_expression conjunction = true_();
     313           0 :       std::vector<pbes_equation> new_eqns;
     314           0 :       std::vector<pbes_expression> conjuncts = split_conjuncts(e);
     315           0 :       for (std::vector<pbes_expression>::const_iterator c = conjuncts.begin(); c != conjuncts.end(); ++c) {
     316           0 :         pbes_expression expr = *c;
     317           0 :         pbes_expression r = rewrite_bqnf_expression(expr);
     318           0 :         if (is_true(conjunction)) {
     319           0 :           conjunction = r;
     320             :         } else {
     321           0 :           conjunction = and_(conjunction, r);
     322             :         }
     323           0 :       }
     324           0 :       return conjunction;
     325           0 :     }
     326             : 
     327             : 
     328             :     /// \brief Rewrites a disjunctive expression.
     329             :     /// rewrite_imp(\/_i phi_i) = \/_i rewrite_bqnf_expression(phi_i).
     330             :     /// \param e a PBES expression
     331             :     /// \return the expression resulting from the transformation.
     332           2 :     virtual pbes_expression rewrite_or(const pbes_expression& e)
     333             :     {
     334             :       //std::clog << "rewrite_or: " << pp(e) << std::endl;
     335           2 :       pbes_expression disjunction = false_();
     336           2 :       std::vector<pbes_expression> new_exprs;
     337           2 :       std::vector<pbes_expression> disjuncts = split_disjuncts(e);
     338           6 :       for (std::vector<pbes_expression>::const_iterator d = disjuncts.begin(); d != disjuncts.end(); ++d) {
     339           4 :         pbes_expression expr = *d;
     340           4 :         pbes_expression r = rewrite_bqnf_expression(expr);
     341           4 :         if (is_false(disjunction)) {
     342           2 :           disjunction = r;
     343             :         } else {
     344           2 :           disjunction = or_(disjunction, r);
     345             :         }
     346           4 :       }
     347           4 :       return disjunction;
     348           2 :     }
     349             : 
     350             : 
     351             :     /// \brief Rewrites an implication:
     352             :     /// rewrite_imp(phi => psi) =
     353             :     ///   rewrite_bqnf_expression(phi) => rewrite_bqnf_expression(psi).
     354             :     /// \param e a PBES expression
     355             :     /// \return the expression resulting from the transformation.
     356           0 :     virtual pbes_expression rewrite_imp(const pbes_expression& e)
     357             :     {
     358             :       //std::clog << "rewrite_imp: " << pp(e) << std::endl;
     359           0 :       pbes_expression l = rewrite_bqnf_expression(pbes_system::accessors::left(e));
     360           0 :       pbes_expression r = rewrite_bqnf_expression(pbes_system::accessors::right(e));
     361           0 :       pbes_expression result = imp(l, r);
     362           0 :       return result;
     363           0 :     }
     364             : 
     365             : 
     366             :     /// \brief Rewrites a BQNF expression.
     367             :     /// Replaces universal quantifier over conjuncts with conjuncts over universal quantifiers:
     368             :     /// rewrite_bqnf_expression(forall x . /\_i phi_i) =
     369             :     ///   /\_i forall (x intersection free(phi_i)) . phi_i
     370             :     /// For subexpressions the transformation is done in the usual way:
     371             :     /// rewrite_bqnf_expression(phi 'op' psi) =
     372             :     ///   rewrite_bqnf_expression(phi) 'op' rewrite_bqnf_expression(psi).
     373             :     /// \param e a PBES expression
     374             :     /// \return the expression resulting from the transformation.
     375          10 :     virtual pbes_expression rewrite_bqnf_expression(const pbes_expression& e)
     376             :     {
     377             :       //std::clog << "rewrite_bqnf_expression: " << pp(e) << std::endl;
     378          10 :       pbes_expression result;
     379          10 :       if (is_propositional_variable_instantiation(e) || is_simple_expression(e)) {
     380             :         // Eqn of the form sigma X(d: D) = phi && Y(h(d, l)), with phi a simple formula.
     381             :         // Add sigma X(d) = e.
     382           7 :         result = e;
     383           3 :       } else if (is_forall(e)) {
     384           1 :         result = rewrite_bounded_forall(e);
     385           2 :       } else if (is_exists(e)) {
     386           0 :         result = rewrite_bounded_exists(e);
     387           2 :       } else if (is_or(e)) {
     388           2 :         result = rewrite_or(e);
     389           0 :       } else if (is_imp(e)) {
     390           0 :         result = rewrite_imp(e);
     391           0 :       } else if (is_and(e)) {
     392           0 :         result = rewrite_and(e);
     393             :       } else {
     394           0 :         std::clog << "Unexpected expression: " << pp(e) << std::endl;
     395           0 :         throw(std::runtime_error("Unexpected expression."));
     396             :       }
     397          10 :       return result;
     398           0 :     }
     399             : 
     400             :   };
     401             : 
     402             : } // namespace detail
     403             : 
     404             : } // namespace pbes_system
     405             : 
     406             : } // namespace mcrl2
     407             : 
     408             : #endif // MCRL2_PBES_DETAIL_BQNF_QUANTIFIER_REWRITER_H

Generated by: LCOV version 1.14