LCOV - code coverage report
Current view: top level - data/include/mcrl2/data - find_equalities.h (source / functions) Hit Total Coverage
Test: mcrl2_coverage.info.cleaned Lines: 186 209 89.0 %
Date: 2024-04-21 03:44:01 Functions: 39 55 70.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Author(s): Wieger Wesselink, Thomas Neele
       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/data/find_equalities.h
      10             : /// \brief add your file description here.
      11             : 
      12             : #ifndef MCRL2_DATA_FIND_EQUALITIES_H
      13             : #define MCRL2_DATA_FIND_EQUALITIES_H
      14             : 
      15             : #include "mcrl2/core/detail/print_utility.h"
      16             : #include "mcrl2/data/find.h"
      17             : 
      18             : namespace mcrl2 {
      19             : 
      20             : namespace data {
      21             : 
      22             : namespace detail {
      23             : 
      24             : struct equality_set_with_top
      25             : {
      26             :   std::map<variable, std::set<data_expression> > assignments;
      27             :   bool is_top = false;
      28             : 
      29       60709 :   std::set<data_expression>& operator[](const variable& var)
      30             :   {
      31       60709 :     return assignments[var];
      32             :   }
      33             : 
      34             :   /// @brief Computes intersection, modifying this set
      35       42088 :   equality_set_with_top& intersect(const equality_set_with_top& other)
      36             :   {
      37       42088 :     if (other.is_top)
      38             :     {
      39          14 :       return *this;
      40             :     }
      41       42074 :     if (is_top)
      42             :     {
      43           1 :       *this = other;
      44           1 :       return *this;
      45             :     }
      46             : 
      47       42073 :     auto i1 = assignments.begin();
      48       42073 :     auto i2 = other.assignments.begin();
      49       50978 :     while (i1 != assignments.end())
      50             :     {
      51        9053 :       if (i2 == other.assignments.end())
      52             :       {
      53         148 :         assignments.erase(i1, assignments.end());
      54         148 :         break;
      55             :       }
      56        8905 :       if (i1->first > i2->first)
      57             :       {
      58          29 :         assignments.erase(i1++);
      59             :       }
      60        8876 :       else if (i2->first > i1->first)
      61             :       {
      62          56 :         ++i2;
      63             :       }
      64             :       else
      65             :       {
      66        8820 :         i1->second = utilities::detail::set_intersection(i1->second, i2->second);
      67        8820 :         if (i1->second.empty())
      68             :         {
      69        8820 :           assignments.erase(i1++);
      70             :         }
      71             :         else
      72             :         {
      73           0 :           ++i1;
      74             :         }
      75        8820 :         ++i2;
      76             :       }
      77             :     }
      78             : 
      79       42073 :     return *this;
      80             :   }
      81             : 
      82             :   /// @brief Computes union, modifying this set
      83       47928 :   equality_set_with_top& union_(const equality_set_with_top& other)
      84             :   {
      85       47928 :     is_top |= other.is_top;
      86      112332 :     for (const auto& [lhs, rhss]: other.assignments)
      87             :     {
      88       64404 :       assignments[lhs].insert(rhss.begin(), rhss.end());
      89             :     }
      90       47928 :     return *this;
      91             :   }
      92             : 
      93           2 :   bool non_empty_intersection(const data::variable_list& variables, const std::set<data::variable>& V) const
      94             :   {
      95             :     using utilities::detail::contains;
      96           4 :     return std::any_of(variables.begin(), variables.end(), [&](const variable& v) { return contains(V,v); });
      97             :   }
      98             : 
      99           4 :   bool must_delete(const data::variable_list& variables, const data::variable& lhs, std::set<data::data_expression>& rhs) const
     100             :   {
     101             :     using utilities::detail::contains;
     102             :     using utilities::detail::remove_if;
     103           4 :     if (contains(variables, lhs))
     104             :     {
     105           2 :       return true;
     106             :     }
     107           4 :     remove_if(rhs, [&](const data::data_expression& x) { return non_empty_intersection(variables, data::find_free_variables(x)); });
     108           2 :     return rhs.empty();
     109             :   }
     110             : 
     111          52 :   void delete_(const data::variable_list& variables)
     112             :   {
     113             :     using utilities::detail::remove_if;
     114          56 :     remove_if(assignments, [&](std::pair<const variable, std::set<data_expression> >& p) { return must_delete(variables, p.first, p.second); });
     115          52 :   }
     116             : 
     117             :   // for each entry b = b', b' = b is added too
     118       29828 :   void close()
     119             :   {
     120       74318 :     for (auto i = assignments.begin(); i != assignments.end(); ++i)
     121             :     {
     122       44490 :       const variable& v = i->first;
     123       44490 :       std::vector<variable> W;
     124       89004 :       for (const data_expression& e: i->second)
     125             :       {
     126       44514 :         if (is_variable(e))
     127             :         {
     128        3142 :           W.push_back(atermpp::down_cast<variable>(e));
     129             :         }
     130             :       }
     131       47632 :       for (const variable& w: W)
     132             :       {
     133        3142 :         assignments[w].insert(v);
     134             :       }
     135       44490 :     }
     136       29828 :   }
     137             : };
     138             : 
     139             : struct find_equalities_expression
     140             : {
     141             :   equality_set_with_top equalities;
     142             :   equality_set_with_top inequalities;
     143             : 
     144             :   /// @brief Creates (empty,empty)
     145        1064 :   find_equalities_expression()
     146        1064 :   {}
     147             : 
     148             :   /// @brief Creates ({lhs == rhs}, empty) if is_equality is true, and (empty, {lhs == rhs}) otherwise
     149             :   /// @param is_equality Indicates whether to construct an equality or inequality
     150       51788 :   find_equalities_expression(const variable& lhs, const data_expression& rhs, bool is_equality)
     151       51788 :   {
     152       51788 :     if (is_equality)
     153             :     {
     154       51783 :       equalities[lhs].insert(rhs);
     155       51783 :       if (is_variable(rhs))
     156             :       {
     157        3063 :         equalities[atermpp::down_cast<variable>(rhs)].insert(lhs);
     158             :       }
     159             :     }
     160             :     else
     161             :     {
     162           5 :       inequalities[lhs].insert(rhs);
     163           5 :       if (is_variable(rhs))
     164             :       {
     165           2 :         inequalities[atermpp::down_cast<variable>(rhs)].insert(lhs);
     166             :       }
     167             :     }
     168       51788 :   }
     169             : 
     170             :   /// @brief Creates ({lhs == true}, {lhs != false})
     171        2928 :   find_equalities_expression(const variable& lhs)
     172        2928 :   {
     173        2928 :     assert(lhs.sort() == sort_bool::bool_());
     174        2928 :     equalities[lhs].insert(sort_bool::true_());
     175        2928 :     inequalities[lhs].insert(sort_bool::false_());
     176        2928 :   }
     177             : 
     178             :   /// @brief Creates (empty,top) if ineq_top is true and (top,empty) otherwise
     179        1222 :   find_equalities_expression(bool ineq_top)
     180        1222 :   {
     181        1222 :     equalities.is_top = !ineq_top;
     182        1222 :     inequalities.is_top = ineq_top;
     183        1222 :   }
     184             : 
     185        2009 :   void swap()
     186             :   {
     187        2009 :     std::swap(equalities, inequalities);
     188        2009 :   }
     189             : 
     190       36086 :   void join_and(const find_equalities_expression& other)
     191             :   {
     192       36086 :     equalities.union_(other.equalities);
     193       36086 :     inequalities.intersect(other.inequalities);
     194       36086 :   }
     195             : 
     196         162 :   void join_or(const find_equalities_expression& other)
     197             :   {
     198         162 :     equalities.intersect(other.equalities);
     199         162 :     inequalities.union_(other.inequalities);
     200         162 :   }
     201             : 
     202          26 :   void delete_(const data::variable_list& variables)
     203             :   {
     204          26 :     equalities.delete_(variables);
     205          26 :     inequalities.delete_(variables);
     206          26 :   }
     207             : 
     208       14914 :   void close()
     209             :   {
     210       14914 :     equalities.close();
     211       14914 :     inequalities.close();
     212       14914 :   }
     213             : };
     214             : 
     215             : inline
     216             : std::ostream& operator<<(std::ostream& out, const find_equalities_expression& x)
     217             : {
     218             :   using core::detail::print_set;
     219             :   std::vector<data_expression> result;
     220             :   for (const auto& [lhs, rhss]: x.equalities.assignments)
     221             :   {
     222             :     for (const data_expression& rhs: rhss)
     223             :     {
     224             :       result.push_back(equal_to(lhs, rhs));
     225             :     }
     226             :   }
     227             :   for (const auto& [lhs, rhss]: x.inequalities.assignments)
     228             :   {
     229             :     for (const data_expression& rhs: rhss)
     230             :     {
     231             :       result.push_back(not_equal_to(lhs, rhs));
     232             :     }
     233             :   }
     234             :   out << print_set(result);
     235             :   return out;
     236             : }
     237             : 
     238             : template <template <class> class Traverser, class Derived>
     239             : struct find_equalities_traverser: public Traverser<Derived>
     240             : {
     241             :   typedef Traverser<Derived> super;
     242             :   using super::enter;
     243             :   using super::leave;
     244             :   using super::apply;
     245             : 
     246             :   std::vector<find_equalities_expression> expression_stack;
     247             : 
     248       82894 :   Derived& derived()
     249             :   {
     250       82894 :     return static_cast<Derived&>(*this);
     251             :   }
     252             : 
     253       57002 :   void push(const find_equalities_expression& x)
     254             :   {
     255       57002 :     expression_stack.push_back(x);
     256       57002 :   }
     257             : 
     258      113116 :   find_equalities_expression& top()
     259             :   {
     260      113116 :     assert(!expression_stack.empty());
     261      113116 :     return expression_stack.back();
     262             :   }
     263             : 
     264             :   const find_equalities_expression& top() const
     265             :   {
     266             :     assert(!expression_stack.empty());
     267             :     return expression_stack.back();
     268             :   }
     269             : 
     270       39168 :   find_equalities_expression& below_top()
     271             :   {
     272       39168 :     assert(expression_stack.size() >= 2);
     273       39168 :     return expression_stack[expression_stack.size() - 2];
     274             :   }
     275             : 
     276             :   const find_equalities_expression& below_top() const
     277             :   {
     278             :     assert(expression_stack.size() >= 2);
     279             :     return expression_stack[expression_stack.size() - 2];
     280             :   }
     281             : 
     282        2920 :   find_equalities_expression& two_below_top()
     283             :   {
     284        2920 :     assert(expression_stack.size() >= 3);
     285        2920 :     return expression_stack[expression_stack.size() - 3];
     286             :   }
     287             : 
     288             :   const find_equalities_expression& two_below_top() const
     289             :   {
     290             :     assert(expression_stack.size() >= 3);
     291             :     return expression_stack[expression_stack.size() - 3];
     292             :   }
     293             : 
     294       42088 :   find_equalities_expression pop()
     295             :   {
     296       42088 :     assert(!expression_stack.empty());
     297       42088 :     find_equalities_expression result = top();
     298       42088 :     expression_stack.pop_back();
     299       42088 :     return result;
     300             :   }
     301             : 
     302             : 
     303       93698 :   void apply(const data::application& x)
     304             :   {
     305       93698 :     if (data::is_equal_to_application(x))
     306             :     {
     307       52160 :       const data_expression& left = binary_left(x);
     308       52160 :       const data_expression& right = binary_right(x);
     309       52160 :       if (is_variable(left) && !search_free_variable(right, atermpp::down_cast<variable>(left)))
     310             :       {
     311       49894 :         push(find_equalities_expression(atermpp::down_cast<variable>(left), right, true));
     312             :       }
     313        2266 :       else if (is_variable(right) && !search_free_variable(left, atermpp::down_cast<variable>(right)))
     314             :       {
     315        1889 :         push(find_equalities_expression(atermpp::down_cast<variable>(right), left, true));
     316             :       }
     317             :       else
     318             :       {
     319         377 :         push(find_equalities_expression());
     320             :       }
     321             :     }
     322       41538 :     else if (data::is_not_equal_to_application(x))
     323             :     {
     324           7 :       const data_expression& left = binary_left(x);
     325           7 :       const data_expression& right = binary_right(x);
     326           7 :       if (is_variable(left) && !search_free_variable(right, atermpp::down_cast<variable>(left)))
     327             :       {
     328           5 :         push(find_equalities_expression(atermpp::down_cast<variable>(left), right, false));
     329             :       }
     330           2 :       else if (is_variable(right) && !search_free_variable(left, atermpp::down_cast<variable>(right)))
     331             :       {
     332           0 :         push(find_equalities_expression(atermpp::down_cast<variable>(right), left, false));
     333             :       }
     334             :       else
     335             :       {
     336           2 :         push(find_equalities_expression());
     337             :       }
     338             :     }
     339       41531 :     else if (sort_bool::is_not_application(x))
     340             :     {
     341        2006 :       derived().apply(sort_bool::arg(x));
     342        2006 :       top().swap();
     343             :     }
     344       39525 :     else if (sort_bool::is_and_application(x))
     345             :     {
     346       35949 :       derived().apply(binary_left(x));
     347       35949 :       derived().apply(binary_right(x));
     348       35949 :       find_equalities_expression& left = below_top();
     349       35949 :       const find_equalities_expression& right = top();
     350       35949 :       left.join_and(right);
     351       35949 :       pop();
     352             :     }
     353        3576 :     else if (sort_bool::is_or_application(x))
     354             :     {
     355         115 :       derived().apply(binary_left(x));
     356         115 :       derived().apply(binary_right(x));
     357         115 :       find_equalities_expression& left = below_top();
     358         115 :       const find_equalities_expression& right = top();
     359         115 :       left.join_or(right);
     360         115 :       pop();
     361             :     }
     362        3461 :     else if (sort_bool::is_implies_application(x))
     363             :     {
     364           0 :       derived().apply(binary_left(x));
     365           0 :       derived().apply(binary_right(x));
     366           0 :       find_equalities_expression& left = below_top();
     367           0 :       const find_equalities_expression& right = top();
     368           0 :       left.swap();
     369           0 :       left.join_or(right);
     370           0 :       pop();
     371             :     }
     372        3461 :     else if (is_if_application(x))
     373             :     {
     374        2920 :       derived().apply(x[1]);
     375        2920 :       derived().apply(x[2]);
     376        2920 :       derived().apply(x[0]);
     377        2920 :       find_equalities_expression& then = two_below_top();
     378        2920 :       find_equalities_expression& else_ = below_top();
     379        2920 :       const find_equalities_expression& cond = top();
     380             :       
     381        2920 :       then.equalities.union_(cond.equalities);
     382        2920 :       else_.equalities.union_(cond.inequalities);
     383        2920 :       then.equalities.intersect(else_.equalities);
     384             :       
     385        2920 :       then.inequalities.union_(cond.equalities);
     386        2920 :       else_.inequalities.union_(cond.inequalities);
     387        2920 :       then.inequalities.intersect(else_.inequalities);
     388             :       
     389        2920 :       pop();
     390        2920 :       pop();
     391             :     }
     392             :     else
     393             :     {
     394         541 :       mCRL2log(log::trace) << "ignoring " << x << std::endl;
     395         541 :       push(find_equalities_expression());
     396             :     }
     397       93698 :   }
     398             : 
     399        2928 :   void leave(const data::variable& x)
     400             :   {
     401        2928 :     if (sort_bool::is_bool(x.sort()))
     402             :     {
     403        2928 :       push(find_equalities_expression(x));
     404             :     }
     405             :     else
     406             :     {
     407           0 :       push(find_equalities_expression());
     408             :     }
     409        2928 :   }
     410             : 
     411           0 :   void leave(const data::abstraction& x)
     412             :   {
     413           0 :     top().delete_(x.variables());
     414           0 :   }
     415             : 
     416        1222 :   void leave(const data::function_symbol& f)
     417             :   {
     418        1222 :     if (sort_bool::is_true_function_symbol(f))
     419             :     {
     420         148 :       push(find_equalities_expression(true));
     421             :     }
     422        1074 :     else if (sort_bool::is_false_function_symbol(f))
     423             :     {
     424        1074 :       push(find_equalities_expression(false));
     425             :     }
     426             :     else
     427             :     {
     428           0 :       push(find_equalities_expression());
     429             :     }
     430        1222 :   }
     431             : 
     432           0 :   void leave(const data::where_clause&)
     433             :   {
     434           0 :     throw mcrl2::runtime_error("not implemented yet!");
     435             :   }
     436             : };
     437             : 
     438             : struct find_equalities_traverser_inst: public find_equalities_traverser<data::data_expression_traverser, find_equalities_traverser_inst>
     439             : {
     440             :   typedef find_equalities_traverser<data::data_expression_traverser, find_equalities_traverser_inst> super;
     441             : 
     442             :   using super::enter;
     443             :   using super::leave;
     444             :   using super::apply;
     445             : };
     446             : 
     447             : } // namespace detail
     448             : 
     449             : inline
     450       14668 : std::map<variable, std::set<data_expression> > find_equalities(const data_expression& x)
     451             : {
     452       14668 :   detail::find_equalities_traverser_inst f;
     453       14668 :   f.apply(x);
     454       14668 :   assert(f.expression_stack.size() == 1);
     455       14668 :   f.top().close();
     456       29336 :   return f.top().equalities.assignments;
     457       14668 : }
     458             : 
     459             : inline
     460           1 : std::map<variable, std::set<data_expression> > find_inequalities(const data_expression& x)
     461             : {
     462           1 :   detail::find_equalities_traverser_inst f;
     463           1 :   f.apply(x);
     464           1 :   assert(f.expression_stack.size() == 1);
     465           1 :   f.top().close();
     466           2 :   return f.top().inequalities.assignments;
     467           1 : }
     468             : 
     469             : inline
     470             : std::string print_equalities(const std::map<variable, std::set<data_expression> >& equalities)
     471             : {
     472             :   using core::detail::print_set;
     473             :   std::vector<data_expression> result;
     474             :   for (const auto& [lhs, rhss]: equalities)
     475             :   {
     476             :     for (const data_expression& rhs: rhss)
     477             :     {
     478             :       result.push_back(equal_to(lhs, rhs));
     479             :     }
     480             :   }
     481             :   return print_set(result);
     482             : }
     483             : 
     484             : inline
     485           0 : std::string print_inequalities(const std::map<variable, std::set<data_expression> >& inequalities)
     486             : {
     487             :   using core::detail::print_set;
     488           0 :   std::vector<data_expression> result;
     489           0 :   for (const auto& [lhs, rhss]: inequalities)
     490             :   {
     491           0 :     for (const data_expression& rhs: rhss)
     492             :     {
     493           0 :       result.push_back(not_equal_to(lhs, rhs));
     494             :     }
     495             :   }
     496           0 :   return print_set(result);
     497           0 : }
     498             : 
     499             : } // namespace data
     500             : 
     501             : } // namespace mcrl2
     502             : 
     503             : #endif // MCRL2_DATA_FIND_EQUALITIES_H

Generated by: LCOV version 1.14