LCOV - code coverage report
Current view: top level - process/include/mcrl2/process - remove_equations.h (source / functions) Hit Total Coverage
Test: mcrl2_coverage.info.cleaned Lines: 84 86 97.7 %
Date: 2024-04-19 03:43:27 Functions: 8 8 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Author(s): Wieger Wesselink
       2             : // Copyright: see the accompanying file COPYING or copy at
       3             : // https://github.com/mCRL2org/mCRL2/blob/master/COPYING
       4             : //
       5             : // Distributed under the Boost Software License, Version 1.0.
       6             : // (See accompanying file LICENSE_1_0.txt or copy at
       7             : // http://www.boost.org/LICENSE_1_0.txt)
       8             : //
       9             : /// \file mcrl2/process/remove_equations.h
      10             : /// \brief add your file description here.
      11             : 
      12             : #ifndef MCRL2_PROCESS_REMOVE_EQUATIONS_H
      13             : #define MCRL2_PROCESS_REMOVE_EQUATIONS_H
      14             : 
      15             : #include "mcrl2/data/substitutions/mutable_map_substitution.h"
      16             : #include "mcrl2/process/replace.h"
      17             : 
      18             : namespace mcrl2 {
      19             : 
      20             : namespace process {
      21             : 
      22             : namespace detail {
      23             : 
      24             : // Uses a bisimulation algorithm to find duplicate equations. For example in the following
      25             : // list of equations
      26             : //
      27             : // S(b: Bool) = sum d: D. r1(d) . T(d, b);
      28             : // T(d: D, b: Bool) = s2(d, b) . (r6(b) . S(!b) + (r6(!b) + r6(e)) . T(d, b));
      29             : // R(b: Bool) = sum d: D. r3(d, b) . s4(d) . s5(b) . R(!b) + (sum d: D. r3(d, !b) + r3(e)) . s5(!b) . R(b);
      30             : // K = sum d: D, b: Bool. r2(d, b) . (i . s3(d, b) + i . s3(e)) . K;
      31             : // L = sum b: Bool. r5(b) . (i . s6(b) + i . s6(e)) . L;
      32             : // S2(b: Bool) = sum d: D. r1(d) . T1(d, b);
      33             : // T1(d: D, b: Bool) = s2(d, b) . (r6(b) . S2(!b) + (r6(!b) + r6(e)) . T1(d, b));
      34             : //
      35             : // the equations for S2 and T1 will be removed
      36             : struct duplicate_equation_removal
      37             : {
      38             :   typedef std::vector<process_equation>::const_iterator iterator;
      39             :   typedef std::set<iterator> group;
      40             :   typedef data::mutable_map_substitution<std::map<process_identifier, process_identifier> > substitution;
      41             : 
      42             :   process_specification& procspec;
      43             :   data::set_identifier_generator generator;
      44             :   std::vector<group> groups;
      45             : 
      46           2 :   std::string print_group(const group& g)
      47             :   {
      48           2 :     std::ostringstream out;
      49           5 :     for (auto i: g)
      50             :     {
      51           3 :       const process_equation& eq = *i;
      52             : 
      53             :       // use a custom print for equations, since by default they are printed on multiple lines...
      54           3 :       bool print_parens = !eq.formal_parameters().empty();
      55           3 :       out << eq.identifier().name();
      56           3 :       if (print_parens)
      57             :       {
      58           1 :         out << "(";
      59             :       }
      60           3 :       out << data::pp(eq.formal_parameters());
      61           3 :       if (print_parens)
      62             :       {
      63           1 :         out << ")";
      64             :       }
      65           3 :       out << " = " << eq.expression() << ";\n";
      66             :     }
      67           4 :     return out.str();
      68           2 :   }
      69             : 
      70           2 :   std::string print_groups()
      71             :   {
      72           2 :     std::ostringstream out;
      73           2 :     std::size_t index = 0;
      74           4 :     for (auto& group: groups)
      75             :     {
      76           2 :       out << "--- group " << index++ << " ---\n" << print_group(group) << std::endl;
      77             :     }
      78           4 :     return out.str();
      79           2 :   }
      80             : 
      81           2 :   duplicate_equation_removal(process_specification& procspec_)
      82           2 :     : procspec(procspec_)
      83             :   {
      84           2 :     generator.add_identifiers(process::find_identifiers(procspec));
      85           2 :     generator.add_identifiers(data::function_and_mapping_identifiers(procspec.data()));
      86           2 :     std::map<data::variable_list, group> s;
      87           5 :     for (auto i = procspec.equations().begin(); i != procspec.equations().end(); ++i)
      88             :     {
      89           3 :       s[i->formal_parameters()].insert(i);
      90             :     }
      91           4 :     for (auto& i: s)
      92             :     {
      93           2 :       groups.push_back(i.second);
      94             :     }
      95           2 :     mCRL2log(log::debug) << "==========================================================\n" << print_groups() << std::endl;
      96           2 :   }
      97             : 
      98             :   // assigns a unique process identifier to each process identifier within a group
      99           2 :   substitution make_substitution()
     100             :   {
     101           2 :     substitution result;
     102           4 :     for (const group& g: groups)
     103             :     {
     104           2 :       const process_equation& first_equation = **g.begin();
     105           4 :       process_identifier id(generator("X"), first_equation.formal_parameters());
     106           5 :       for (iterator i: g)
     107             :       {
     108           3 :         const process_equation& eq = *i;
     109           3 :         result[eq.identifier()] = id;
     110             :       }
     111           2 :     }
     112           2 :     return result;
     113           0 :   }
     114             : 
     115             :   // splits the group g into multiple groups, and appends them to result
     116           2 :   void split_group(const group& g, const substitution& sigma, std::vector<group>& result)
     117             :   {
     118           2 :     std::map<process_expression, group> m;
     119           5 :     for (auto i: g)
     120             :     {
     121           3 :       const process_equation& eq = *i;
     122           3 :       process_expression expr = replace_process_identifiers(eq.expression(), sigma);
     123           3 :       m[expr].insert(i);
     124           3 :     }
     125           4 :     for (auto &i : m)
     126             :     {
     127           2 :       result.push_back(i.second);
     128             :     }
     129           2 :   }
     130             : 
     131             :   // splits all groups
     132             :   // returns true if at least one of the groups was split into multiple groups
     133           2 :   bool split_groups()
     134             :   {
     135           2 :     substitution sigma = make_substitution();
     136           2 :     std::vector<group> new_groups;
     137           4 :     for (auto& group: groups)
     138             :     {
     139           2 :       split_group(group, sigma, new_groups);
     140             :     }
     141           2 :     bool result = new_groups.size() > groups.size();
     142           2 :     groups = new_groups;
     143           2 :     return result;
     144           2 :   }
     145             : 
     146           2 :   void run()
     147             :   {
     148             :     // Compute groups of equal equations
     149             :     for (;;)
     150             :     {
     151           2 :       if (!split_groups())
     152             :       {
     153           2 :         break;
     154             :       }
     155           0 :       mCRL2log(log::debug) << "==========================================================\n" << print_groups() << std::endl;
     156             :     }
     157             : 
     158             :     // Choose one equation per group (the one with the lowest index in equations),
     159             :     // and prepare a substitution sigma that removes the others
     160           2 :     std::vector<process_equation> new_equations;
     161           2 :     substitution sigma;
     162           4 :     for (auto& i : groups)
     163             :     {
     164             :       // optimization for the case of only one equation in a group
     165           2 :       if (i.size() == 1)
     166             :       {
     167           1 :         new_equations.push_back(**(i.begin()));
     168           1 :         continue;
     169             :       }
     170             : 
     171           1 :       group::const_iterator j = std::min_element(i.begin(), i.end());
     172           1 :       new_equations.push_back(**j);
     173           3 :       for (group::const_iterator k = i.begin(); k != i.end(); ++k)
     174             :       {
     175           2 :         if (k != j)
     176             :         {
     177           1 :           sigma[(**k).identifier()] = (**j).identifier();
     178             :         }
     179             :       }
     180             :     }
     181             : 
     182             :     // Apply sigma to the new equations and the initial state
     183           4 :     for (auto& new_equation : new_equations)
     184             :     {
     185           2 :       new_equation = process_equation(new_equation.identifier(), new_equation.formal_parameters(), replace_process_identifiers(new_equation.expression(), sigma));
     186             :     }
     187           2 :     procspec.init() = replace_process_identifiers(procspec.init(), sigma);
     188           2 :     procspec.equations() = new_equations;
     189           2 :   }
     190             : };
     191             : 
     192             : } // namespace detail
     193             : 
     194             : inline
     195             : /// \brief Removes duplicate equations from a process specification, using a bisimulation algorithm
     196           2 : void remove_duplicate_equations(process_specification& procspec)
     197             : {
     198           2 :   detail::duplicate_equation_removal f(procspec);
     199           2 :   f.run();
     200           2 : }
     201             : 
     202             : } // namespace process
     203             : 
     204             : } // namespace mcrl2
     205             : 
     206             : #endif // MCRL2_PROCESS_REMOVE_EQUATIONS_H

Generated by: LCOV version 1.14