LCOV - code coverage report
Current view: top level - lts/include/mcrl2/lts/detail - liblts_sim.h (source / functions) Hit Total Coverage
Test: mcrl2_coverage.info.cleaned Lines: 327 396 82.6 %
Date: 2024-04-19 03:43:27 Functions: 22 30 73.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Author(s): Bas Ploeger
       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 liblts_sim.h
      10             : /// \brief Header file for the simulation preorder algorithm
      11             : 
      12             : #ifndef LIBLTS_SIM_H
      13             : #define LIBLTS_SIM_H
      14             : #include "mcrl2/lts/lts_utilities.h"
      15             : #include "mcrl2/lts/detail/sim_hashtable.h"
      16             : #include "mcrl2/lts/lts_aut.h"
      17             : #include "mcrl2/lts/lts_fsm.h"
      18             : #include "mcrl2/lts/lts_dot.h"
      19             : 
      20             : namespace mcrl2
      21             : {
      22             : namespace lts
      23             : {
      24             : namespace detail
      25             : {
      26             : 
      27             : template <class LTS_TYPE>
      28             : class sim_partitioner
      29             : {
      30             :   public:
      31             :     /** Creates a partitioner for an LTS.
      32             :      * \param[in] l Pointer to the LTS. */
      33             :     sim_partitioner(LTS_TYPE& l);
      34             : 
      35             :     /** Destroys this partitioner. */
      36             :     ~sim_partitioner();
      37             : 
      38             :     /** Computes the simulation equivalence classes and preorder
      39             :      * relations of the LTS. */
      40             :     virtual void partitioning_algorithm();
      41             : 
      42             :     /** Gives the transition relation on the computed equivalence
      43             :      * classes of the LTS. The label numbers of the transitions
      44             :      * correspond to the label numbers of the LTS that was passed as an
      45             :      * argument to the constructor of this partitioner.
      46             :      * The state numbers of the transitions are the equivalence class
      47             :      * numbers which range from 0 upto (and excluding) \ref num_eq_classes().
      48             :      *
      49             :      * \pre The simulation equivalence classes have been computed.
      50             :      * \return A vector containing the transitions between the
      51             :      * simulation equivalence classes. */
      52             :     std::vector < mcrl2::lts::transition> get_transitions() const;
      53             : 
      54             :     /** Gives the number of simulation equivalence classes of the LTS.
      55             :      * \pre The simulation equivalence classes have been computed.
      56             :      * \return The number of simulation equivalence classes of the LTS.
      57             :      */
      58             :     std::size_t num_eq_classes() const;
      59             : 
      60             :     /** Gives the equivalence class number of a state.
      61             :      * The equivalence class numbers range from 0 upto (and excluding)
      62             :      * \ref num_eq_classes().
      63             :      * \pre The simulation equivalence classes have been computed.
      64             :      * \param[in] s A state number.
      65             :      * \return The number of the equivalence class to which \e s
      66             :      * belongs. */
      67             :     std::size_t get_eq_class(std::size_t s) const;
      68             : 
      69             :     /** Returns whether one state is simulated by another state.
      70             :      * \pre The simulation preorder has been computed.
      71             :      * \param[in] s A state number.
      72             :      * \param[in] t A state number.
      73             :      * \retval true if \e s is simulated by \e t;
      74             :      * \retval false otherwise. */
      75             :     bool in_preorder(std::size_t s,std::size_t t) const;
      76             : 
      77             :     /** Returns whether two states are in the same simulation
      78             :      * equivalence class.
      79             :      * \pre The simulation equivalence classes have been computed.
      80             :      * \param[in] s A state number.
      81             :      * \param[in] t A state number.
      82             :      * \retval true if \e s and \e t are in the same simulation
      83             :      * equivalence class;
      84             :      * \retval false otherwise. */
      85             :     bool in_same_class(std::size_t s,std::size_t t) const;
      86             : 
      87             :   protected:
      88             : 
      89             :     /** Computes the simulation equivalence classes and preorder
      90             :      * relations of the LTS.
      91             :      * \pre : initialise_datastructures called */
      92             :     void partitioning_algorithmG();
      93             :     
      94             :     struct state_bucket
      95             :     {
      96             :       ptrdiff_t next;
      97             :       ptrdiff_t prev;
      98             :     };
      99             : 
     100             :     LTS_TYPE& aut;
     101             :     mcrl2::lts::outgoing_transitions_per_state_action_t trans_index;
     102             :     std::size_t s_Sigma;
     103             :     std::size_t s_Pi;
     104             :     std::vector<bool> state_touched;
     105             :     std::vector<bool> block_touched;
     106             :     std::vector<state_bucket> state_buckets;
     107             :     std::vector<std::size_t> block_Pi;
     108             :     std::vector<std::size_t> parent;
     109             :     std::vector< std::vector<std::size_t> > children;
     110             :     std::vector<ptrdiff_t> contents_t;
     111             :     std::vector<ptrdiff_t> contents_u;
     112             :     std::vector< std::vector<bool> > stable;
     113             :     hash_table3* exists;
     114             :     hash_table3* forall;
     115             :     std::vector< std::vector<std::size_t> > pre_exists;
     116             :     std::vector< std::vector<std::size_t> > pre_forall;
     117             :     hash_table3* match;
     118             :     std::vector< std::vector<bool> > P;
     119             :     std::vector< std::vector<bool> > Q;
     120             : 
     121             :     /* auxiliary variables */
     122             :     std::vector<std::size_t> touched_blocks;
     123             :     std::vector<std::size_t> contents;
     124             : 
     125             :     void initialise_datastructures();
     126             :     //void read_partition_from_file(char *parfile);
     127             : 
     128             :     void refine(bool& change);
     129             :     void update();
     130             :     //void update_lts();
     131             : 
     132             :     void touch(std::size_t a,std::size_t alpha);
     133             :     void untouch(std::size_t alpha);
     134             : 
     135             :     void reverse_topological_sort(std::vector<std::size_t>& Sort);
     136             :     void dfs_visit(std::size_t u,std::vector<bool>& visited,
     137             :                    std::vector<std::size_t>& Sort);
     138             : 
     139             :     void initialise_Sigma(std::size_t gamma,std::size_t l);
     140             :     void initialise_Pi(std::size_t gamma,std::size_t l);
     141             :     void filter(std::size_t S,std::vector< std::vector<bool> >& R,bool B);
     142             :     void cleanup(std::size_t alpha,std::size_t beta);
     143             :     void initialise_pre_EA();
     144             :     void induce_P_on_Pi();
     145             : 
     146             :     std::string print_Sigma_P();
     147             :     std::string print_Pi_Q();
     148             :     std::string print_Sigma();
     149             :     std::string print_Pi();
     150             :     std::string print_relation(std::size_t s,std::vector< std::vector<bool> >& R);
     151             :     std::string print_block(std::size_t b);
     152             :     std::string print_structure(hash_table3* struc);
     153             :     std::string print_reverse_topological_sort(const std::vector<std::size_t>& Sort);
     154             : };
     155             : 
     156             : 
     157             : #define LIST_END (-1)
     158             : #define UNIVERSAL_PART (0)
     159             : 
     160             : template <class LTS_TYPE>
     161          54 : sim_partitioner<LTS_TYPE>::sim_partitioner(LTS_TYPE& l)
     162          54 :   : aut(l)
     163             : {
     164          54 :   match  = new hash_table3(1000);
     165          54 :   exists = new hash_table3(1000);
     166          54 :   forall = new hash_table3(1000);
     167          54 : }
     168             : 
     169             : template <class LTS_TYPE>
     170          54 : sim_partitioner<LTS_TYPE>::~sim_partitioner()
     171             : {
     172          54 :   delete match;
     173          54 :   delete exists;
     174          54 :   delete forall;
     175         108 : }
     176             : 
     177             : /* ----------------- PARTITIONING ALGORITHM ------------------------- */
     178             : 
     179             : template <class LTS_TYPE>
     180          38 : void sim_partitioner<LTS_TYPE>::partitioning_algorithm()
     181             : {
     182          38 :   initialise_datastructures();
     183          38 :   partitioning_algorithmG();
     184          38 : }
     185             : 
     186             : /* Pre : initialise_datastructures called */
     187             : template <class LTS_TYPE>
     188          54 : void sim_partitioner<LTS_TYPE>::partitioning_algorithmG()
     189             : {
     190             :   using namespace mcrl2::core;
     191             : 
     192             :   bool change;
     193             :   std::size_t i;
     194             : 
     195          54 :   refine(change);
     196          54 :   update();
     197             : 
     198          54 :   change = true;
     199          54 :   i = 0;
     200         145 :   while (change)
     201             :   {
     202          91 :     change = false;
     203             : 
     204             :     /* Set Sigma to Pi and P to Q*/
     205          91 :     s_Sigma = s_Pi;
     206             :     /* The following statement simultaneously assigns P to Q and Q to P.
     207             :      * The assignment of Q to P is safe because Q is not used in
     208             :      * refine() and will be freshly computed at the start of update().
     209             :      * The advantage of using swap() is that it is executed in constant
     210             :      * time. */
     211          91 :     P.swap(Q);
     212             : 
     213          91 :     mCRL2log(log::debug) << "--------------------- ITERATION " << i << " ----------------------------------" << std::endl;
     214             : 
     215          91 :     mCRL2log(log::debug) << "  iteration " << i << "; number of blocks: " << s_Sigma << std::endl;
     216             : 
     217          91 :     refine(change);
     218          91 :     if (change)
     219             :     {
     220          37 :       update();
     221             :     }
     222             :     else
     223             :     {
     224             :       /* No blocks were split by refine(), so update() need not be
     225             :        * called. However, we do need to swap P and Q again: Q currently
     226             :        * contains the P-relation of the previous iteration (due to the
     227             :        * call to swap() prior to the call to refine()) but we want it to
     228             :        * contain that of the current iteration! */
     229          54 :       P.swap(Q);
     230             :     }
     231          91 :     ++i;
     232             :   }
     233             : 
     234          54 :   if (mCRL2logEnabled(log::debug))
     235             :   {
     236           0 :     mCRL2log(log::debug) << print_Pi_Q();
     237             :   }
     238          54 : }
     239             : 
     240             : template <class LTS_TYPE>
     241          54 : void sim_partitioner<LTS_TYPE>::initialise_datastructures()
     242             : {
     243             :   // aut.sort_transitions(mcrl2::lts::lbl_tgt_src);
     244             :   // trans_index = aut.get_transition_pre_table();
     245          54 :   trans_index=transitions_per_outgoing_state_action_pair_reversed(aut.get_transitions(),aut.hidden_label_set());
     246             : 
     247          54 :   std::size_t N = aut.num_states();
     248             : 
     249          54 :   state_bucket sb = { LIST_END, LIST_END };
     250          54 :   state_buckets.assign(N,sb);
     251          54 :   state_touched.assign(N,false);
     252          54 :   block_Pi.assign(N,UNIVERSAL_PART);
     253             : 
     254             :   /* put all states in one block */
     255          54 :   s_Pi = 1;
     256          54 :   contents_u.push_back(UNIVERSAL_PART);
     257          54 :   contents_t.push_back(LIST_END);
     258         666 :   for (std::size_t i = 0; i < N; ++i)
     259             :   {
     260         612 :     if (i > 0)
     261             :     {
     262         558 :       state_buckets[i].prev = i-1;
     263             :     }
     264             :     else
     265             :     {
     266          54 :       state_buckets[i].prev = LIST_END;
     267             :     }
     268         612 :     if (i < N-1)
     269             :     {
     270         558 :       state_buckets[i].next = i+1;
     271             :     }
     272             :     else
     273             :     {
     274          54 :       state_buckets[i].next = LIST_END;
     275             :     }
     276             :   }
     277             : 
     278          54 :   block_touched.assign(s_Pi,false);
     279          54 :   s_Sigma = s_Pi;
     280             : 
     281             :   /* initialise P and children */
     282          54 :   std::vector<std::size_t> vi;
     283          54 :   children.assign(s_Sigma,vi);
     284          54 :   std::vector<bool> vb(s_Sigma,false);
     285          54 :   P.assign(s_Sigma,vb);
     286         108 :   for (std::size_t i = 0; i < s_Sigma; ++i)
     287             :   {
     288          54 :     children[i].push_back(i);
     289          54 :     P[i][i] = true;
     290             :   }
     291             : 
     292          54 :   mCRL2log(log::debug) << "--------------------- INITIALISATION ---------------------------" << std::endl;
     293          54 :   mCRL2log(log::debug) << "  initialisation; number of blocks: " << s_Sigma << std::endl;
     294          54 : }
     295             : 
     296             : /* ----------------- INITIALISE ------------------------------------- */
     297             : 
     298             : template <class LTS_TYPE>
     299        9482 : void sim_partitioner<LTS_TYPE>::initialise_Pi(std::size_t gamma,std::size_t l)
     300             : {
     301             :   std::size_t alpha, a, c;
     302        9482 :   std::vector<std::size_t>::iterator ci, last;
     303             : 
     304        9482 :   contents.clear();
     305       34235 :   for (ptrdiff_t i = contents_u[gamma]; i != LIST_END;
     306       24753 :        i = state_buckets[i].next)
     307             :   {
     308       24753 :     contents.push_back(std::size_t(i));
     309             :   }
     310        9711 :   for (ptrdiff_t i = contents_t[gamma]; i != LIST_END;
     311         229 :        i = state_buckets[i].next)
     312             :   {
     313         229 :     contents.push_back(std::size_t(i));
     314             :   }
     315        9482 :   last = contents.end();
     316       34464 :   for (ci = contents.begin(); ci != last; ++ci)
     317             :   {
     318       24982 :     c = *ci;
     319             :     /* iterate over the incoming l-transitions of c */
     320             :     using namespace mcrl2::lts;
     321       24982 :     for (outgoing_transitions_per_state_action_t::iterator
     322       24982 :          t=trans_index.lower_bound(std::pair < transition::size_type, transition::size_type >(c,l));
     323       30538 :          t!=trans_index.upper_bound(std::pair < transition::size_type, transition::size_type >(c,l)); ++t)
     324             :     {
     325        5556 :       a = to(t); // As trans_index is reversed, this is actually the state from which the transition t goes.
     326        5556 :       if (!state_touched[a])
     327             :       {
     328        5154 :         alpha = block_Pi[a];
     329        5154 :         touch(a,alpha);
     330        5154 :         if (!block_touched[alpha])
     331             :         {
     332        2730 :           touched_blocks.push_back(alpha);
     333        2730 :           block_touched[alpha] = true;
     334             :         }
     335             :       }
     336             :     }
     337             :   }
     338        9482 : }
     339             : 
     340             : template <class LTS_TYPE>
     341        5077 : void sim_partitioner<LTS_TYPE>::initialise_Sigma(std::size_t gamma,std::size_t l)
     342             : {
     343        5077 :   std::vector<std::size_t>::iterator deltai, last;
     344        5077 :   last = children[gamma].end();
     345       11848 :   for (deltai = children[gamma].begin(); deltai != last; ++deltai)
     346             :   {
     347        6771 :     initialise_Pi(*deltai,l);
     348             :   }
     349        5077 : }
     350             : 
     351             : /* ----------------- REFINE ----------------------------------------- */
     352             : 
     353             : /* PRE: s_Sigma = s_Pi */
     354             : template <class LTS_TYPE>
     355         145 : void sim_partitioner<LTS_TYPE>::refine(bool& change)
     356             : {
     357             :   using namespace mcrl2::core;
     358             :   /* Initialise the parent and children functions */
     359         145 :   std::vector<std::size_t> v;
     360         145 :   children.assign(s_Pi,v);
     361         145 :   parent.assign(s_Pi,0);
     362             :   std::size_t alpha;
     363         830 :   for (alpha = 0; alpha < s_Pi; ++alpha)
     364             :   {
     365         685 :     children[alpha].push_back(alpha);
     366         685 :     parent[alpha] = alpha;
     367             :   }
     368             : 
     369         145 :   if (mCRL2logEnabled(log::debug))
     370             :   {
     371           0 :     mCRL2log(log::debug) << "--------------------- Refine ---------------------------------------" << std::endl;
     372           0 :     mCRL2log(log::debug) << print_Sigma_P();
     373             :   }
     374             : 
     375             :   /* Compute a reverse topological sorting of Sigma w.r.t. P */
     376         145 :   std::vector<std::size_t> Sort;
     377         145 :   Sort.reserve(s_Sigma);
     378         145 :   reverse_topological_sort(Sort);
     379             : 
     380         145 :   if (mCRL2logEnabled(log::debug))
     381             :   {
     382           0 :     mCRL2log(log::debug) << print_reverse_topological_sort(Sort);
     383             :   }
     384             : 
     385             :   /* Some local variables */
     386         145 :   std::vector<bool> v_false(s_Sigma,false);
     387         145 :   std::vector<std::size_t>::iterator alphai, last, gammai;
     388         145 :   std::vector< std::vector<bool> >::iterator stable_alpha, P_gamma;
     389             :   bool stable_alpha_gamma;
     390             :   std::size_t gamma, delta, l;
     391             : 
     392             :   /* The main loop */
     393         764 :   for (l = 0; l < aut.num_action_labels(); ++l)
     394             :   {
     395         619 :     mCRL2log(log::debug) << "---------------------------------------------------" << std::endl;
     396         619 :     mCRL2log(log::debug) << "Label = \"" << mcrl2::lts::pp(aut.action_label(l)) << "\"" << std::endl;
     397             : 
     398             :     /* reset the stable function */
     399         619 :     stable.assign(s_Pi,v_false);
     400             : 
     401             :     /* iterate over the reverse topological sorting */
     402        3787 :     for (gammai = Sort.begin(); gammai != Sort.end(); ++gammai)
     403             :     {
     404        3168 :       gamma = *gammai;
     405             : 
     406        3168 :       touched_blocks.clear();
     407        3168 :       initialise_Sigma(gamma,l);
     408             : 
     409             :       /* iterate over all alpha such that alpha -l->E gamma */
     410        3168 :       last = touched_blocks.end();
     411        4246 :       for (alphai = touched_blocks.begin(); alphai != last; ++alphai)
     412             :       {
     413        1078 :         alpha = *alphai;
     414             :         /* compute stable(alpha,gamma); use a local boolean variable for
     415             :          * efficiency */
     416        1078 :         stable_alpha_gamma = false;
     417        1078 :         stable_alpha = stable.begin() + alpha;
     418        1078 :         P_gamma = P.begin() + gamma;
     419       10462 :         for (delta = 0; delta < s_Sigma && !stable_alpha_gamma; ++delta)
     420             :         {
     421        9384 :           if ((*stable_alpha)[delta] && (*P_gamma)[delta])
     422             :           {
     423          32 :             stable_alpha_gamma = true;
     424             :           }
     425             :         }
     426        1078 :         (*stable_alpha)[gamma] = stable_alpha_gamma;
     427        1078 :         if (!stable_alpha_gamma)
     428             :         {
     429             :           /* if alpha -l->A gamma then alpha cannot be split */
     430        1046 :           if (contents_u[alpha] != LIST_END)
     431             :           {
     432             :             /* split alpha; new block will be s_Pi */
     433         195 :             change = true;
     434             : 
     435         195 :             children[parent[alpha]].push_back(s_Pi);
     436         195 :             parent.push_back(parent[alpha]);
     437         195 :             stable.push_back(*stable_alpha);
     438         195 :             block_touched.push_back(false);
     439         195 :             contents_t.push_back(LIST_END);
     440             : 
     441             :             /* assign the untouched contents of alpha to s_Pi */
     442         195 :             contents_u.push_back(contents_u[alpha]);
     443         195 :             contents_u[alpha] = LIST_END;
     444             : 
     445             :             /* update the block information for the moved states */
     446        1458 :             for (ptrdiff_t i = contents_u[s_Pi]; i != LIST_END;
     447        1263 :                  i = state_buckets[i].next)
     448             :             {
     449        1263 :               block_Pi[i] = s_Pi;
     450             :             }
     451         195 :             ++s_Pi;
     452             :           }
     453        1046 :           stable[alpha][gamma] = true;
     454             :         }
     455        1078 :         untouch(alpha);
     456             :       }
     457             :     }
     458             :   }
     459         145 : }
     460             : 
     461             : template <class LTS_TYPE>
     462         145 : void sim_partitioner<LTS_TYPE>::reverse_topological_sort(std::vector<std::size_t>& Sort)
     463             : {
     464         145 :   std::vector<bool> visited(s_Sigma,false);
     465         830 :   for (std::size_t u = 0; u < s_Sigma; ++u)
     466             :   {
     467         685 :     if (!visited[u])
     468             :     {
     469         587 :       dfs_visit(u,visited,Sort);
     470             :     }
     471             :   }
     472         145 : }
     473             : 
     474             : template <class LTS_TYPE>
     475         685 : void sim_partitioner<LTS_TYPE>::dfs_visit(std::size_t u,std::vector<bool>& visited,
     476             :     std::vector<std::size_t> &Sort)
     477             : {
     478         685 :   visited[u] = true;
     479        6956 :   for (std::size_t v = 0; v < s_Sigma; ++v)
     480             :   {
     481        6271 :     if (!visited[v] && P[u][v])
     482             :     {
     483          98 :       dfs_visit(v,visited,Sort);
     484             :     }
     485             :   }
     486         685 :   Sort.push_back(u);
     487         685 : }
     488             : 
     489             : template <class LTS_TYPE>
     490        5154 : void sim_partitioner<LTS_TYPE>::touch(std::size_t a,std::size_t alpha)
     491             : {
     492        5154 :   state_touched[a] = true;
     493        5154 :   ptrdiff_t p = state_buckets[a].prev;
     494        5154 :   ptrdiff_t n = state_buckets[a].next;
     495        5154 :   if (p == LIST_END)
     496             :   {
     497        2865 :     contents_u[alpha] = n;
     498             :   }
     499             :   else
     500             :   {
     501        2289 :     state_buckets[p].next = n;
     502             :   }
     503        5154 :   if (n != LIST_END)
     504             :   {
     505        1463 :     state_buckets[n].prev = p;
     506             :   }
     507        5154 :   state_buckets[a].prev = LIST_END;
     508        5154 :   state_buckets[a].next = contents_t[alpha];
     509        5154 :   if (contents_t[alpha] != LIST_END)
     510             :   {
     511        2424 :     state_buckets[contents_t[alpha]].prev = a;
     512             :   }
     513        5154 :   contents_t[alpha] = a;
     514        5154 : }
     515             : 
     516             : /* PRE: contents_t[alpha] != LIST_END */
     517             : template <class LTS_TYPE>
     518        2730 : void sim_partitioner<LTS_TYPE>::untouch(std::size_t alpha)
     519             : {
     520             :   // search linearly for the last element of contents_t[alpha];
     521             :   // untouch every state we encounter along the way
     522        2730 :   ptrdiff_t i = contents_t[alpha];
     523        5154 :   while (state_buckets[i].next != LIST_END)
     524             :   {
     525        2424 :     state_touched[i] = false;
     526        2424 :     i = state_buckets[i].next;
     527             :   }
     528             :   // last element has not been untouched yet
     529        2730 :   state_touched[i] = false;
     530             : 
     531             :   // insert the list contents_t[alpha] at the beginning of
     532             :   // contents_u[alpha]
     533        2730 :   state_buckets[i].next = contents_u[alpha];
     534        2730 :   if (contents_u[alpha] != LIST_END)
     535             :   {
     536         125 :     state_buckets[contents_u[alpha]].prev = i;
     537             :   }
     538        2730 :   contents_u[alpha] = contents_t[alpha];
     539        2730 :   contents_t[alpha] = LIST_END;
     540        2730 :   block_touched[alpha] = false;
     541        2730 : }
     542             : 
     543             : /* ----------------- UPDATE ----------------------------------------- */
     544             : 
     545             : template <class LTS_TYPE>
     546          91 : void sim_partitioner<LTS_TYPE>::update()
     547             : {
     548             :   using namespace mcrl2::core;
     549          91 :   mCRL2log(log::debug) << "--------------------- Update ---------------------------------------" << std::endl;
     550             : 
     551             :   std::size_t l,alpha,gamma;
     552          91 :   std::vector<std::size_t>::iterator alphai, last;
     553             : 
     554          91 :   induce_P_on_Pi();
     555             : 
     556          91 :   initialise_pre_EA();
     557             : 
     558             :   /* Compute the pre_exists and pre_forall functions */
     559         485 :   for (l = 0; l < aut.num_action_labels(); ++l)
     560             :   {
     561         394 :     pre_exists[l].reserve(s_Sigma + 1);
     562         394 :     pre_forall[l].reserve(s_Sigma + 1);
     563         394 :     pre_exists[l].push_back(exists->get_num_elements());
     564         394 :     pre_forall[l].push_back(forall->get_num_elements());
     565        2175 :     for (gamma = 0; gamma < s_Sigma; ++gamma)
     566             :     {
     567        1781 :       touched_blocks.clear();
     568        1781 :       initialise_Sigma(gamma,l);
     569        1781 :       last = touched_blocks.end();
     570        2501 :       for (alphai = touched_blocks.begin(); alphai != last; ++alphai)
     571             :       {
     572         720 :         alpha = *alphai;
     573         720 :         exists->add(alpha,l,gamma);
     574         720 :         if (contents_u[alpha] == LIST_END)
     575             :         {
     576         714 :           forall->add(alpha,l,gamma);
     577             :         }
     578         720 :         untouch(alpha);
     579             :       }
     580        1781 :       pre_exists[l].push_back(exists->get_num_elements());
     581        1781 :       pre_forall[l].push_back(forall->get_num_elements());
     582             :     }
     583             :   }
     584             : 
     585          91 :   mCRL2log(log::debug) << "------ Filter(false) ------\nExists: ";
     586          91 :   mCRL2log(log::debug) << print_structure(exists);
     587          91 :   mCRL2log(log::debug) << "\nForall: ";
     588          91 :   mCRL2log(log::debug) << print_structure(forall);
     589          91 :   mCRL2log(log::debug) << "\nSimulation relation: ";
     590          91 :   mCRL2log(log::debug) << print_relation(s_Pi,Q);
     591             : 
     592             :   /* Apply the first filtering to Q */
     593          91 :   filter(s_Sigma,P,false);
     594             : 
     595             : 
     596          91 :   initialise_pre_EA();
     597             : 
     598             :   /* Compute the pre_exists and pre_forall functions */
     599         485 :   for (l = 0; l < aut.num_action_labels(); ++l)
     600             :   {
     601         394 :     pre_exists[l].reserve(s_Pi + 1);
     602         394 :     pre_forall[l].reserve(s_Pi + 1);
     603         394 :     pre_exists[l].push_back(exists->get_num_elements());
     604         394 :     pre_forall[l].push_back(forall->get_num_elements());
     605        3105 :     for (gamma = 0; gamma < s_Pi; ++gamma)
     606             :     {
     607        2711 :       touched_blocks.clear();
     608        2711 :       initialise_Pi(gamma,l);
     609        2711 :       last = touched_blocks.end();
     610        3508 :       for (alphai = touched_blocks.begin(); alphai != last; ++alphai)
     611             :       {
     612         797 :         alpha = *alphai;
     613         797 :         exists->add(alpha,l,gamma);
     614         797 :         if (contents_u[alpha] == LIST_END)
     615             :         {
     616         684 :           forall->add(alpha,l,gamma);
     617             :         }
     618         797 :         untouch(alpha);
     619             :       }
     620        2711 :       pre_exists[l].push_back(exists->get_num_elements());
     621        2711 :       pre_forall[l].push_back(forall->get_num_elements());
     622             :     }
     623             :   }
     624             : 
     625          91 :   mCRL2log(log::debug) << "------ Filter(true) ------\nExists: ";
     626          91 :   mCRL2log(log::debug) << print_structure(exists);
     627          91 :   mCRL2log(log::debug) << "\nForall: ";
     628          91 :   mCRL2log(log::debug) << print_structure(forall);
     629          91 :   mCRL2log(log::debug) << "\nSimulation relation: ";
     630          91 :   mCRL2log(log::debug) << print_relation(s_Pi,Q);
     631             : 
     632             :   /* Apply the second filtering to Q */
     633          91 :   filter(s_Pi,Q,true);
     634          91 : }
     635             : 
     636             : template <class LTS_TYPE>
     637         182 : void sim_partitioner<LTS_TYPE>::initialise_pre_EA()
     638             : {
     639             :   /* Initialise the pre_exists and pre_forall data structures */
     640         182 :   exists->clear();
     641         182 :   forall->clear();
     642         182 :   std::vector<std::size_t> v;
     643         182 :   pre_exists.assign(aut.num_action_labels(),v);
     644         182 :   pre_forall.assign(aut.num_action_labels(),v);
     645         182 : }
     646             : 
     647             : template <class LTS_TYPE>
     648         107 : void sim_partitioner<LTS_TYPE>::induce_P_on_Pi()
     649             : {
     650             :   /* Compute the relation induced on Pi by P, store it in Q */
     651         107 :   std::vector<bool> v(s_Pi,false);
     652         107 :   Q.assign(s_Pi,v);
     653             : 
     654             :   std::size_t alpha,beta;
     655         107 :   std::vector< std::vector<bool> >::iterator P_parent_alpha;
     656         754 :   for (alpha = 0; alpha < s_Pi; ++alpha)
     657             :   {
     658         647 :     P_parent_alpha = P.begin() + parent[alpha];
     659        6880 :     for (beta = 0; beta < s_Pi; ++beta)
     660             :     {
     661        6233 :       Q[alpha][beta] = (*P_parent_alpha)[parent[beta]];
     662             :     }
     663             :   }
     664         107 : }
     665             : 
     666             : 
     667             : /* ----------------- FILTER ----------------------------------------- */
     668             : 
     669             : template <class LTS_TYPE>
     670         182 : void sim_partitioner<LTS_TYPE>::filter(std::size_t S,std::vector< std::vector<bool> > &R,
     671             :                                        bool B)
     672             : {
     673             :   /* Initialise the match function */
     674         182 :   match->clear();
     675             : 
     676             :   std::size_t alpha,beta,gamma,delta,l;
     677         182 :   hash_table3_iterator etrans(exists);
     678         970 :   for (l = 0; l < aut.num_action_labels(); ++l)
     679             :   {
     680        5280 :     for (delta = 0; delta < S; ++delta)
     681             :     {
     682        4492 :       etrans.set_end(pre_exists[l][delta+1]);
     683        6009 :       for (etrans.set(pre_exists[l][delta]); !etrans.is_end(); ++etrans)
     684             :       {
     685        1517 :         beta = etrans.get_x();
     686       15998 :         for (gamma = 0; gamma < S; ++gamma)
     687             :         {
     688       14481 :           if (R[gamma][delta])
     689             :           {
     690        2510 :             match->add(l,beta,gamma);
     691             :           }
     692             :         }
     693             :       }
     694             :     }
     695             :   }
     696             : 
     697         182 :   hash_table3_iterator atrans(forall);
     698             :   /* The main for loop */
     699         970 :   for (l = 0; l < aut.num_action_labels(); ++l)
     700             :   {
     701        5280 :     for (gamma = 0; gamma < S; ++gamma)
     702             :     {
     703        4492 :       atrans.set_end(pre_forall[l][gamma+1]);
     704        5890 :       for (atrans.set(pre_forall[l][gamma]); !atrans.is_end(); ++atrans)
     705             :       {
     706        1398 :         alpha = atrans.get_x();
     707       16898 :         for (beta = 0; beta < s_Pi; ++beta)
     708             :         {
     709       15500 :           if (Q[alpha][beta] && !match->find(l,beta,gamma))
     710             :           {
     711        1047 :             Q[alpha][beta] = false;
     712        1047 :             if (B)
     713             :             {
     714          20 :               cleanup(alpha,beta);
     715             :             }
     716             :           }
     717             :         }
     718             :       }
     719             :     }
     720             :   }
     721         182 : }
     722             : 
     723             : /* ----------------- CLEANUP ---------------------------------------- */
     724             : 
     725             : template <class LTS_TYPE>
     726          28 : void sim_partitioner<LTS_TYPE>::cleanup(std::size_t alpha,std::size_t beta)
     727             : {
     728             :   std::size_t l,alpha1,beta1,delta;
     729             :   bool match_l_beta1_alpha;
     730          28 :   hash_table3_iterator alpha1i(forall);
     731          28 :   hash_table3_iterator beta1i(exists);
     732         203 :   for (l = 0; l < aut.num_action_labels(); ++l)
     733             :   {
     734         175 :     alpha1i.set_end(pre_forall[l][alpha+1]);
     735         175 :     beta1i.set_end(pre_exists[l][beta+1]);
     736         204 :     for (beta1i.set(pre_exists[l][beta]); !beta1i.is_end(); ++beta1i)
     737             :     {
     738          29 :       beta1 = beta1i.get_x();
     739          29 :       match_l_beta1_alpha = false;
     740         843 :       for (delta = 0; delta < s_Pi && !match_l_beta1_alpha; ++delta)
     741             :       {
     742         814 :         if (exists->find(beta1,l,delta) && Q[alpha][delta])
     743             :         {
     744           1 :           match_l_beta1_alpha = true;
     745             :         }
     746             :       }
     747          29 :       if (!match_l_beta1_alpha)
     748             :       {
     749          28 :         match->remove(l,beta1,alpha);
     750          43 :         for (alpha1i.set(pre_forall[l][alpha]); !alpha1i.is_end();
     751          15 :              ++alpha1i)
     752             :         {
     753          15 :           alpha1 = alpha1i.get_x();
     754          15 :           if (Q[alpha1][beta1])
     755             :           {
     756           8 :             Q[alpha1][beta1] = false;
     757           8 :             cleanup(alpha1,beta1);
     758             :           }
     759             :         }
     760             :       }
     761             :     }
     762             :   }
     763          28 : }
     764             : 
     765             : /* ----------------- FOR POST-PROCESSING ---------------------------- */
     766             : 
     767             : template <class LTS_TYPE>
     768           5 : std::vector < mcrl2::lts::transition> sim_partitioner<LTS_TYPE>::get_transitions() const
     769             : {
     770             :   using namespace mcrl2::lts;
     771             : 
     772           5 :   std::vector < mcrl2::lts::transition> ts;
     773           5 :   ts.reserve(forall->get_num_elements());
     774             : 
     775           5 :   std::vector<bool> pre_sim;
     776             :   transition::size_type l,beta,gamma;
     777           5 :   hash_table3_iterator alphai(exists);
     778           5 :   hash_table3_iterator gammai(forall);
     779          65 :   for (beta = 0; beta < s_Pi; ++beta)
     780             :   {
     781         409 :     for (l = 0; l < aut.num_action_labels(); ++l)
     782             :     {
     783             :       // there is an l-transition from alpha to beta iff:
     784             :       // - alpha -l->A [beta]
     785             :       // - not Exists gamma : beta Q gamma  /\  alpha -l->E gamma
     786             :       // first compute for which alpha the latter statement does not
     787             :       // hold
     788         349 :       pre_sim.assign(s_Pi,false);
     789        9978 :       for (gamma = 0; gamma < s_Pi; ++gamma)
     790             :       {
     791             :         // only consider gammas that are unequal to beta
     792        9629 :         if (gamma != beta && Q[beta][gamma])
     793             :         {
     794          49 :           alphai.set_end(pre_exists[l][gamma+1]);
     795          62 :           for (alphai.set(pre_exists[l][gamma]); !alphai.is_end();
     796          13 :                ++alphai)
     797             :           {
     798          13 :             pre_sim[alphai.get_x()] = true;
     799             :           }
     800             :         }
     801             :       }
     802         349 :       gammai.set_end(pre_forall[l][beta+1]);
     803         434 :       for (gammai.set(pre_forall[l][beta]); !gammai.is_end(); ++gammai)
     804             :       {
     805          85 :         gamma = gammai.get_x();
     806          85 :         if (!pre_sim[gamma])
     807             :         {
     808             :           // add the transition gamma -l-> beta
     809          83 :           ts.push_back(transition(gamma,l,beta));
     810             :         }
     811             :       }
     812             :     }
     813             :   }
     814          10 :   return ts;
     815           5 : }
     816             : 
     817             : template <class LTS_TYPE>
     818           5 : std::size_t sim_partitioner<LTS_TYPE>::num_eq_classes() const
     819             : {
     820           5 :   return s_Pi;
     821             : }
     822             : 
     823             : template <class LTS_TYPE>
     824           5 : std::size_t sim_partitioner<LTS_TYPE>::get_eq_class(std::size_t s) const
     825             : {
     826           5 :   return block_Pi[s];
     827             : }
     828             : 
     829             : template <class LTS_TYPE>
     830          33 : bool sim_partitioner<LTS_TYPE>::in_preorder(std::size_t s,std::size_t t) const
     831             : {
     832          33 :   return Q[block_Pi[s]][block_Pi[t]];
     833             : }
     834             : 
     835             : template <class LTS_TYPE>
     836          16 : bool sim_partitioner<LTS_TYPE>::in_same_class(std::size_t s,std::size_t t) const
     837             : {
     838          16 :   return (block_Pi[s] == block_Pi[t]);
     839             : }
     840             : 
     841             : /*
     842             : // PRE: FORALL and EXISTS structures on Pi are computed
     843             : void sim_partitione<LTS_TYPE>r::update_nfa()
     844             : {
     845             :   std::vector< std::vector<std::size_t> > v(s_Pi);
     846             :   std::vector< std::vector< std::vector<std::size_t> > > post_trans(L,v);
     847             : 
     848             :   std::vector<bool> pre_sim;
     849             :   std::size_t l,beta,alpha,gamma;
     850             :   hash_table3_iterator alphai(exists);
     851             :   hash_table3_iterator gammai(forall);
     852             :   for (beta = 0; beta < s_Pi; ++beta)
     853             :   {
     854             :     for (l = 0; l < aut.num_action_labels(); ++l)
     855             :     {
     856             :       // there is an l-transition from alpha to beta iff:
     857             :       // - alpha -l->A [beta]
     858             :       // - not Exists gamma : beta Q gamma  /\  alpha -l->E gamma
     859             :       // first compute for which alpha the latter statement does not
     860             :       // hold
     861             :       pre_sim.assign(s_Pi,false);
     862             :       for (gamma = 0; gamma < s_Pi; ++gamma)
     863             :       {
     864             :         // only consider gammas that are unequal to beta
     865             :         if (gamma != beta && Q[beta][gamma])
     866             :         {
     867             :           alphai.set_end(pre_exists[l][gamma+1]);
     868             :           for (alphai.set(pre_exists[l][gamma]); !alphai.is_end();
     869             :               ++alphai)
     870             :           {
     871             :             pre_sim[alphai.get_x()] = true;
     872             :           }
     873             :         }
     874             :       }
     875             :       gammai.set_end(pre_forall[l][beta+1]);
     876             :       for (gammai.set(pre_forall[l][beta]); !gammai.is_end(); ++gammai)
     877             :       {
     878             :         gamma = gammai.get_x();
     879             :         if (!pre_sim[gamma])
     880             :         {
     881             :           post_trans[l][gamma].push_back(beta);
     882             :         }
     883             :       }
     884             :     }
     885             :   }
     886             : 
     887             :   std::vector<transition> *trans = new std::vector<transition> ();
     888             :   std::vector<bool> *final = new std::vector<bool> ();
     889             : 
     890             :   // Do a breadth first search over the computed graph to assign ids to
     891             :   // the reachable blocks and construct the final transition relation
     892             :   std::vector<std::size_t>::iterator post_it,post_last;
     893             :   std::queue<std::size_t> todo;
     894             :   std::vector<std::size_t> block_id(s_Pi,s_Pi);
     895             :   todo.push(block_Pi[aut.initial_state()]);
     896             :   block_id[block_Pi[aut.initial_state()]] = 0;
     897             :   std::size_t n_s = 1;
     898             :   std::size_t n_f = 0;
     899             :   if (aut.is_final(aut.initial_state()))
     900             :   {
     901             :     final->push_back(true);
     902             :     ++n_f;
     903             :   }
     904             :   else
     905             :   {
     906             :     final->push_back(false);
     907             :   }
     908             :   while (!todo.empty())
     909             :   {
     910             :     // visit todo.front()
     911             :     beta = todo.front();
     912             :     for (l = 0; l < L; ++l)
     913             :     {
     914             :       post_last = post_trans[l][beta].end();
     915             :       for (post_it = post_trans[l][beta].begin(); post_it != post_last;
     916             :           ++post_it)
     917             :       {
     918             :         alpha = *post_it;
     919             :         if (block_id[alpha] == s_Pi)
     920             :         {
     921             :           todo.push(alpha);
     922             :           block_id[alpha] = n_s;
     923             :           ++n_s;
     924             :           if (aut.is_final(contents_u[alpha]))
     925             :           {
     926             :             final->push_back(true);
     927             :             ++n_f;
     928             :           }
     929             :           else
     930             :           {
     931             :             final->push_back(false);
     932             :           }
     933             :         }
     934             :         transition t = {block_id[beta], l, block_id[alpha]};
     935             :         trans->push_back(t);
     936             :       }
     937             :     }
     938             :     todo.pop();
     939             :   }
     940             : 
     941             :   // assign the new transition relation to aut
     942             :   aut.clear_transition_relation();
     943             :   aut.clear_final();
     944             :   aut.set_num_states(n_s);
     945             :   aut.set_num_transitions(trans->size());
     946             :   aut.set_num_final(n_f);
     947             :   aut.set_init(0);
     948             :   aut.set_trans(trans);
     949             :   aut.set_final(final);
     950             : 
     951             :   // assign the simulation relation to aut
     952             :   aut.init_simulation_relation();
     953             :   for (beta = 0; beta < s_Pi; ++beta)
     954             :   {
     955             :     // only consider reachable blocks
     956             :     if (block_id[beta] < s_Pi)
     957             :     {
     958             :       for (gamma = 0; gamma < s_Pi; ++gamma)
     959             :       {
     960             :         if (block_id[gamma] < s_Pi && Q[beta][gamma])
     961             :         {
     962             :           aut.add_simulation(block_id[beta],block_id[gamma]);
     963             :         }
     964             :       }
     965             :     }
     966             :   }
     967             : }
     968             : */
     969             : 
     970             : /* ----------------- FOR DEBUGGING ---------------------------------- */
     971             : 
     972             : template <class LTS_TYPE>
     973           0 : std::string sim_partitioner<LTS_TYPE>::print_Sigma_P()
     974             : {
     975             :   using namespace mcrl2::core;
     976           0 :   std::stringstream result;
     977           0 :   result << print_Sigma() << "Simulation relation: " << print_relation(s_Sigma,P);
     978           0 :   return result.str();
     979           0 : }
     980             : 
     981             : template <class LTS_TYPE>
     982           0 : std::string sim_partitioner<LTS_TYPE>::print_Pi_Q()
     983             : {
     984             :   using namespace mcrl2::core;
     985           0 :   std::stringstream result;
     986           0 :   result << print_Pi() << "Simulation relation: " << print_relation(s_Pi,Q);
     987           0 :   return result.str();
     988           0 : }
     989             : 
     990             : template <class LTS_TYPE>
     991           0 : std::string sim_partitioner<LTS_TYPE>::print_Sigma()
     992             : {
     993             :   using namespace mcrl2::core;
     994           0 :   std::stringstream result;
     995           0 :   std::vector<std::size_t>::iterator ci, last;
     996           0 :   for (std::size_t b = 0; b < s_Sigma; ++b)
     997             :   {
     998           0 :     result << "block " << b << ": {";
     999           0 :     last = children[b].end();
    1000           0 :     for (ci = children[b].begin(); ci != last; ++ci)
    1001             :     {
    1002           0 :       result << print_block(*ci);
    1003             :     }
    1004           0 :     result << "}" << std::endl;
    1005             :   }
    1006           0 :   return result.str();
    1007           0 : }
    1008             : 
    1009             : template <class LTS_TYPE>
    1010           0 : std::string sim_partitioner<LTS_TYPE>::print_Pi()
    1011             : {
    1012           0 :   std::stringstream result;
    1013             :   using namespace mcrl2::core;
    1014           0 :   for (std::size_t b = 0; b < s_Pi; ++b)
    1015             :   {
    1016           0 :     result << "block " << b << ": {" << print_block(b) << "}" << std::endl;
    1017             :   }
    1018           0 :   return result.str();
    1019           0 : }
    1020             : 
    1021             : template <class LTS_TYPE>
    1022           0 : std::string sim_partitioner<LTS_TYPE>::print_block(std::size_t b)
    1023             : {
    1024           0 :   std::stringstream result;
    1025             :   using namespace mcrl2::core;
    1026           0 :   for (ptrdiff_t i = contents_u[b]; i != LIST_END; i = state_buckets[i].next)
    1027             :   {
    1028           0 :     result << i << ",";
    1029             :   }
    1030           0 :   for (ptrdiff_t i = contents_t[b]; i != LIST_END; i = state_buckets[i].next)
    1031             :   {
    1032           0 :     result << i << ",";
    1033             :   }
    1034           0 :   return result.str();
    1035           0 : }
    1036             : 
    1037             : template <class LTS_TYPE>
    1038           0 : std::string sim_partitioner<LTS_TYPE>::print_relation(std::size_t s,
    1039             :     std::vector< std::vector<bool> > &R)
    1040             : {
    1041             :   using namespace mcrl2::core;
    1042           0 :   std::stringstream result;
    1043           0 :   result << "{";
    1044             :   std::size_t beta,gamma;
    1045           0 :   for (beta = 0; beta < s; ++beta)
    1046             :   {
    1047           0 :     for (gamma = 0; gamma < s; ++gamma)
    1048             :     {
    1049           0 :       if (R[beta][gamma])
    1050             :       {
    1051           0 :         result << "(" << beta << "," << gamma << "),";
    1052             :       }
    1053             :     }
    1054             :   }
    1055           0 :   result << "}" << std::endl;
    1056           0 :   return result.str();
    1057           0 : }
    1058             : 
    1059             : template <class LTS_TYPE>
    1060           0 : std::string sim_partitioner<LTS_TYPE>::print_structure(hash_table3* struc)
    1061             : {
    1062             :   using namespace mcrl2::core;
    1063           0 :   std::stringstream result;
    1064           0 :   result << "{";
    1065           0 :   hash_table3_iterator i(struc);
    1066           0 :   for (; !i.is_end(); ++i)
    1067             :   {
    1068           0 :     result << "(" << i.get_x() << "," << mcrl2::lts::pp(aut.action_label(i.get_y()))
    1069           0 :            << "," << i.get_z() << "),";
    1070             :   }
    1071           0 :   result << "}";
    1072           0 :   return result.str();
    1073           0 : }
    1074             : 
    1075             : template <class LTS_TYPE>
    1076           0 : std::string sim_partitioner<LTS_TYPE>::print_reverse_topological_sort(const std::vector<std::size_t> &Sort)
    1077             : {
    1078             :   using namespace mcrl2::core;
    1079           0 :   std::stringstream result;
    1080           0 :   result << "reverse topological sort is: [";
    1081           0 :   for (std::size_t i = 0; i < Sort.size(); ++i)
    1082             :     {
    1083           0 :       result << Sort[i];
    1084           0 :       if (i+1 < Sort.size())
    1085             :         {
    1086           0 :           result << ",";
    1087             :         }
    1088             :     }
    1089           0 :   result << "]" << std::endl;
    1090           0 :   return result.str();
    1091           0 : } 
    1092             : 
    1093             : 
    1094             : } // namespace detail
    1095             : } // namespace lts
    1096             : } // namespace mcrl2
    1097             : #endif

Generated by: LCOV version 1.14