LCOV - code coverage report
Current view: top level - lts/source - liblts_bisim_dnj.cpp (source / functions) Hit Total Coverage
Test: mcrl2_coverage.info.cleaned Lines: 1455 1656 87.9 %
Date: 2019-06-26 00:32:26 Functions: 125 197 63.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Author(s): David N. Jansen, Institute of Software, Chinese Academy of
       2             : // Sciences, Beijing, PR China
       3             : //
       4             : // Copyright: see the accompanying file COPYING or copy at
       5             : // https://github.com/mCRL2org/mCRL2/blob/master/COPYING
       6             : //
       7             : // Distributed under the Boost Software License, Version 1.0.
       8             : // (See accompanying file LICENSE_1_0.txt or copy at
       9             : // http://www.boost.org/LICENSE_1_0.txt)
      10             : 
      11             : /// \file lts/detail/liblts_bisim_dnj.cpp
      12             : ///
      13             : /// \brief O(m log n)-time branching bisimulation algorithm
      14             : ///
      15             : /// \details This file implements an efficient partition refinement algorithm
      16             : /// for labelled transition systems inspired by Groote / Jansen / Keiren / Wijs
      17             : /// (2017) and Valmari (2009) to calculate the branching bisimulation classes
      18             : /// of a labelled transition system.  Different from the 2017 article, it does
      19             : /// not translate the LTS to a Kripke structure, but works on the LTS directly.
      20             : /// In this way the memory use can be reduced.
      21             : ///
      22             : /// Partition refinement means that the algorithm maintains a partition of the
      23             : /// state space of the LTS into ``blocks''.  A block contains all states in one
      24             : /// or several branching bisimulation equivalence classes.  Blocks are being
      25             : /// refined until every block contains exactly one branching bisimulation
      26             : /// equivalence class.
      27             : ///
      28             : /// The algorithm divides the non-inert transitions into *action_block-slices.*
      29             : /// An action_block-slice contains all transitions with a given action label
      30             : /// into one block.  One or more action_block-slices are joined into a *bunch.*
      31             : /// Bunches register which blocks have already been stabilised:
      32             : ///
      33             : /// > Invariant:  The blocks are stable under the bunches, i. e. if a block
      34             : /// > has a transition in a bunch, then every bottom state in this block has
      35             : /// > a transition in this bunch.
      36             : ///
      37             : /// However, if a bunch is non-trivial (i. e., it contains more than one
      38             : /// action_block-slice), its slices may split some blocks into finer parts:
      39             : /// not all states may have a transition in the same action_block-slice.  So, a
      40             : /// refinement step consists of moving one small action_block-slice from a
      41             : /// non-trivial bunch to a new bunch and then splitting blocks to restore the
      42             : /// Invariant.  Splitting is always done by finding a small subblock and move
      43             : /// the states in that subblock to a new block.  Note that we always handle a
      44             : /// small part of some larger unit; that ensures that each state and transition
      45             : /// is only touched O(log n) times.
      46             : ///
      47             : /// After splitting blocks, some inert transitions may have become non-inert.
      48             : /// These transitions mostly need to be inserted into their own bunch.  Also,
      49             : /// some states may have lost all their inert transitions and become new bottom
      50             : /// states.  These states need to be handled as well to reestablish the
      51             : /// Invariant.
      52             : ///
      53             : /// Overall, we spend time as follows:
      54             : /// - Every transition is moved to a new bunch at most
      55             : ///   log<SUB>2</SUB>(2 * n<SUP>2</SUP>) = 2*log<SUB>2</SUB>(n) + 1 times.
      56             : ///   Every move leads to O(1) work.
      57             : /// - Every state is moved to a new block at most log<SUB>2</SUB>(n) times.
      58             : ///   Every move leads to work proportional to the number of its incoming and
      59             : ///   outgoing transitions.
      60             : /// - Every state becomes a new bottom state at most once.  When this happens,
      61             : ///   this leads to work proportional to log(n) times the number of its
      62             : ///   incoming and outgoing transitions.
      63             : /// When summing this up over all states and transitions, we get that the
      64             : /// algorithm spends time in O(m log n), where m is the number of transitions
      65             : /// and n ist the number of states.
      66             : ///
      67             : /// \author David N. Jansen, Institute of Software, Chinese Academy of
      68             : /// Sciences, Beijing, PR China
      69             : 
      70             : // The file is best viewed on a screen or in a window that is 160 characters
      71             : // wide.  The left 80 columns contain the main text of the program.  The right
      72             : // 80 columns contain assertions and other code used for debugging.
      73             : 
      74             : #include "mcrl2/lts/detail/liblts_bisim_dnj.h"
      75             : #include "mcrl2/lts/lts_lts.h"
      76             : #include "mcrl2/lts/lts_aut.h"
      77             : #include "mcrl2/lts/lts_fsm.h"
      78             : #include "mcrl2/lts/detail/liblts_scc.h"
      79             : #include "mcrl2/lts/detail/liblts_merge.h"
      80             : #include "mcrl2/lts/detail/coroutine.h"
      81             : #include "mcrl2/lts/detail/check_complexity.h"
      82             : #include "mcrl2/lts/detail/fixed_vector.h"
      83             : 
      84             : #include <list>  // for the list of block_bunch-slices
      85             : #include <algorithm> // for std::lower_bound()
      86             : 
      87             : namespace mcrl2
      88             : {
      89             : namespace lts
      90             : {
      91             : namespace detail
      92             : {
      93             :                                                                                 #ifndef NDEBUG
      94             :                                                                                     /// \brief include something in Debug mode
      95             :                                                                                     /// \details In a few places, we have to include an additional parameter to
      96             :                                                                                     /// a function in Debug mode.  While it is in principle possible to use
      97             :                                                                                     /// #ifndef NDEBUG ... #endif, that would lead to distributing the code
      98             :                                                                                     /// over many code lines.  This macro expands to its arguments in Debug
      99             : // state_type and trans_type are defined in check_complexity.h.                     /// mode and to nothing otherwise.
     100             :                                                                                     #define ONLY_IF_DEBUG(...) __VA_ARGS__
     101             :                                                                                     #define ONLY_IF_NOT_DEBUG(...)
     102             :                                                                                 #else
     103             :                                                                                     #define ONLY_IF_DEBUG(...)
     104             :                                                                                     #define ONLY_IF_NOT_DEBUG(...) __VA_ARGS__
     105             :                                                                                 #endif
     106             : /// \brief type used to store label numbers and counts
     107             : typedef std::size_t label_type;
     108             : 
     109             : namespace bisim_dnj
     110             : {
     111             : 
     112             : template <class LTS_TYPE> class bisim_partitioner_dnj;
     113             : 
     114             : /// \class iterator_or_counter
     115             : /// \brief union: either iterator or counter (for initialisation)
     116             : /// \details During initialisation, we need some counters to count the number
     117             : /// of transitions for each state.  To avoid allocating separate memory for
     118             : /// these counters, we store their value in the same place where we later
     119             : /// store an iterator.
     120             : ///
     121             : /// We assume that each such variable starts out as a counter and at some point
     122             : /// becomes an iterator.  That point is marked by
     123             : /// calling convert_to_iterator().  The structure may only be destroyed
     124             : /// afterwards, as the destructor assumes it's an iterator.
     125             : 
     126             : template <class Iterator>
     127             : union iterator_or_counter
     128             : {
     129             :     trans_type count;
     130             :     Iterator begin;
     131             : 
     132             :     /// \brief Construct the object as a counter
     133        1694 :     iterator_or_counter()  {  count = 0;  }
     134             : 
     135             : 
     136             :     /// \brief Convert the object from counter to iterator
     137        1538 :     void convert_to_iterator(const Iterator& other)
     138             :     {
     139        1538 :         new (&begin) Iterator(other);
     140        1538 :     }
     141             : 
     142             : 
     143             :     /// \brief Destruct the object as an iterator
     144        1694 :     ~iterator_or_counter()  {  begin.~Iterator();  }
     145             : };
     146             : 
     147             : 
     148             : /// \class iterator_or_null
     149             : /// \brief union: either iterator or nullptr
     150             : /// \details In some places in the data structures, we sometimes want to store
     151             : /// an iterator but sometimes nothing.  However, iterators normally cannot hold
     152             : /// something equivalent to a null pointer, so this union provides this
     153             : /// functionality.  It relies on the implementation detail that an iterator is
     154             : /// a non-null pointer, which is checked through assertions.
     155             : template <class Iterator>
     156             : union iterator_or_null
     157             : {
     158             :   private:
     159             :     const void* null;
     160             :     Iterator iter;
     161             :   public:
     162             :     /// \brief Construct an object containing no iterator
     163        2873 :     iterator_or_null()
     164             :     {
     165        2873 :         null = nullptr;
     166        2873 :     }
     167             : 
     168             : 
     169             :     /// \brief Construct an object containing a valid iterator
     170             :     explicit iterator_or_null(const Iterator& new_iter)
     171             :     {
     172             :         new (&iter) Iterator(new_iter);                                         assert(nullptr != null);
     173             :     }
     174             : 
     175             : 
     176             :     /// \brief Destruct an object (whether it contains a valid iterator or not)
     177        2873 :     ~iterator_or_null()
     178             :     {
     179        2873 :         if (!is_null())  iter.~Iterator();
     180        2873 :     }
     181             : 
     182             : 
     183             :     /// \brief Compare the object with an iterator
     184             :     /// \details If the object does not contain a valid iterator, it compares
     185             :     /// unequal with the iterator.
     186         128 :     bool operator==(const Iterator& other) const
     187             :     {                                                                           // assert(nullptr != &*other); -- generates a warning
     188         128 :         return (sizeof(null)==sizeof(iter) || !is_null()) && &*iter == &*other;
     189             :     }
     190             : 
     191             : 
     192          62 :     bool operator!=(const Iterator& other) const
     193             :     {
     194          62 :         return !operator==(other);
     195             :     }
     196             : 
     197             : 
     198             :     /// \brief Compare the object with a non-null pointer
     199             :     /// \details If the object does not contain a valid iterator, it compares
     200             :     /// unequal with the pointer.
     201       13463 :     bool operator==(const typename Iterator::value_type* const other) const
     202       13463 :     {                                                                           assert(nullptr != other);
     203       13463 :         return (sizeof(null) == sizeof(iter) || !is_null()) && &*iter == other;
     204             :     }
     205             : 
     206             : 
     207       13357 :     bool operator!=(const typename Iterator::value_type* const other) const
     208             :     {
     209       13357 :         return !operator==(other);
     210             :     }
     211             : 
     212             : 
     213             :     /// \brief Check whether the object contains a valid iterator
     214      134598 :     bool is_null() const  {  return nullptr == null;  }
     215             : 
     216             : 
     217             :     /// \brief Clear the valid iterator stored in the object
     218             :     void clear()
     219             :     {                                                                           assert(!is_null());
     220             :         iter.~Iterator();
     221             :         null = nullptr;
     222             :     }
     223             : 
     224             : 
     225             :     /// \brief Set an object, which does not contain an iterator, to a valid
     226             :     /// iterator
     227        2220 :     void set(const Iterator& new_iter)
     228        2220 :     {                                                                           assert(is_null());
     229        2220 :         new (&iter) Iterator(new_iter);                                         assert(!is_null());
     230        2220 :     }
     231             : 
     232             : 
     233             :     /// \brief Change the valid iterator stored in the object to a new value
     234        3171 :     void change(const Iterator& new_iter)
     235        3171 :     {                                                                           assert(!is_null());
     236        3171 :         iter = new_iter;                                                        assert(!is_null());
     237        3171 :     }
     238             : 
     239             : 
     240             :     /// \brief Read the valid value of the iterator
     241      111704 :     const Iterator& operator()() const
     242      111704 :     {                                                                           assert(!is_null());
     243      111704 :         return iter;
     244             :     }
     245             : };
     246             : 
     247             : class block_bunch_entry;
     248             : typedef bisim_gjkw::fixed_vector<block_bunch_entry>::iterator
     249             :                                                             block_bunch_iter_t;
     250             : typedef bisim_gjkw::fixed_vector<block_bunch_entry>::const_iterator
     251             :                                                       block_bunch_const_iter_t;
     252             : 
     253             : class action_block_entry;
     254             : typedef bisim_gjkw::fixed_vector<action_block_entry>::iterator
     255             :                                                            action_block_iter_t;
     256             : typedef bisim_gjkw::fixed_vector<action_block_entry>::const_iterator
     257             :                                                      action_block_const_iter_t;
     258             : 
     259             : 
     260             : 
     261             : 
     262             : 
     263             : /* ************************************************************************* */
     264             : /*                                                                           */
     265             : /*                   R E F I N A B L E   P A R T I T I O N                   */
     266             : /*                                                                           */
     267             : /* ************************************************************************* */
     268             : 
     269             : 
     270             : 
     271             : 
     272             : 
     273             : class state_info_entry;
     274             : class permutation_entry;
     275             : 
     276             : typedef bisim_gjkw::fixed_vector<state_info_entry>::iterator state_info_iter_t;
     277             : typedef bisim_gjkw::fixed_vector<state_info_entry>::const_iterator
     278             :                                                        state_info_const_iter_t;
     279             : 
     280             : /// \class permutation_t
     281             : /// \brief stores a permutation of the states, ordered by block
     282             : /// \details This is the central concept of the _refinable partition_: the
     283             : /// permutation of the states, such that states belonging to the same block are
     284             : /// adjacent.
     285             : ///
     286             : /// Iterating over the states of a block will
     287             : /// therefore be done using the permutation_t array.
     288             : typedef bisim_gjkw::fixed_vector<permutation_entry> permutation_t;
     289             : typedef permutation_t::iterator permutation_iter_t;
     290             : typedef permutation_t::const_iterator permutation_const_iter_t;
     291             : 
     292             : class block_t;
     293             : class bunch_t;
     294             : 
     295             : class pred_entry;
     296             : class succ_entry;
     297             : typedef bisim_gjkw::fixed_vector<pred_entry>::iterator pred_iter_t;
     298             : typedef bisim_gjkw::fixed_vector<succ_entry>::iterator succ_iter_t;
     299             : 
     300             : typedef bisim_gjkw::fixed_vector<pred_entry>::const_iterator pred_const_iter_t;
     301             : typedef bisim_gjkw::fixed_vector<succ_entry>::const_iterator succ_const_iter_t;
     302             : 
     303             : class block_bunch_slice_t;
     304             : typedef std::list<block_bunch_slice_t>::iterator block_bunch_slice_iter_t;
     305             : typedef std::list<block_bunch_slice_t>::const_iterator
     306             :                                                 block_bunch_slice_const_iter_t;
     307             : 
     308             : enum new_block_mode_t { new_block_is_blue, new_block_is_red };
     309             : 
     310             : /// \class state_info_entry
     311             : /// \brief stores information about a single state
     312             : /// \details This class stores all other information about a state that the
     313             : /// partition needs.  In particular:  the block where the state belongs and the
     314             : /// position in the permutation array (i. e. the inverse of the permutation).
     315        1022 : class state_info_entry
     316             : {
     317             :   public:
     318             :     /// \brief iterator to first inert incoming transition
     319             :     /// \details Non-inert incoming transitions of the state are stored just
     320             :     /// before the element where this iterator points to.
     321             :     ///
     322             :     /// During initialisation, this field also doubles up as a counter for
     323             :     /// the number of incoming transitions, and as the pointer to the first
     324             :     /// incoming inert transition that already has been initialised.
     325             :     iterator_or_counter<pred_iter_t> pred_inert;
     326             : 
     327             :     /// \brief iterator to first inert outgoing transition
     328             :     /// \details Non-inert outgoing transitions of the state are stored just
     329             :     /// before the element where this iterator points to.
     330             :     ///
     331             :     /// During initialisation, this field also doubles up as a counter for the
     332             :     /// number of *inert* outgoing transitions, and as the pointer to the first
     333             :     /// outgoing inert transition that already has been initialised.
     334             :     iterator_or_counter<succ_iter_t> succ_inert;
     335             : 
     336             :     /// block where the state belongs
     337             :     block_t* block;
     338             : 
     339             :     /// position of the state in the permutation array
     340             :     permutation_iter_t pos;
     341             : 
     342             :     /// \brief number of inert transitions to non-blue states
     343             :     /// \details Actually, as we cannot easily count how many inert outgoing
     344             :     /// transitions this state has, we initialize this pointer to
     345             :     /// succ_inert.begin.  Every time we find an outgoing transition to a blue
     346             :     /// state, we increase this iterator; as soon as it no longer points to an
     347             :     /// outgoing transition of this state, we have found all inert outgoing
     348             :     /// transitions.  This requires that after the inert outgoing transitions
     349             :     /// there is a transition that starts in another state, or there is a dummy
     350             :     /// transition.
     351             :     ///
     352             :     /// During initialisation, this field is used to point at the first
     353             :     /// unused slot of the (non-inert) predecessors.  So we always assume
     354             :     /// that it starts as a pred_iter_t, at some moment is converted to a
     355             :     /// succ_const_iter_t, and then stays that way until it is destroyed.
     356             :     union not__t {
     357             :         pred_iter_t used_pred;
     358             :         succ_const_iter_t blue;
     359             : 
     360         511 :         not__t()  {  new (&used_pred) pred_iter_t();  };
     361             : 
     362             : 
     363         459 :         void convert_to_succ_iter_t()
     364             :         {
     365             :             used_pred.~pred_iter_t();
     366         459 :             new (&blue) succ_const_iter_t();
     367         459 :         }
     368             : 
     369             : 
     370         511 :         ~not__t()  {  blue.~succ_const_iter_t();  }
     371             :     } not_;
     372             : 
     373             :     /// \brief iterator to first outgoing transition to the bunch of interest
     374             :     /// \details This iterator generally points to the an outgoing non-inert
     375             :     /// transition of the state, to the first transition in an out-slice.  If
     376             :     /// the bottom state has a transition in the splitter bunch (for a specific
     377             :     /// refinement), this out-slice contains the transitions in the splitter.
     378             :     /// The iterator helps to decide quickly whether a bottom state has a
     379             :     /// transition in the splitter.
     380             :     ///
     381             :     /// During initialisation, this field also doubles up as a counter for the
     382             :     /// number of *non-inert* outgoing transitions, and as the pointer to the
     383             :     /// first outgoing transition that already has been initialised.
     384             :     iterator_or_counter<succ_iter_t> current_out_slice;
     385             : 
     386             :     bool surely_has_transition_in(                                              ONLY_IF_DEBUG( const bisim_gjkw::fixed_vector<succ_entry>& succ, )
     387             :                                   const bunch_t* bunch) const;
     388             :     bool surely_has_no_transition_in(                                           ONLY_IF_DEBUG( const bisim_gjkw::fixed_vector<succ_entry>& succ, )
     389             :                                      const bunch_t* bunch) const;
     390             :                                                                                 #ifndef NDEBUG
     391             :                                                                                     /// \brief print a short state identification for debugging
     392           0 :                                                                                     std::string debug_id_short(const bisim_gjkw::fixed_vector<state_info_entry>
     393             :                                                                                                                                             & state_info) const
     394           0 :                                                                                     {   assert(&*state_info.cbegin() <= this);
     395           0 :                                                                                         assert(this <= &state_info.cend()[-2]);
     396           0 :                                                                                         return std::to_string(this - &*state_info.cbegin());
     397             :                                                                                     }
     398             : 
     399             :                                                                                     /// \brief print a state identification for debugging
     400           0 :                                                                                     std::string debug_id(const bisim_gjkw::fixed_vector<state_info_entry>&
     401             :                                                                                                                                               state_info) const
     402             :                                                                                     {
     403           0 :                                                                                         return "state " + debug_id_short(state_info);
     404             :                                                                                     }
     405             : 
     406             :                                                                                     mutable bisim_gjkw::check_complexity::state_dnj_counter_t work_counter;
     407             :                                                                                 #endif
     408             : };
     409             : 
     410             : 
     411             : class permutation_entry {
     412             :   public:
     413             :     state_info_iter_t st;
     414             : 
     415         459 :     permutation_entry() = default;
     416             : 
     417        1391 :     permutation_entry(const permutation_entry&& other)
     418        1391 :     {
     419        1391 :         st = other.st;
     420             :         // The move constructor is called when a temporary object is created;
     421             :         // in that case, it is not necessary to set the pos pointer.
     422             :         // st->pos += this - &*st->pos; // st->pos = iterator(this);
     423        1391 :     }
     424        2781 :     void operator=(const permutation_entry&& other)
     425             :     {
     426             :         // The move assignment operator is called when an object is moved to
     427             :         // its final place. Therefore, we have to adapt the pos pointer.  Note
     428             :         // that std::swap also uses move assignment, so we automatically get
     429             :         // the correct behaviour there.
     430        2781 :         st = other.st;
     431        2781 :         st->pos += this - &*st->pos; // st->pos = iterator(this);
     432        2781 :     }
     433             : };
     434             : 
     435             : 
     436             : /// \class block_t
     437             : /// \brief stores information about a block
     438             : /// \details A block corresponds to a slice of the permutation array.  As the
     439             : /// number of blocks is initially unknown, we will allocate instances of this
     440             : /// class dynamically.
     441             : ///
     442             : /// The slice in the permutation array containing the states of the block is
     443             : /// subdivided into the following subslices (in this order):
     444             : /// 1. unmarked bottom states
     445             : /// 2. marked bottom states (initially empty)
     446             : /// 3. unmarked non-bottom states
     447             : /// 4. marked non-bottom states (initially empty)
     448             : ///
     449             : /// A state should be marked iff it is a predecessor of the current splitter
     450             : /// (through a strong transition).  The marking is later extended to the red
     451             : /// states;  that are the states with a weak transition to the splitter.
     452             : ///
     453             : /// (During the execution of some functions, blocks are subdivided further;
     454             : /// however, as these subdivisions are local to a single function, they are not
     455             : /// stored here.)
     456         260 : class block_t
     457             : {
     458             :   public:
     459             :     /// \brief iterator to the first state of the block
     460             :     permutation_iter_t begin;
     461             : 
     462             :     /// \brief iterator to the first marked bottom state of the block
     463             :     permutation_iter_t marked_bottom_begin;
     464             : 
     465             :     /// \brief iterator to the first non-bottom state of the block
     466             :     permutation_iter_t nonbottom_begin;
     467             : 
     468             :     /// \brief iterator to the first marked non-bottom state of the block
     469             :     permutation_iter_t marked_nonbottom_begin;
     470             : 
     471             :     /// \brief iterator past the last state of the block
     472             :     permutation_iter_t end;
     473             : 
     474             :     /// \brief list of stable block_bunch-slices with transitions from this
     475             :     /// block
     476             :     std::list<block_bunch_slice_t> stable_block_bunch;
     477             : 
     478             :     /// \brief unique sequence number of this block
     479             :     /// \details After the stuttering equivalence algorithm has terminated,
     480             :     /// this number is used as a state number in the quotient LTS.
     481             :     const state_type seqnr;
     482             : 
     483             :     /// \brief constructor
     484             :     /// \details The constructor initialises the block to: all states are
     485             :     /// bottom states, no state is marked.
     486             :     /// \param new_begin   initial iterator to the first state of the block
     487             :     /// \param new_end     initial iterator past the last state of the block
     488             :     /// \param new_seqnr   is the sequence number of the new block
     489         260 :     block_t(const permutation_iter_t& new_begin,
     490             :                        const permutation_iter_t& new_end, state_type new_seqnr)
     491             :       : begin(new_begin),
     492             :         marked_bottom_begin(new_end),
     493             :         nonbottom_begin(new_end),
     494             :         marked_nonbottom_begin(new_end),
     495             :         end(new_end),
     496             :         stable_block_bunch(),
     497         260 :         seqnr(new_seqnr)
     498         260 :     {                                                                           assert(new_begin < new_end);
     499         260 :     }
     500             : 
     501             : 
     502             :     /// provides the number of states in the block
     503       17495 :     state_type size() const
     504       17495 :     {                                                                           assert(begin <= marked_bottom_begin);  assert(marked_nonbottom_begin <= end);
     505       17495 :                                                                                 assert(marked_bottom_begin <= nonbottom_begin);
     506       17495 :                                                                                 assert(nonbottom_begin <= marked_nonbottom_begin);
     507       17495 :         return end - begin;
     508             :     }
     509             : 
     510             : 
     511             :     /// \brief provides the number of bottom states in the block
     512          99 :     state_type bottom_size() const
     513          99 :     {                                                                           assert(begin <= marked_bottom_begin);  assert(marked_nonbottom_begin <= end);
     514          99 :                                                                                 assert(marked_bottom_begin <= nonbottom_begin);
     515          99 :                                                                                 assert(nonbottom_begin <= marked_nonbottom_begin);
     516          99 :         return nonbottom_begin - begin;
     517             :     }
     518             : 
     519             : 
     520             :     /// \brief provides the number of marked bottom states in the block
     521        2586 :     state_type marked_bottom_size() const
     522        2586 :     {                                                                           assert(begin <= marked_bottom_begin);  assert(marked_nonbottom_begin <= end);
     523        2586 :                                                                                 assert(marked_bottom_begin <= nonbottom_begin);
     524        2586 :                                                                                 assert(nonbottom_begin <= marked_nonbottom_begin);
     525        2586 :         return nonbottom_begin - marked_bottom_begin;
     526             :     }
     527             : 
     528             : 
     529             :     /// \brief provides the number of marked states in the block
     530        2371 :     state_type marked_size() const
     531             :     {
     532        2371 :         return end - marked_nonbottom_begin + marked_bottom_size();
     533             :     }
     534             : 
     535             : 
     536             :     /// provides the number of unmarked bottom states in the block
     537         839 :     state_type unmarked_bottom_size() const
     538         839 :     {                                                                           assert(begin <= marked_bottom_begin);  assert(marked_nonbottom_begin <= end);
     539         839 :                                                                                 assert(marked_bottom_begin <= nonbottom_begin);
     540         839 :                                                                                 assert(nonbottom_begin <= marked_nonbottom_begin);
     541         839 :         return marked_bottom_begin - begin;
     542             :     }
     543             : 
     544             : 
     545             :     /// provides the number of unmarked nonbottom states in the block
     546         416 :     state_type unmarked_nonbottom_size() const
     547         416 :     {                                                                           assert(begin <= marked_bottom_begin);  assert(marked_nonbottom_begin <= end);
     548         416 :                                                                                 assert(marked_bottom_begin <= nonbottom_begin);
     549         416 :                                                                                 assert(nonbottom_begin <= marked_nonbottom_begin);
     550         416 :         return marked_nonbottom_begin - nonbottom_begin;
     551             :     }
     552             : 
     553             : 
     554             :     /// \brief mark a non-bottom state
     555             :     /// \details Marking is done by moving the state to the slice of the marked
     556             :     /// non-bottom states of the block.
     557             :     /// \param s the non-bottom state that has to be marked
     558             :     /// \returns true if the state was not marked before
     559         262 :     bool mark_nonbottom(const permutation_iter_t& s)
     560         262 :     {                                                                           assert(this == s->st->block);  assert(nonbottom_begin <= s);  assert(s < end);
     561         262 :                                                                                 assert(begin <= marked_bottom_begin);
     562         262 :                                                                                 assert(marked_bottom_begin <= nonbottom_begin);
     563         262 :                                                                                 assert(nonbottom_begin <= marked_nonbottom_begin);
     564         262 :         if (marked_nonbottom_begin <= s)  return false;                         assert(marked_nonbottom_begin <= end);
     565         242 :         std::swap(*s, *--marked_nonbottom_begin);                               assert(nonbottom_begin <= marked_nonbottom_begin);
     566         242 :         return true;
     567             :     }
     568             : 
     569             : 
     570             :     /// \brief mark a state
     571             :     /// \details Marking is done by moving the state to the slice of the marked
     572             :     /// bottom or non-bottom states of the block.
     573             :     /// \param s the state that has to be marked
     574             :     /// \returns true if the state was not marked before
     575         797 :     bool mark(const permutation_iter_t& s)
     576         797 :     {                                                                           assert(this == s->st->block);  assert(begin <= s);
     577         797 :         if (s < nonbottom_begin)
     578         651 :         {                                                                       assert(begin <= marked_bottom_begin);  assert(marked_nonbottom_begin <= end);
     579         651 :                                                                                 assert(nonbottom_begin <= marked_nonbottom_begin);
     580         651 :             if (marked_bottom_begin <= s)  return false;                        assert(marked_bottom_begin <= nonbottom_begin);
     581         615 :             std::swap(*s, *--marked_bottom_begin);                              assert(begin <= marked_bottom_begin);
     582         615 :             return true;
     583             :         }
     584         146 :         return mark_nonbottom(s);
     585             :     }
     586             : 
     587             : 
     588             :     /// \brief refine a block
     589             :     /// \details This function is called after a refinement function has found
     590             :     /// where to split the block into unmarked (blue) and marked (red) states.
     591             :     /// It creates a new block for the smaller subblock.
     592             :     /// \param   new_block_mode indicates whether the blue or the red block
     593             :     ///          should be the new one.  (This parameter is necessary in case
     594             :     ///          the two halves have exactly the same size.)
     595             :     /// \param   new_seqnr is the sequence number of the new block
     596             :     /// \returns pointer to the new block
     597         208 :     block_t* split_off_block(enum new_block_mode_t const new_block_mode,        ONLY_IF_DEBUG( const permutation_t& permutation, )
     598             :                                                           state_type new_seqnr)
     599         208 :     {                                                                           assert(0 < marked_size());  assert(0 < unmarked_bottom_size());
     600             :         // swap contents
     601             : 
     602             :         // The structure of a block is
     603             :         // |  unmarked  |   marked   |  unmarked  |   marked   |
     604             :         // |   bottom   |   bottom   | non-bottom | non-bottom |
     605             :         // We have to swap the marked bottom with the unmarked non-bottom
     606             :         // states.
     607             :         //
     608             :         // It is not necessary to reset the nottoblue counters; these counters
     609             :         // are anyway only valid for the maybe-blue states.
     610             : 
     611             :         // create a new block
     612             :         block_t* new_block;
     613             :         {
     614         208 :             state_type swapcount(std::min(marked_bottom_size(),
     615         416 :                                                    unmarked_nonbottom_size()));
     616             :             {
     617             :                 permutation_iter_t const splitpoint(marked_bottom_begin +
     618         208 :                                                     unmarked_nonbottom_size()); assert(begin < splitpoint);  assert(splitpoint < end);
     619         208 :                                                                                 assert(splitpoint->st->pos == splitpoint);
     620         208 :                 if (new_block_is_blue == new_block_mode)
     621          73 :                 {                                                               assert((state_type) (splitpoint - begin) <= size()/2);
     622          73 :                     new_block = new block_t(begin, splitpoint, new_seqnr);
     623          73 :                     new_block->nonbottom_begin = marked_bottom_begin;
     624             : 
     625             :                     // adapt the old block: it only keeps the red states
     626          73 :                     begin = splitpoint;
     627          73 :                     nonbottom_begin = marked_nonbottom_begin;
     628             :                 }
     629             :                 else
     630         135 :                 {                                                               assert(new_block_is_red == new_block_mode);
     631         135 :                     new_block = new block_t(splitpoint, end, new_seqnr);        assert((state_type) (end - splitpoint) <= size()/2);
     632         135 :                     new_block->nonbottom_begin = marked_nonbottom_begin;
     633             : 
     634             :                     // adapt the old block: it only keeps the blue states
     635         135 :                     end = splitpoint;
     636         135 :                     nonbottom_begin = marked_bottom_begin;
     637             :                 }
     638         208 :             }                                                                   ONLY_IF_DEBUG( new_block->work_counter = work_counter; )
     639             : 
     640         208 :             if (0 < swapcount)
     641             :             {
     642             :                 // vector swap the states:
     643          34 :                 permutation_iter_t pos1(marked_bottom_begin),
     644          34 :                                                   pos2(marked_nonbottom_begin); assert(pos1 < pos2);
     645          34 :                 permutation_entry const temp(std::move(*pos1));
     646           7 :                 for (;;)
     647             :                 {
     648          41 :                     --pos2;                                                     assert(pos1 < pos2);
     649          41 :                     *pos1 = std::move(*pos2);
     650          41 :                     ++pos1;
     651          41 :                     if (0 >= --swapcount)  break;                               assert(pos1 < pos2);
     652           7 :                     *pos2 = std::move(*pos1);                                   // mCRL2complexity(new_block_is_blue == new_block_mode ? pos1[-1] : *pos2, ...)
     653             :                 }                                                               // -- overapproximated by the call at the end
     654          34 :                 *pos2 = std::move(temp);                                        // mCRL2complexity(new_block_is_blue == new_block_mode ? pos1[-1] : *pos2, ...)
     655             :             }                                                                   // -- overapproximated by the call at the end
     656             :                                                                                 #ifndef NDEBUG
     657         208 :                                                                                     permutation_const_iter_t s_iter(begin);  assert(s_iter < end);
     658        4028 :                                                                                     do  assert(s_iter->st->pos == s_iter);
     659        2014 :                                                                                     while (++s_iter < end);
     660             :                                                                                 #endif
     661             :         }
     662             :         // unmark all states in both blocks
     663         208 :         marked_nonbottom_begin = end;                                           assert(new_block->marked_nonbottom_begin == new_block->end);
     664         208 :         marked_bottom_begin = nonbottom_begin;
     665         208 :         new_block->marked_bottom_begin = new_block->nonbottom_begin;            assert(new_block->size() <= size());
     666             : 
     667             :         // set the block pointer of states in the new block
     668         208 :         permutation_iter_t s_iter(new_block->begin);                            assert(s_iter < new_block->end);
     669         393 :         do
     670         393 :         {                                                                       assert(s_iter->st->pos == s_iter);
     671         393 :             s_iter->st->block = new_block;                                      // mCRL2complexity (*s_iter, ...) -- subsumed in the call below
     672             :         }
     673         601 :         while (++s_iter < new_block->end);                                      mCRL2complexity(new_block, add_work(bisim_gjkw::check_complexity::
     674             :                                                                                                     split_off_block, bisim_gjkw::check_complexity::log_n -
     675             :                                                                                                     bisim_gjkw::check_complexity::ilog2(new_block->size())),
     676             :                                                                                                                                                   permutation);
     677         208 :         return new_block;
     678             :     }
     679             :                                                                                 #ifndef NDEBUG
     680             :                                                                                     /// \brief print a block identification for debugging
     681           0 :                                                                                     std::string debug_id(const permutation_t& permutation) const
     682           0 :                                                                                     {   assert(permutation.cbegin() <= begin);  assert(begin < end);
     683           0 :                                                                                         assert(begin <= marked_bottom_begin);
     684           0 :                                                                                         assert(marked_bottom_begin <= nonbottom_begin);
     685           0 :                                                                                         assert(nonbottom_begin <= marked_nonbottom_begin);
     686           0 :                                                                                         assert(marked_nonbottom_begin <= end);
     687           0 :                                                                                         assert(end <= permutation.cend());
     688           0 :                                                                                         return "block [" + std::to_string(begin - permutation.cbegin()) +
     689           0 :                                                                                                "," + std::to_string(end - permutation.cbegin()) + ") (#" +
     690           0 :                                                                                                                                    std::to_string(seqnr) + ")";
     691             :                                                                                     }
     692             : 
     693             :                                                                                     mutable bisim_gjkw::check_complexity::block_dnj_counter_t work_counter;
     694             :                                                                                 #endif
     695             : };
     696             : 
     697             : 
     698             : /// \class part_state_t
     699             : /// \brief refinable partition data structure
     700             : /// \details This class collects all information about a partition of the
     701             : /// states.
     702             : class part_state_t
     703             : {
     704             :   public:
     705             :     /// \brief permutation array
     706             :     /// \details This is the central element of the data structure:  In this
     707             :     /// array, states that belong to the same block are stored in adjacent
     708             :     /// elements.
     709             :     permutation_t permutation;
     710             : 
     711             :     /// \brief array with all other information about states
     712             :     /// \details We allocate 1 additional dummy ``state'' at the end of the
     713             :     /// array, to get an illegal state that can actually be dereferenced.
     714             :     bisim_gjkw::fixed_vector<state_info_entry> state_info;
     715             : 
     716             :     /// \brief total number of blocks with unique sequence number allocated
     717             :     /// \details Upon starting the stuttering equivalence algorithm, the number
     718             :     /// of blocks must be zero.
     719             :     state_type nr_of_blocks;
     720             : 
     721             :     /// \brief constructor
     722             :     /// \details The constructor allocates memory and makes the permutation and
     723             :     /// state_info arrays consistent with each other, but does not actually
     724             :     /// initialise the partition.  Immediately afterwards, the initialisation
     725             :     /// will be done in `bisim_partitioner_dnj::create_initial_partition()`.
     726             :     /// \param num_states number of states in the LTS
     727          52 :     part_state_t(state_type num_states)
     728             :       : permutation(num_states),
     729             :         state_info(num_states + 1),
     730          52 :         nr_of_blocks(0)
     731          52 :     {                                                                           assert(1 < num_states);
     732          52 :         permutation_iter_t perm_iter(permutation.begin());
     733          52 :         state_info_iter_t state_iter(state_info.begin());
     734          52 :                                                                                 assert(perm_iter < permutation.end());
     735        1377 :         do
     736             :         {
     737         459 :             state_iter->pos = perm_iter;
     738         459 :             perm_iter->st = state_iter;
     739             :         }
     740         970 :         while (++state_iter, ++perm_iter < permutation.end());                  assert(state_iter == state_info.cend() - 1);
     741          52 :     }
     742             : 
     743             :     /// \brief destructor
     744             :     /// \details The destructor also deallocates the blocks, as they are not
     745             :     /// directly referenced from anywhere.
     746          52 :     ~part_state_t()
     747         104 :     {                                                                           ONLY_IF_DEBUG( state_type deleted_blocks(0); )
     748          52 :         permutation_iter_t perm_iter(permutation.end());                        assert(permutation.begin() < perm_iter);
     749         520 :         do
     750             :         {
     751         260 :             block_t* const B(perm_iter[-1].st->block);                          assert(B->end == perm_iter);
     752         260 :             perm_iter = B->begin;                                               ONLY_IF_DEBUG( ++deleted_blocks; )
     753         260 :             delete B;
     754             :         }
     755         572 :         while (permutation.begin() < perm_iter);                                assert(deleted_blocks == nr_of_blocks);
     756          52 :     }
     757             : 
     758             :     /// \brief calculate the size of the state space
     759             :     /// \returns the number of states in the LTS
     760         104 :     state_type state_size() const  {  return permutation.size();  }
     761             : 
     762             :     /// \brief find the block of a state
     763             :     /// \param s number of the state
     764             :     /// \returns a pointer to the block where state s resides in
     765          54 :     const block_t* block(state_type s) const
     766             :     {
     767          54 :         return state_info[s].block;
     768             :     }
     769             :                                                                                 #ifndef NDEBUG
     770             :                                                                                     /// \brief print a slice of the partition (typically a block)
     771             :                                                                                     /// \details If the slice indicated by the parameters is not empty, the
     772             :                                                                                     /// message and the states in this slice will be printed.
     773             :                                                                                     /// \param message      text printed as a title if the slice is not empty
     774             :                                                                                     /// \param begin_print  iterator to the beginning of the slice
     775             :                                                                                     /// \param end_print    iterator past the end of the slice
     776           0 :                                                                                     void print_block(const block_t* B, const char* const message,
     777             :                                                                                                                permutation_const_iter_t begin_print,
     778             :                                                                                                                const permutation_const_iter_t& end_print) const
     779           0 :                                                                                     {   assert(B->begin <= begin_print);  assert(end_print <= B->end);
     780           0 :                                                                                         if (end_print == begin_print)  return;
     781             : 
     782           0 :                                                                                         mCRL2log(log::debug, "bisim_dnj") << '\t' << message
     783           0 :                                                                                                              << (1 < end_print - begin_print ? "s:\n" : ":\n");
     784           0 :                                                                                         assert(begin_print < end_print);
     785           0 :                                                                                         do
     786             :                                                                                         {
     787           0 :                                                                                             mCRL2log(log::debug,"bisim_dnj") << "\t\t"
     788           0 :                                                                                                                       << begin_print->st->debug_id(state_info);
     789           0 :                                                                                             if (B != begin_print->st->block)
     790             :                                                                                             {
     791           0 :                                                                                                 mCRL2log(log::debug,"bisim_dnj") << ", inconsistent: points "
     792           0 :                                                                                                         "to " << begin_print->st->block->debug_id(permutation);
     793             :                                                                                             }
     794           0 :                                                                                             if (begin_print != begin_print->st->pos)
     795             :                                                                                             {
     796           0 :                                                                                                 mCRL2log(log::debug, "bisim_dnj")
     797           0 :                                                                                                                << ", inconsistent pointer to state_info_entry";
     798             :                                                                                             }
     799           0 :                                                                                             mCRL2log(log::debug, "bisim_dnj") << '\n';
     800             :                                                                                         }
     801           0 :                                                                                         while (++begin_print < end_print);
     802             :                                                                                     }
     803             : 
     804             :                                                                                     /// \brief print the partition per block
     805             :                                                                                     /// \details The function prints all blocks in order.  For each block, it
     806             :                                                                                     /// lists its states, separated into nonbottom and bottom states.
     807         329 :                                                                                     void print_part() const
     808         329 :                                                                                     {   assert(permutation.cbegin() < permutation.cend());
     809         329 :                                                                                         if (!mCRL2logEnabled(log::debug, "bisim_dnj"))  return;
     810           0 :                                                                                         const block_t* B(permutation.cbegin()->st->block);
     811           0 :                                                                                         do
     812             :                                                                                         {
     813           0 :                                                                                             mCRL2log(log::debug, "bisim_dnj")<<B->debug_id(permutation)<<":\n";
     814           0 :                                                                                             print_block(B, "Bottom state", B->begin, B->marked_bottom_begin);
     815           0 :                                                                                             print_block(B, "Marked bottom state",
     816           0 :                                                                                                                    B->marked_bottom_begin, B->nonbottom_begin);
     817           0 :                                                                                             print_block(B, "Non-bottom state",
     818           0 :                                                                                                                 B->nonbottom_begin, B->marked_nonbottom_begin);
     819           0 :                                                                                             print_block(B, "Marked non-bottom state",
     820           0 :                                                                                                                             B->marked_nonbottom_begin, B->end);
     821             :                                                                                         // go to next block
     822             :                                                                                         }
     823           0 :                                                                                         while (B->end < permutation.cend() && (B = B->end->st->block, true));
     824             :                                                                                     }
     825             : 
     826             :                                                                                     /// \brief asserts that the partition of states is consistent
     827             :                                                                                     /// \details It also requires that no states are marked.
     828         278 :                                                                                     void assert_consistency(bool branching) const
     829             :                                                                                     {
     830         278 :                                                                                         permutation_const_iter_t perm_iter(permutation.cbegin());
     831         278 :                                                                                         assert(perm_iter < permutation.cend());
     832        4796 :                                                                                         do
     833             :                                                                                         {
     834        2398 :                                                                                             const block_t* const block(perm_iter->st->block);
     835             :                                                                                             // block is consistent:
     836        2398 :                                                                                             assert(block->begin == perm_iter);
     837        2398 :                                                                                             assert(block->begin < block->marked_bottom_begin);
     838        2398 :                                                                                             assert(block->marked_bottom_begin == block->nonbottom_begin);
     839        2398 :                                                                                             assert(block->nonbottom_begin <= block->marked_nonbottom_begin);
     840        2398 :                                                                                             assert(block->marked_nonbottom_begin == block->end);
     841        2398 :                                                                                             assert(branching || block->nonbottom_begin == block->end);
     842             :                                                                                             assert(0 <= block->seqnr);
     843        2398 :                                                                                             assert(block->seqnr < nr_of_blocks);
     844        4796 :                                                                                             unsigned const max_block(bisim_gjkw::check_complexity::log_n -
     845        4796 :                                                                                                            bisim_gjkw::check_complexity::ilog2(block->size()));
     846        2398 :                                                                                             mCRL2complexity(block, no_temporary_work(max_block), permutation);
     847             : 
     848             :                                                                                             // states in the block are consistent:
     849        6492 :                                                                                             do
     850             :                                                                                             {
     851        6492 :                                                                                                 state_info_const_iter_t const state(perm_iter->st);
     852             :                                                                                                 // assert(part_tr.pred.cbegin()+1 <= state->pred_inert.begin);
     853       25690 :                                                                                                 assert(state_info.cend() - 2 == state ||
     854       19476 :                                                                                                          state->pred_inert.begin <= state[1].pred_inert.begin);
     855             :                                                                                                 // assert(state->pred_inert.begin <= part_tr.pred.cend() - 1);
     856             :                                                                                                 // assert(part_tr.succ.cbegin() + 1 <=
     857             :                                                                                                 //                             state->current_out_slice.begin);
     858        6492 :                                                                                                 assert(state->current_out_slice.begin <=
     859        6492 :                                                                                                                                       state->succ_inert.begin);
     860             :                                                                                                 // assert(state->succ_inert.begin <= part_tr.succ.cend() - 1);
     861             :                                                                                                 // assert(state->current_out_slice.begin ==
     862             :                                                                                                 //                                   state->succ_inert.begin ||
     863             :                                                                                                 //   state == state->current_out_slice.begin->
     864             :                                                                                                 //                                  block_bunch->pred->source);
     865        6492 :                                                                                                 if (perm_iter < block->nonbottom_begin)
     866             :                                                                                                 {
     867       21134 :                                                                                                     assert(state_info.cend() - 2 == state || state->
     868       16059 :                                                                                                          succ_inert.begin <= state[1].current_out_slice.begin);
     869             :                                                                                                     // assert(state->succ_inert.begin==part_tr.succ.cend()-1 ||
     870             :                                                                                                     //    state <
     871             :                                                                                                     //     state->succ_inert.begin->block_bunch->pred->source);
     872        5353 :                                                                                                     mCRL2complexity(state, no_temporary_work(max_block, true),
     873             :                                                                                                                                                    state_info);
     874             :                                                                                                 }
     875             :                                                                                                 else
     876             :                                                                                                 {
     877             :                                                                                                     // assert(state->succ_inert.begin < part_tr.succ.cend()-1);
     878        4556 :                                                                                                     assert(state_info.cend() - 2 == state || state->
     879        3417 :                                                                                                           succ_inert.begin < state[1].current_out_slice.begin);
     880             :                                                                                                     //assert(state ==
     881             :                                                                                                     //     state->succ_inert.begin->block_bunch->pred->source);
     882        1139 :                                                                                                     mCRL2complexity(state, no_temporary_work(max_block, false),
     883             :                                                                                                                                                    state_info);
     884             :                                                                                                 }
     885        6492 :                                                                                                 assert(block == state->block);
     886        6492 :                                                                                                 assert(perm_iter == state->pos);
     887             :                                                                                             }
     888        6492 :                                                                                             while (++perm_iter < block->end);
     889        2398 :                                                                                             assert(perm_iter == block->end);
     890             :                                                                                         }
     891        4796 :                                                                                         while (perm_iter < permutation.cend());
     892         278 :                                                                                     }
     893             :                                                                                 #endif
     894             : };
     895             : 
     896             : ///@} (end of group part_state)
     897             : 
     898             : 
     899             : 
     900             : 
     901             : 
     902             : /* ************************************************************************* */
     903             : /*                                                                           */
     904             : /*                           T R A N S I T I O N S                           */
     905             : /*                                                                           */
     906             : /* ************************************************************************* */
     907             : 
     908             : 
     909             : 
     910             : 
     911             : 
     912             : /// \defgroup part_trans
     913             : /// \brief data structures for transitions used during partition refinement
     914             : /// \details These definitions provide a partition for transition data
     915             : /// structure that can be used for the partition refinement algorithm.
     916             : ///
     917             : /// Basically, transitions are stored in four arrays:
     918             : /// - `pred`: transitions ordered by goal state, to allow finding all
     919             : ///   predecessors of a goal state.
     920             : /// - `succ`: transitions ordered by source state and bunch, to
     921             : ///   allow finding all successors of a source state.  Given a transition in
     922             : ///   this array, it is easy to find all transitions from the same source state
     923             : ///   in the same bunch.
     924             : /// - `action_block`: a permutation of the transitions such that transitions
     925             : ///   in the same bunch are adjacent, and within each bunch transitions with
     926             : ///   the same action label and target block.
     927             : ///   (Between two action_block-slices with different actions, there is a dummy
     928             : ///   entry.)
     929             : /// - `block_bunch`: a permutation of the transitions suche that transitions
     930             : ///   from the same block in the same bunch are adjacent.
     931             : ///   (At the beginning of the block_bunch array, there is a dummy entry.)
     932             : /// Entries in these four arrays are linked with each other with circular
     933             : /// iterators, so that one can find the corresponding entry in another array.
     934             : ///
     935             : /// Within this sort order, inert transitions are always placed after non-inert
     936             : /// transitions.
     937             : ///
     938             : /// state_info_entry and block_t (defined above) contain pointers to the slices
     939             : /// of these arrays.  For bunches and block_bunch-slices, we additionally
     940             : /// create _descriptors_ that hold some information about the slice.
     941             : 
     942             : ///@{
     943             : 
     944             : /// \brief information about a transition sorted per source state
     945        1408 : class succ_entry
     946             : {
     947             :   public:
     948             :     /// \brief circular iterator to link the four transition arrays
     949             :     block_bunch_iter_t block_bunch;
     950             : 
     951             :     /// \brief pointer to delimit the slice of transitions in the same bunch
     952             :     /// \details For most transitions, this pointer points to the first
     953             :     /// transition that starts in the same state and belongs to the same
     954             :     /// bunch.  But if this transition is the first such transition, the
     955             :     /// pointer points to the last such transition (not one past the last, like
     956             :     /// otherwise in C and C++).
     957             :     ///
     958             :     /// For inert transitions, the value is nullptr.
     959             :     iterator_or_null<succ_iter_t> begin_or_before_end;
     960             : 
     961             : 
     962             :     /// \brief find the beginning of the out-slice
     963             :     succ_iter_t out_slice_begin(                                                ONLY_IF_DEBUG( const bisim_gjkw::fixed_vector<succ_entry>& succ )
     964             :                                 ) const;
     965             : 
     966             : 
     967             :     /// \brief find the bunch of the transition
     968             :     bunch_t* bunch() const;
     969             :                                                                                 #ifndef NDEBUG
     970             :                                                                                     template <class LTS_TYPE>
     971             :                                                                                     static inline void add_work_to_out_slice(
     972             :                                                                                         const bisim_partitioner_dnj<LTS_TYPE>& partitioner,
     973             :                                                                                         succ_const_iter_t out_slice_begin, enum bisim_gjkw::check_complexity::
     974             :                                                                                                              counter_type const ctr, unsigned const max_value);
     975             :                                                                                 #endif
     976             : };
     977             : 
     978             : 
     979             : /// \brief information about a transition sorted per (source block, bunch) pair
     980        1304 : class block_bunch_entry
     981             : {
     982             :   public:
     983             :     /// \brief circular iterator to link the four transition arrays
     984             :     pred_iter_t pred;
     985             : 
     986             :     /// \brief block_bunch-slice of which this transition is part
     987             :     /// \details The slice is null iff the transition is inert.
     988             :     iterator_or_null<block_bunch_slice_iter_t> slice;
     989             : };
     990             : 
     991             : 
     992             : /// \brief information about a transition sorted per target state
     993             : /// \details As I expect the transitions in this array to be moved least often,
     994             : /// I store the information on source and target state in this entry.  (It
     995             : /// could be stored in any of the four arrays describing the transition;
     996             : /// through the circular iterators, the information would be available anyway.)
     997         704 : class pred_entry
     998             : {
     999             :   public:
    1000             :     /// \brief circular iterator to link the four transition arrays
    1001             :     action_block_iter_t action_block;
    1002             : 
    1003             :     /// \brief source state of the transition
    1004             :     state_info_iter_t source;
    1005             : 
    1006             :     /// \brief target state of the transition
    1007             :     state_info_iter_t target;
    1008             :                                                                                 #ifndef NDEBUG
    1009             :                                                                                     /// \brief print a short transition identification for debugging
    1010           0 :                                                                                     std::string debug_id_short(const bisim_gjkw::fixed_vector<state_info_entry>
    1011             :                                                                                                                                             & state_info) const
    1012             :                                                                                     {
    1013           0 :                                                                                         return "from " + source->debug_id_short(state_info) +
    1014           0 :                                                                                                                    " to " + target->debug_id_short(state_info);
    1015             :                                                                                     }
    1016             : 
    1017             :                                                                                     /// \brief print a transition identification for debugging
    1018             :                                                                                     template <class LTS_TYPE>
    1019             :                                                                                     std::string debug_id(const bisim_partitioner_dnj<LTS_TYPE>& partitioner)
    1020             :                                                                                                                                                          const;
    1021             : 
    1022             :                                                                                     mutable bisim_gjkw::check_complexity::trans_dnj_counter_t work_counter;
    1023             :                                                                                 #endif
    1024             : };
    1025             : 
    1026             : 
    1027             : /// \brief information about a transition sorted per (action, target block)
    1028             : /// pair
    1029        1418 : class action_block_entry
    1030             : {
    1031             :   public:
    1032             :     /// \brief circular iterator to link the four transition arrays
    1033             :     /// \details This iterator can be nullptr because we need to insert dummy
    1034             :     /// elements between two action_block-slices during initialisation, to make
    1035             :     /// it easier for first_move_transition_to_new_action_block() to detect
    1036             :     /// whether two action_block-slices belong to the same action or not.
    1037             :     iterator_or_null<succ_iter_t> succ;
    1038             : 
    1039             :     /// \brief pointer to delimit the slice of transitions in the same (action,
    1040             :     /// block) pair
    1041             :     /// \details For most transitions, this pointer points to the first
    1042             :     /// transition that has the same action and goes to the same block.  But if
    1043             :     /// this transition is the first such transition, the pointer points to the
    1044             :     /// last such transition (not one past the last, like otherwise in C and
    1045             :     /// C++).
    1046             :     ///
    1047             :     /// For inert transitions and dummy entries, the value is nullptr.
    1048             :     iterator_or_null<action_block_iter_t> begin_or_before_end;
    1049             : 
    1050             :     /// \brief find the beginning of the action_block-slice
    1051         453 :     action_block_iter_t action_block_slice_begin(                               ONLY_IF_DEBUG( const bisim_gjkw::fixed_vector<action_block_entry>&
    1052             :                                                                                         action_block, action_block_const_iter_t action_block_orig_inert_begin )
    1053             :                                                  ) const
    1054             :     {
    1055         453 :         action_block_iter_t result(begin_or_before_end());
    1056         453 :         if (this < &*result)
    1057          94 :         {                                                                       assert(this == &*result->begin_or_before_end());
    1058          94 :             result += this - &*result; // result = action_block_iter_t(this);   // The following assertion does not always hold: the function is called
    1059             :         }                                                                       // immediately after a block is refined, so it may be the case that the
    1060             :                                                                                 // transitions are still to be moved to different slices.
    1061             :                                                                                 // assert(succ()->block_bunch->pred->target->block ==
    1062             :                                                                                 //                           result->succ()->block_bunch->pred->target->block);
    1063         453 :                                                                                 assert(succ()->bunch() == result->succ()->bunch());
    1064        1750 :                                                                                 assert(result == action_block.cbegin() || result[-1].succ.is_null() ||
    1065             :                                                                                             action_block_orig_inert_begin <= result ||
    1066             :                                                                                             result[-1].succ()->block_bunch->pred->target->block !=
    1067        1359 :                                                                                                              result->succ()->block_bunch->pred->target->block);
    1068             :                                                                                 // assert(this has the same action as result);
    1069         453 :         return result;
    1070             :     }
    1071             : 
    1072             : /*
    1073             :     /// \brief find the end of the action_block-slice
    1074             :     action_block_iter_t action_block_slice_before_end() const
    1075             :     {
    1076             :         action_block_iter_t result(begin_or_before_end());
    1077             :         if (&*result < this)
    1078             :         {
    1079             :             result = result->begin_or_before_end();                             assert(this <= &*result);
    1080             :         }                                                                       // assert(this has the same action as result);
    1081             :                                                                                 assert(succ()->block_bunch->pred->target->block ==
    1082             :                                                                                                              result->succ()->block_bunch->pred->target->block);
    1083             :                                                                                 assert(succ()->bunch() == result->succ()->bunch());
    1084             :                                                                                 assert(result + 1 == part_tr.action_block_inert_begin ||
    1085             :                                                                                                 result[1].succ.is_null() ||
    1086             :                                                                                                 result[1].succ()->block_bunch->pred->target->block !=
    1087             :                                                                                                              result->succ()->block_bunch->pred->target->block);
    1088             :         return result;
    1089             :     }
    1090             : */
    1091             : };
    1092             : 
    1093             : 
    1094             : class part_trans_t;
    1095             : 
    1096             : /// \brief bunch of transitions
    1097             : /// \details Like a slice, at the end of the algorithm there will be a bunch
    1098             : /// for every transition in the bisimulation quotient.  Therefore, we should
    1099             : /// try to minimize the size of a bunch as much as possible.
    1100             : class bunch_t
    1101             : {
    1102             :   public:
    1103             :     action_block_iter_t begin;
    1104             :     action_block_iter_t end;
    1105             : 
    1106             :     union sort_key_and_label_t
    1107             :     {
    1108             :         // During refinement, this field stores the sort key.
    1109             :         // After refinement, it is set to the label.
    1110             :         // To distinguish the two, we will use large numbers for sort keys and
    1111             :         // small ones for labels; then the probability that an error message is
    1112             :         // generated if someone mixes up the two is high.
    1113             :         trans_type sort_key;
    1114             :         label_type label;
    1115             : 
    1116         321 :         sort_key_and_label_t(trans_type new_sort_key)
    1117             :         {
    1118         321 :             sort_key = new_sort_key;
    1119         321 :         }
    1120             :     } sort_key_and_label;
    1121             :   public:
    1122             :     bunch_t* next_nontrivial;
    1123             : 
    1124         321 :     bunch_t(const action_block_iter_t& new_begin,
    1125             :                    const action_block_iter_t& new_end, trans_type new_sort_key)
    1126             :       : begin(new_begin),
    1127             :         end(new_end),
    1128             :         sort_key_and_label(new_sort_key),
    1129         321 :         next_nontrivial(nullptr)
    1130         321 :     {  }
    1131             : 
    1132             :     /// \brief returns true iff the bunch is trivial
    1133             :     /// \details If this bunch is the last in the list of non-trivial
    1134             :     /// bunches, the convention is that the next pointer points to this
    1135             :     /// bunch itself (to distinguish it from nullptr).
    1136        3153 :     bool is_trivial() const
    1137             :     {
    1138        3153 :         return nullptr == next_nontrivial;
    1139             :     }
    1140             : 
    1141             :     /// \brief split off a single action_block-slice from the bunch
    1142             :     /// \details The function splits the current bunch after
    1143             :     /// its first action_block-slice or before its last
    1144             :     /// action_block-slice, whichever is smaller.  It creates
    1145             :     /// a new bunch for the split-off slice and returns a pointer to the
    1146             :     /// new bunch.  The caller has to adapt the block_bunch-slices.
    1147             :     bunch_t* split_off_small_action_block_slice(part_trans_t& part_tr);
    1148             : 
    1149         769 :     bool operator<(const bunch_t& el) const
    1150             :     {
    1151         769 :         return sort_key_and_label.sort_key < el.sort_key_and_label.sort_key;
    1152             :     }
    1153             :     bool operator>(const bunch_t& el) const  {  return el.operator<(*this);  }
    1154             :     bool operator<=(const bunch_t& el) const  {  return !operator>(el);  }
    1155             :     bool operator>=(const bunch_t& el) const  {  return !operator<(el);  }
    1156             :                                                                                 #ifndef NDEBUG
    1157             :                                                                                     template <class LTS_TYPE>
    1158           0 :                                                                                     std::string debug_id_short(const bisim_partitioner_dnj<LTS_TYPE>&
    1159             :                                                                                                                                              partitioner) const
    1160           0 :                                                                                     {   assert(partitioner.part_tr.action_block.cbegin() <= begin);
    1161           0 :                                                                                         assert(begin < end);
    1162           0 :                                                                                         assert(end <= partitioner.part_tr.action_block_inert_begin);
    1163           0 :                                                                                         return "bunch [" + std::to_string(begin -
    1164             :                                                                                                              partitioner.part_tr.action_block.cbegin()) + "," +
    1165           0 :                                                                                            std::to_string(end-partitioner.part_tr.action_block.cbegin()) + ")";
    1166             :                                                                                     }
    1167             : 
    1168             :                                                                                     /// \brief print a bunch identification for debugging
    1169             :                                                                                     template <class LTS_TYPE>
    1170           0 :                                                                                     std::string debug_id(const bisim_partitioner_dnj<LTS_TYPE>& partitioner)
    1171             :                                                                                                                                                           const
    1172           0 :                                                                                     {   assert(!end[-1].succ.is_null());
    1173           0 :                                                                                         action_block_const_iter_t iter(begin);
    1174           0 :                                                                                         assert(iter == iter->succ()->block_bunch->pred->action_block);
    1175           0 :                                                                                         std::string result(debug_id_short(partitioner));
    1176           0 :                                                                                         result += " containing transition";
    1177           0 :                                                                                         result += iter < end - 1 ? "s " : " ";
    1178           0 :                                                                                         result += iter->succ()->block_bunch->pred->debug_id_short(
    1179             :                                                                                                                                partitioner.part_st.state_info);
    1180           0 :                                                                                         ++iter;
    1181           0 :                                                                                         if (end <= iter)  return result;
    1182           0 :                                                                                         while (iter->succ.is_null())  ++iter;
    1183           0 :                                                                                         assert(iter < end);
    1184           0 :                                                                                         assert(iter == iter->succ()->block_bunch->pred->action_block);
    1185           0 :                                                                                         result += ", ";
    1186           0 :                                                                                         result += iter->succ()->block_bunch->pred->debug_id_short(
    1187             :                                                                                                                                partitioner.part_st.state_info);
    1188           0 :                                                                                         if (iter < end - 3)
    1189             :                                                                                         {
    1190           0 :                                                                                             result += ", ...";
    1191           0 :                                                                                             iter = end - 3;
    1192             :                                                                                         }
    1193           0 :                                                                                         while (++iter < end)
    1194             :                                                                                         {
    1195           0 :                                                                                             if (!iter->succ.is_null())
    1196           0 :                                                                                             {   assert(iter == iter->succ()->block_bunch->pred->action_block);
    1197           0 :                                                                                                 result += ", ";
    1198           0 :                                                                                                 result += iter->succ()->block_bunch->pred->debug_id_short(
    1199             :                                                                                                                                partitioner.part_st.state_info);
    1200             :                                                                                             }
    1201             :                                                                                         }
    1202           0 :                                                                                         return result;
    1203             :                                                                                     }
    1204             : 
    1205             :                                                                                     /// \brief calculates the maximal allowed value for work counters
    1206             :                                                                                     /// associated with this bunch
    1207             :                                                                                     /// \details Work counters may only be nonzero if this bunch is a
    1208             :                                                                                     /// single-action bunch, i. e. all its transitions have the same action
    1209             :                                                                                     /// label.  Also, only then the size can be calculated as end - begin.
    1210             :                                                                                     template <class LTS_TYPE> int max_work_counter(
    1211             :                                                                                                      const bisim_partitioner_dnj<LTS_TYPE>& partitioner) const;
    1212             : 
    1213             :                                                                                     mutable bisim_gjkw::check_complexity::bunch_dnj_counter_t work_counter;
    1214             :                                                                                 #endif
    1215             : };
    1216             : 
    1217             : 
    1218             : /// \brief Information about a set of transitions with the same source block,
    1219             : /// in the same bunch
    1220             : /// \details This describes the coarser partition of transitions.  In the end
    1221             : /// we will have one slice for each transition, so we should try to minimize
    1222             : /// this data structure as much as possible.
    1223             : ///
    1224             : /// Also note that these slices are part of a doubly-linked list.  We cannot
    1225             : /// change this to a singly-linked list because then we would have to
    1226             : /// meticulously keep the list ordered, which is not possible when a block
    1227             : /// loses all its bottom states.
    1228             : class block_bunch_slice_t
    1229             : {
    1230             :   public:
    1231             :     /// pointer past the end of the transitions in the block_bunch array
    1232             :     block_bunch_iter_t end;
    1233             : 
    1234             :     /// bunch to which this slice belongs
    1235             :     class bunch_stability_t
    1236             :     {
    1237             :       private:
    1238             :         intptr_t data;
    1239             :       public:
    1240         412 :         bunch_stability_t(bunch_t* new_bunch, bool is_stable)
    1241         412 :           : data(reinterpret_cast<intptr_t>(new_bunch) | (intptr_t) is_stable)
    1242             :         {                                                                       static_assert(sizeof(bunch_t*)==sizeof(intptr_t), "size of intptr_t is wrong");
    1243         412 :                                                                                 assert(0 == (reinterpret_cast<intptr_t>(new_bunch) & 3));
    1244         412 :         }
    1245             : 
    1246          70 :         void operator=(bunch_t* new_bunch)
    1247          70 :         {                                                                       assert(0 == (reinterpret_cast<intptr_t>(new_bunch) & 3));
    1248          70 :             data = reinterpret_cast<intptr_t>(new_bunch) | (data & 3);
    1249          70 :         }
    1250       30279 :         bunch_t* operator()() const
    1251             :         {
    1252       30279 :             return reinterpret_cast<bunch_t*>(data & ~(intptr_t) 3);
    1253             :         }
    1254       12649 :         bool is_stable__() const           {  return data & 1;         }
    1255         407 :         void make_stable__()               {  data |= 1;               }
    1256         168 :         void make_unstable__()             {  data &= ~(intptr_t) 1;   }
    1257             :         //bool is_marked__() const           {  return 0 != (data & 2);  }
    1258             :         //void mark__()                      {  data |= 2;               }
    1259             :         //void unmark__()                    {  data &= ~(intptr_t) 2;   }
    1260             :         //void make_unstable_and_unmark__()  {  data &= ~(intptr_t) 3;   }
    1261             :     } bunch;
    1262             : 
    1263       12649 :     bool is_stable() const           {  return bunch.is_stable__();  }
    1264         407 :     void make_stable()               {  bunch.make_stable__();       }
    1265         168 :     void make_unstable()             {  bunch.make_unstable__();     }
    1266             :     //bool is_marked() const           {  return bunch.is_marked__();  }
    1267             :     //void mark()                      {  bunch.mark__();              }
    1268             :     //void unmark()                    {  bunch.unmark__();            }
    1269             :     //void make_unstable_and_unmark()  {  bunch.make_unstable_and_unmark__();  }
    1270             : 
    1271             : 
    1272         412 :     block_bunch_slice_t(const block_bunch_iter_t& new_end,
    1273             :                                         bunch_t* new_bunch, bool new_is_stable)
    1274             :       : end(new_end),
    1275         412 :         bunch(new_bunch, new_is_stable)
    1276         412 :     {  }
    1277             : 
    1278             : 
    1279       13357 :     bool empty() const
    1280             :     {                                                                           // assert(part_tr.block_bunch.cbegin() + 1 <= end);
    1281             :                                                                                 // assert(end <= part_tr.block_bunch_inert_begin);
    1282             :                                                                                 // assert(part_tr.block_bunch.cbegin()->slice != this);
    1283       13357 :         return end[-1].slice != this;
    1284             :     }
    1285             : 
    1286             : 
    1287             :     /// compute the source block of the transitions in this slice
    1288       12339 :     block_t* source_block() const
    1289       12339 :     {                                                                           assert(!empty());
    1290       12339 :         return end[-1].pred->source->block;
    1291             :     }
    1292             :                                                                                 #ifndef NDEBUG
    1293             :                                                                                     template <class LTS_TYPE>
    1294             :                                                                                     std::string debug_id(const bisim_partitioner_dnj<LTS_TYPE>& partitioner)
    1295             :                                                                                                                                                          const;
    1296             : 
    1297             : 
    1298             :                                                                                     // \brief add work to transitions starting in bottom states
    1299             :                                                                                     template <class LTS_TYPE>
    1300          62 :                                                                                     bool add_work_to_bottom_transns(
    1301             :                                                                                        enum bisim_gjkw::check_complexity::counter_type ctr, unsigned max_value,
    1302             :                                                                                                       const bisim_partitioner_dnj<LTS_TYPE>& partitioner) const
    1303          62 :                                                                                     {   assert(!empty());
    1304          62 :                                                                                         assert(1U == max_value);
    1305          62 :                                                                                         const block_t* block(source_block());
    1306          62 :                                                                                         bool result(false);
    1307          62 :                                                                                         block_bunch_const_iter_t block_bunch(end);
    1308          62 :                                                                                         assert(partitioner.part_tr.block_bunch.cbegin() + 1 < block_bunch);
    1309         546 :                                                                                         do
    1310             :                                                                                         {
    1311         110 :                                                                                             --block_bunch;
    1312         110 :                                                                                             state_info_const_iter_t const source(block_bunch->pred->source);
    1313         110 :                                                                                             assert(source->block == block);
    1314         110 :                                                                                             if (source->pos < block->nonbottom_begin)
    1315             :                                                                                             {
    1316             :                                                                                                 // the transition starts in a (new) bottom state
    1317          87 :                                                                                                 mCRL2complexity(block_bunch->pred, add_work(ctr, max_value),
    1318             :                                                                                                                                                   partitioner);
    1319          87 :                                                                                                 result = true;
    1320             :                                                                                             }
    1321             :                                                                                         }
    1322         440 :                                                                                         while (partitioner.part_tr.block_bunch.cbegin() + 1 < block_bunch &&
    1323         106 :                                                                                                                                 block_bunch[-1].slice == this);
    1324          62 :                                                                                         return result;
    1325             :                                                                                     }
    1326             : 
    1327             :                                                                                     mutable bisim_gjkw::check_complexity::block_bunch_dnj_counter_t
    1328             :                                                                                                                                                   work_counter;
    1329             :                                                                                 #endif
    1330             : };
    1331             : 
    1332             : 
    1333             : /// \brief find the beginning of the out-slice
    1334         378 : inline succ_iter_t succ_entry::out_slice_begin(                                 ONLY_IF_DEBUG( const bisim_gjkw::fixed_vector<succ_entry>& succ )
    1335             :                                                ) const
    1336             : {
    1337         378 :     succ_iter_t result(begin_or_before_end());
    1338         378 :     if (this < &*result)
    1339          66 :     {                                                                           assert(this == &*result->begin_or_before_end());
    1340          66 :         result += this - &*result; // result = succ_iter_t(this);
    1341         378 :     }                                                                           assert(block_bunch->pred->source == result->block_bunch->pred->source);
    1342             :                                                                                 // assert(this <= result); //< holds always, based on the if() above
    1343         378 :                                                                                 assert(this <= &*result->begin_or_before_end());
    1344         378 :                                                                                 assert(block_bunch->slice() == result->block_bunch->slice());
    1345        1474 :                                                                                 assert(succ.cbegin() + 1 == result ||
    1346             :                                                                                         result[-1].block_bunch->pred->source < block_bunch->pred->source ||
    1347        1134 :                                                                                                          *result[-1].bunch() < *block_bunch->slice()->bunch());
    1348         378 :     return result;
    1349             : }
    1350             : 
    1351             : 
    1352       16967 : inline bunch_t* succ_entry::bunch() const
    1353             : {
    1354       16967 :     return block_bunch->slice()->bunch();
    1355             : }
    1356             : 
    1357             : 
    1358             : class part_trans_t
    1359             : {
    1360             :   public:
    1361             :     /// \brief array containing all successor entries
    1362             :     /// \details The first and last entry are dummy entries, pointing to a
    1363             :     /// transition from nullptr to nullptr, to make it easier to check whether
    1364             :     /// there is another transition from the current state.
    1365             :     bisim_gjkw::fixed_vector<succ_entry> succ;
    1366             : 
    1367             :     /// \brief array containing all block_bunch entries
    1368             :     /// \details The first entry is a dummy entry, pointing to a transition not
    1369             :     /// contained in any slice, to make it easier to check whether there is
    1370             :     /// another transition in the current block_bunch.
    1371             :     bisim_gjkw::fixed_vector<block_bunch_entry> block_bunch;
    1372             : 
    1373             :     /// \brief array containing all predecessor entries
    1374             :     /// \details The first and last entry are dummy entries, pointing to a
    1375             :     /// transition to nullptr, to make it easier to check whether there is
    1376             :     /// another transition to the current state.
    1377             :     bisim_gjkw::fixed_vector<pred_entry> pred;
    1378             : 
    1379             :     /// \brief array containing all action_block entries
    1380             :     /// \details During initialisation, the transitions are sorted according to
    1381             :     /// their label. Between transitions with different labels there is a dummy
    1382             :     /// entry, to make it easier to check whether there is another transition
    1383             :     /// in the current action_block slice.
    1384             :     bisim_gjkw::fixed_vector<action_block_entry> action_block;
    1385             : 
    1386             :     /// \brief pointer to the first inert transition in block_bunch
    1387             :     block_bunch_iter_t block_bunch_inert_begin;
    1388             : 
    1389             :     /// \brief pointer to the first inert transition in action_block
    1390             :     action_block_iter_t action_block_inert_begin;
    1391             :                                                                                 #ifndef NDEBUG
    1392             :                                                                                     /// \brief pointer to the first inert transition in the initial partition
    1393             :                                                                                     action_block_const_iter_t action_block_orig_inert_begin;
    1394             :                                                                                 #endif
    1395             :     // state_type number_of_new_bottom_states;
    1396             : 
    1397             :     /// \brief list of unstable block_bunch-slices
    1398             :     std::list<block_bunch_slice_t> unstable_block_bunch;
    1399             : 
    1400             :     /// \brief pointer to first unstable block_bunch-slice that is not
    1401             :     /// currently postprocessed
    1402             :     /// \details During postprocessing, only the unstable block_bunch-slices
    1403             :     /// that contain transitions from the block withe new non-inert transitions
    1404             :     /// need to be handled.  This pointer points to the first unstable
    1405             :     /// block_bunch-slice that does not need to be postprocessed.  It cannot
    1406             :     /// be a block_bunch_slice_const_iter_t because we sometimes splice to that
    1407             :     /// point.
    1408             :     ///
    1409             :     /// At other times, this pointer points to the end of the unstable
    1410             :     /// block_bunch-slices.
    1411             :     block_bunch_slice_iter_t unstable_block_bunch_postprocess_end;
    1412             : 
    1413             :     /// \brief pointer to first non-trivial bunch
    1414             :     bunch_t* first_nontrivial;
    1415             : 
    1416             :     /// \brief constructor
    1417             :     /// \details The constructor sets up the dummy transitions at the beginning
    1418             :     /// and end of the succ, block_bunch and pred arrays.  (Dummy transitions
    1419             :     /// in action_block depend on the number of transitions per action label,
    1420             :     /// so they cannot be set up without knowing details about how many
    1421             :     /// transitions have which label.)
    1422             :     /// \param num_transitions  number of transitions of the LTS
    1423             :     /// \param num_actions      number of action labels of the LTS
    1424             :     /// \param illegal_state    an iterator to a dummy state (which can be
    1425             :     ///                         dereferenced, see the implementation of
    1426             :     ///                         surely_has_no_transition_in()).  This parameter
    1427             :     ///                         is used to initialize dummy transitions.
    1428          52 :     part_trans_t(trans_type num_transitions,
    1429             :                  trans_type num_actions,
    1430             :                  state_info_iter_t illegal_state)
    1431             :       : succ(num_transitions + 2),
    1432             :         block_bunch(num_transitions + 1),
    1433             :         pred(num_transitions + 2),
    1434          52 :         action_block(num_transitions + num_actions - 1),
    1435          52 :         block_bunch_inert_begin(block_bunch.end()),
    1436          52 :         action_block_inert_begin(action_block.end()),
    1437             :         // number_of_new_bottom_states(0),
    1438             :         unstable_block_bunch(),
    1439          52 :         unstable_block_bunch_postprocess_end(unstable_block_bunch.end()),
    1440         260 :         first_nontrivial(nullptr)
    1441             :     {
    1442          52 :         succ.begin()->block_bunch = block_bunch.begin();
    1443          52 :         succ.end()[-1].block_bunch = block_bunch.begin();
    1444          52 :         block_bunch.begin()->pred = pred.begin();                               assert(block_bunch.begin()->slice.is_null());
    1445          52 :         pred.begin()->source = illegal_state;
    1446          52 :         pred.begin()->target = illegal_state;
    1447          52 :         pred.end()[-1].source = illegal_state;
    1448          52 :         pred.end()[-1].target = illegal_state;
    1449          52 :     }
    1450             : 
    1451             : 
    1452             :     /// \brief destructor
    1453             :     /// \details The destructor also deallocates the bunches, as they are not
    1454             :     /// directly referenced from anywhere.
    1455          52 :     ~part_trans_t()
    1456          52 :     {
    1457             :         // mCRL2log(log::verbose, "bisim_dnj") << "The algorithm found "
    1458             :         //           << number_of_new_bottom_states << " new bottom states.\n";
    1459          52 :         action_block_iter_t action_block_iter(action_block.begin());
    1460         321 :         for (;;)
    1461             :         {
    1462         430 :             do
    1463             :             {
    1464         482 :                 if (action_block_inert_begin <= action_block_iter)  return;
    1465             :             }
    1466         430 :             while (action_block_iter->succ.is_null() && (                       assert(action_block_iter->begin_or_before_end.is_null()),
    1467         321 :                                                    ++action_block_iter, true)); assert(!action_block_iter->begin_or_before_end.is_null());
    1468         321 :             bunch_t* const bunch(action_block_iter->succ()->bunch());           assert(bunch->begin == action_block_iter);
    1469         321 :             action_block_iter = bunch->end;
    1470         321 :             delete bunch;
    1471             :         }
    1472             :         /* unreachable                                                       */ assert(0);
    1473          52 :     }
    1474             : 
    1475             :     // \brief provide some bunch from the list of nontrivial bunches
    1476         278 :     bunch_t* get_some_nontrivial()
    1477             :     {
    1478         278 :         return first_nontrivial;
    1479             :     }
    1480             : 
    1481             :     // \brief insert a bunch into the list of nontrivial bunches
    1482          74 :     void make_nontrivial(bunch_t* bunch)
    1483          74 :     {                                                                           assert(1 < bunch->end - bunch->begin);  assert(bunch->is_trivial());
    1484             :                                                                                 // The following assertions do not necessarily hold during initialisation:
    1485             :                                                                                 //assert(bunch->begin <= bunch->begin->begin_or_before_end());
    1486          74 :         bunch->next_nontrivial = nullptr == first_nontrivial ? bunch
    1487          74 :                                                             : first_nontrivial; //assert(bunch->begin->begin_or_before_end() <
    1488             :                                                                                 //                                       bunch->end[-1].begin_or_before_end());
    1489          74 :         first_nontrivial = bunch;                                               //assert(end[-1].begin_or_before_end() <= end);
    1490          74 :     }
    1491             : 
    1492             :     /// \brief remove a bunch from the list of nontrivial bunches
    1493          74 :     void make_trivial(bunch_t* bunch)
    1494          74 :     {                                                                           assert(!bunch->is_trivial());  assert(first_nontrivial == bunch);
    1495          74 :         first_nontrivial = bunch == bunch->next_nontrivial ? nullptr
    1496          74 :                                                       : bunch->next_nontrivial; assert(bunch->end - 1 == bunch->begin->begin_or_before_end());
    1497          74 :         bunch->next_nontrivial = nullptr;                                       assert(bunch->begin == bunch->end[-1].begin_or_before_end());
    1498          74 :     }
    1499             : 
    1500             :     /// \brief transition is moved to a new bunch
    1501             :     /// \details This (and the next function) have to be called after a
    1502             :     /// transition has changed its bunch.  The member function will adapt the
    1503             :     /// transition data structure.  It assumes that the transition is
    1504             :     /// non-inert.
    1505             :     ///
    1506             :     /// The work has to be done in two steps: We call the first step
    1507             :     /// first_move_transition_to_new_bunch() for each transition in the new
    1508             :     /// bunch, and then call second_move_transition_to_new_bunch() again for
    1509             :     /// all these transitions.  The reason is that some data structures need to
    1510             :     /// be finalised in the second phase.
    1511             :     ///
    1512             :     /// The first phase moves all transitions to their correct position in
    1513             :     /// the out-slices and block_bunch-slices, but it doesn't yet create
    1514             :     /// a fully correct new out-slice and block_bunch-slice.  It adapts
    1515             :     /// current_out_slice of all states with a transition in the new bunch.
    1516             :     /// \param action_block_iter_iter     transition that has to be changed
    1517             :     /// \param first_transition_of_state  This is the first transition of the
    1518             :     ///                                   state, so a new bunch_slice has to be
    1519             :     ///                                   allocated.
    1520             :     #ifdef NDEBUG
    1521             :         static
    1522             :     #endif
    1523         378 :     void first_move_transition_to_new_bunch(const action_block_iter_t&
    1524             :                        action_block_iter, bool const first_transition_of_state)
    1525             :     {
    1526             : 
    1527             :         /* -  -  -  -  -  -  -  - adapt part_tr.succ -  -  -  -  -  -  -  - */
    1528             : 
    1529             :         // Line 1.17: Register that s --> t is now part of new_bunch
    1530         378 :         succ_iter_t const old_succ_pos(action_block_iter->succ());              assert(old_succ_pos->block_bunch->pred->action_block == action_block_iter);
    1531             :         succ_iter_t out_slice_begin(old_succ_pos->out_slice_begin(              ONLY_IF_DEBUG( succ )
    1532         378 :                                                                   ));           assert(out_slice_begin->block_bunch->pred->action_block->succ() ==
    1533         378 :                                                                                                                                               out_slice_begin);
    1534         378 :         succ_iter_t const new_succ_pos(out_slice_begin->begin_or_before_end()); assert(out_slice_begin == new_succ_pos->begin_or_before_end());
    1535         378 :                                                                                 assert(new_succ_pos<old_succ_pos->block_bunch->pred->source->succ_inert.begin);
    1536         378 :         /* move the transition to the end of its out-slice                   */ assert(new_succ_pos->block_bunch->pred->action_block->succ() == new_succ_pos);
    1537         378 :         if (old_succ_pos < new_succ_pos)
    1538             :         {
    1539          68 :             std::swap(old_succ_pos->block_bunch, new_succ_pos->block_bunch);
    1540          68 :             old_succ_pos->block_bunch->pred->action_block->succ.change(
    1541          68 :                                                                  old_succ_pos); assert(action_block_iter == new_succ_pos->block_bunch->pred->action_block);
    1542          68 :             action_block_iter->succ.change(new_succ_pos);
    1543         310 :         }                                                                       else  assert(old_succ_pos == new_succ_pos);
    1544             : 
    1545             :         // adapt the old out-slice immediately
    1546             :             // If the old out-slice becomes empty, then out_slice_begin ==
    1547             :             // new_succ_pos, so the two following assignments will assign the
    1548             :             // same variable.  The second assignment is the relevant one.
    1549         378 :         out_slice_begin->begin_or_before_end.change(new_succ_pos - 1);
    1550             : 
    1551             :         // adapt the new out-slice, as far as is possible now:
    1552             :             // make the begin_or_before_end pointers of the first and last
    1553             :             // transition in the slice correct immediately.  The other
    1554             :             // begin_or_before_end pointers need to be corrected after all
    1555             :             // transitions in the new bunch have been positioned correctly.
    1556         378 :         if (first_transition_of_state)
    1557             :         {
    1558             :             // Line 1.15: Set the current out-slice pointer of s to a
    1559             :             //            transition in splitter_bunch (preferably not
    1560             :             //            s --> t itself)
    1561         369 :             new_succ_pos->block_bunch->pred->source->current_out_slice.begin =
    1562         369 :                                                                out_slice_begin;
    1563         369 :             new_succ_pos->begin_or_before_end.change(new_succ_pos);
    1564             :         }
    1565             :         else
    1566             :         {
    1567             :             succ_iter_t out_slice_before_end(
    1568           9 :                                         new_succ_pos[1].begin_or_before_end()); assert(new_succ_pos < out_slice_before_end);
    1569           9 :                                                                                 assert(out_slice_before_end->block_bunch->pred->action_block->succ() ==
    1570           9 :                                                                                                                                          out_slice_before_end);
    1571           9 :                                                                                 assert(out_slice_before_end <
    1572           9 :                                                                                                     new_succ_pos->block_bunch->pred->source->succ_inert.begin);
    1573           9 :                                                                                 assert(new_succ_pos + 1 == out_slice_before_end->begin_or_before_end());
    1574           9 :             out_slice_before_end->begin_or_before_end.change(new_succ_pos);     assert(out_slice_begin ==
    1575           9 :                                                                                              new_succ_pos->block_bunch->pred->source->current_out_slice.begin);
    1576           9 :             new_succ_pos->begin_or_before_end.change(out_slice_before_end);     assert(out_slice_before_end->bunch() == new_succ_pos->bunch());
    1577             :         }
    1578             : 
    1579         378 :         /* -  -  -  -  -  -  - adapt part_tr.block_bunch -  -  -  -  -  -  - */ assert(new_succ_pos == action_block_iter->succ());
    1580         378 :                                                                                 assert(unstable_block_bunch.empty());
    1581             :         block_bunch_iter_t const old_block_bunch_pos(
    1582         378 :                                                     new_succ_pos->block_bunch); assert(old_block_bunch_pos->pred->action_block == action_block_iter);
    1583             :         block_bunch_slice_iter_t const old_block_bunch_slice(
    1584         378 :                                                  old_block_bunch_pos->slice());
    1585             :         block_bunch_iter_t const new_block_bunch_pos(
    1586         378 :                                                old_block_bunch_slice->end - 1); assert(new_block_bunch_pos->pred->action_block->succ()->block_bunch ==
    1587         378 :                                                                                                                                           new_block_bunch_pos);
    1588             :         // move the transition to the end of its block_bunch-slice
    1589         378 :         if (old_block_bunch_pos < new_block_bunch_pos)
    1590             :         {
    1591         263 :             std::swap(old_block_bunch_pos->pred, new_block_bunch_pos->pred);
    1592         263 :             old_block_bunch_pos->pred->action_block->succ()->block_bunch =
    1593         263 :                                                            old_block_bunch_pos; assert(new_succ_pos == new_block_bunch_pos->pred->action_block->succ());
    1594         263 :             new_succ_pos->block_bunch = new_block_bunch_pos;
    1595         115 :         }                                                                       else  assert(new_block_bunch_pos == old_block_bunch_pos);
    1596             : 
    1597             :         // adapt the old block_bunch-slice
    1598         378 :         old_block_bunch_slice->end = new_block_bunch_pos;
    1599             : 
    1600             :         // (create and) adapt the new block_bunch-slice
    1601             :             // All this work is done in the second phase.
    1602         378 :     }
    1603             : 
    1604             : 
    1605             :     /// \brief correct transition data structure after splitting a bunch
    1606             :     /// \brief transition is moved to a new bunch, phase 2
    1607             :     /// \details This (and the previous function) have to be called after a
    1608             :     /// transition has changed its bunch.  The member function will adapt the
    1609             :     /// transition data structure.  It assumes that the transition is
    1610             :     /// non-inert.
    1611             :     ///
    1612             :     /// The work has to be done in two steps: We call the first step
    1613             :     /// first_move_transition_to_new_bunch() for each transition in the new
    1614             :     /// bunch, and then call second_move_transition_to_new_bunch() again for
    1615             :     /// all these transitions.  The reason is that some data structures need to
    1616             :     /// be finalised/ in the second phase.
    1617             :     ///
    1618             :     /// The second phase finalizes the new out-slices and block_bunch-slices
    1619             :     /// that were left half-finished by the first phase.  It assumes that all
    1620             :     /// block_bunch-slices are registered as stable.
    1621             :                                                                                 ONLY_IF_DEBUG( template <class LTS_TYPE> )
    1622         378 :     void second_move_transition_to_new_bunch(                                   ONLY_IF_DEBUG( const bisim_partitioner_dnj<LTS_TYPE>& partitioner, )
    1623             :         const action_block_iter_t& action_block_iter, bunch_t* const new_bunch)
    1624         378 :     {                                                                           assert(nullptr != new_bunch);
    1625             : 
    1626             :         /* -  -  -  -  -  -  -  - adapt part_tr.succ -  -  -  -  -  -  -  - */
    1627             : 
    1628             :         // Line 1.17: Register that s --> t is now part of new_bunch
    1629             :             // We already moved the transition in part_tr.succ to the correct
    1630             :             // place in first_move_transition_to_new_bunch(); now we have to
    1631             :             // set begin_or_before_end.
    1632         378 :         succ_iter_t const new_succ_pos(action_block_iter->succ());              assert(new_succ_pos->block_bunch->pred->action_block == action_block_iter);
    1633             :         state_info_iter_t const source(
    1634         378 :                                       new_succ_pos->block_bunch->pred->source); assert(source->pos->st == source);
    1635             :         {
    1636             :             succ_iter_t const new_begin_or_before_end(
    1637         378 :                    new_succ_pos->begin_or_before_end()->begin_or_before_end()); assert(new_begin_or_before_end->block_bunch->pred->action_block->succ() ==
    1638             :                                                                                                                                       new_begin_or_before_end);
    1639         378 :             if (new_begin_or_before_end < new_succ_pos)
    1640             :             {
    1641           0 :                 new_succ_pos->begin_or_before_end.change(
    1642             :                                                       new_begin_or_before_end);
    1643             :             }
    1644             :                                                                                 #ifndef NDEBUG
    1645             :                                                                                     else
    1646         378 :                                                                                     {   assert(new_begin_or_before_end == new_succ_pos);
    1647             :                                                                                         succ_const_iter_t new_before_end(
    1648         378 :                                                                                                                new_begin_or_before_end->begin_or_before_end());
    1649         378 :                                                                                         if (new_begin_or_before_end <= new_before_end)
    1650         369 :                                                                                         {   assert(source->current_out_slice.begin <= new_begin_or_before_end);
    1651             :                                                                                             // This is the first transition in the new out-slice.  Test
    1652             :                                                                                             // whether it is sorted according to bunch order.
    1653         369 :                                                                                             assert(partitioner.part_tr.succ.cbegin()+1==new_begin_or_before_end
    1654             :                                                                                              || new_begin_or_before_end[-1].block_bunch->pred->source<source ||
    1655             :                                                                                                             *new_begin_or_before_end[-1].bunch() < *new_bunch);
    1656         369 :                                                                                             assert(new_before_end + 1 == source->succ_inert.begin ||
    1657             :                                                                                                                       *new_bunch < *new_before_end[1].bunch());
    1658             :                                                                                         }
    1659             :                                                                                     }
    1660             :                                                                                 #endif
    1661             :         }
    1662             : 
    1663             :         /* -  -  -  -  -  -  - adapt part_tr.block_bunch -  -  -  -  -  -  - */
    1664             : 
    1665             :         block_bunch_iter_t const new_block_bunch_pos(
    1666         378 :                                                     new_succ_pos->block_bunch); assert(new_block_bunch_pos->pred->action_block->succ() == new_succ_pos);
    1667             :         block_bunch_slice_iter_t const old_block_bunch_slice(
    1668         378 :                                                  new_block_bunch_pos->slice());
    1669             :                                                                                 #ifndef NDEBUG
    1670         378 :                                                                                     if (new_bunch == old_block_bunch_slice->bunch())
    1671             :                                                                                     {   // the block_bunch-slice has been updated in an earlier call.
    1672         131 :                                                                                         assert(new_block_bunch_pos + 1 < old_block_bunch_slice->end);
    1673         131 :                                                                                         assert(old_block_bunch_slice == new_block_bunch_pos[1].slice());
    1674             :                                                                                     }
    1675             :                                                                                     else
    1676         247 :                                                                                     {   assert(*old_block_bunch_slice->bunch() < *new_bunch);
    1677         247 :                                                                                         assert(old_block_bunch_slice->end <= new_block_bunch_pos);
    1678             :                                                                                     }
    1679             :                                                                                 #endif
    1680         711 :         if (new_block_bunch_pos + 1 < block_bunch_inert_begin &&
    1681         333 :                    &*old_block_bunch_slice == &*new_block_bunch_pos[1].slice())
    1682             :         {
    1683             :             // This transition is not the last in the block_bunch-slice.
    1684         332 :             return;
    1685             :         }
    1686         247 :                                                                                 assert(old_block_bunch_slice->is_stable());
    1687             :         // This transition is the last in the block_bunch-slice.  We do all
    1688             :         // necessary work for this block_bunch-slice upon finding this
    1689             :         // transition.  Because every block_bunch-slice has exactly one such
    1690             :         // transition, all work is executed exactly once.
    1691         247 :         if (old_block_bunch_slice->empty())
    1692             :         {
    1693             :             // The old block_bunch-slice is empty, reuse it as the new one.
    1694          70 :             old_block_bunch_slice->end = new_block_bunch_pos + 1;
    1695          70 :             old_block_bunch_slice->bunch = new_bunch;
    1696             : 
    1697             :             // Because now every bottom state has a transition in the new
    1698             :             // bunch, and no state has a transition in the old bunch, there
    1699             :             // is no need to refine this block.  So we don't make this
    1700             :             // block_bunch-slice unstable.
    1701             : 
    1702             :             // unmark the states
    1703          70 :             source->block->marked_nonbottom_begin = source->block->end;
    1704          70 :             source->block->marked_bottom_begin=source->block->nonbottom_begin;
    1705             : 
    1706          70 :             return;
    1707             :         }
    1708             : 
    1709             :         // Create a new block_bunch-slice and set the pointers accordingly
    1710         177 :         block_bunch_slice_iter_t new_block_bunch_slice;
    1711         177 :         if (1 >= source->block->size())
    1712             :         {
    1713             :             // the new block_bunch-slice is stable
    1714             : 
    1715             :             // unmark the state
    1716          15 :             source->block->marked_bottom_begin=source->block->nonbottom_begin;  assert(source->block->marked_nonbottom_begin == source->block->end);
    1717             : 
    1718             :             // Insert at the appropriate position in the list of stable
    1719             :             // block_bunch-slices:  immediately after the old
    1720             :             // block_bunch-slice.
    1721          15 :             new_block_bunch_slice = source->block->stable_block_bunch.
    1722          30 :                     emplace(std::next(old_block_bunch_slice),
    1723             :                                      new_block_bunch_pos + 1, new_bunch, true);
    1724             :         }
    1725             :         else
    1726             :         {
    1727             :             // The old block_bunch-slice becomes unstable, and the new
    1728             :             // block_bunch-slice is created unstable.
    1729             : 
    1730             :             // Line 1.16: Add the block_bunch-slice of splitter_bunch
    1731             :             //            where s --> t was in to the list of unstable
    1732             :             //            block_bunch-slices
    1733         162 :             unstable_block_bunch.splice(unstable_block_bunch.begin(),
    1734             :                      source->block->stable_block_bunch, old_block_bunch_slice);
    1735         162 :             old_block_bunch_slice->make_unstable();
    1736             : 
    1737             :             // Line 1.18: Add the block_bunch-slice of new_bunch where
    1738             :             //            s --> t is now in to the list of unstable
    1739             :             //            block_bunch-slices
    1740         162 :             unstable_block_bunch.emplace_front(new_block_bunch_pos + 1,
    1741             :                                                              new_bunch, false);
    1742         162 :             new_block_bunch_slice = unstable_block_bunch.begin();
    1743             :         }
    1744             :                                                                                 #ifndef NDEBUG
    1745         177 :         /* set the pointers accordingly                                      */     new_block_bunch_slice->work_counter = old_block_bunch_slice->work_counter;
    1746             :                                                                                 #endif
    1747         177 :         block_bunch_iter_t block_bunch_iter(old_block_bunch_slice->end);        assert(block_bunch_iter <= new_block_bunch_pos);
    1748         294 :         do
    1749         294 :         {                                                                       assert(block_bunch_iter->slice() == old_block_bunch_slice);
    1750         294 :                                                                                 assert(block_bunch_iter->pred->action_block->succ()->block_bunch ==
    1751             :                                                                                                                                              block_bunch_iter);
    1752         294 :                 block_bunch_iter->slice.change(new_block_bunch_slice);          assert(block_bunch_iter->pred->source->block == source->block);
    1753             :                                                                                 // mCRL2complexity(block_bunch_iter->pred, ...) -- subsumed by the call below
    1754             :         }
    1755         471 :         while (++block_bunch_iter <= new_block_bunch_pos);                      mCRL2complexity(new_block_bunch_slice, add_work(
    1756             :                                                                                         bisim_gjkw::check_complexity::second_move_transition_to_new_bunch,
    1757             :                                                                                                        new_bunch->max_work_counter(partitioner)), partitioner);
    1758             :     }
    1759             : 
    1760             : 
    1761             :   private:
    1762             :     /// \brief Adapt the non-inert transitions in an out-slice to a new block
    1763             :     /// \details After a block has been split, the outgoing transitions of the
    1764             :     /// new block need to move to the respective block_bunch-slice of the new
    1765             :     /// block.
    1766             :     ///
    1767             :     /// This function handles all transitions in the out-slice just before
    1768             :     /// `out_slice_end`, as they all belong to the same block_bunch-slice and
    1769             :     /// can be moved together.
    1770             :     ///
    1771             :     /// The function returns the beginning of this out-slice (which can become
    1772             :     /// the next out_slice_end).  It is meant to be called from the last
    1773             :     /// out-slice back to the first because it inserts stable
    1774             :     /// block_bunch-slices at the beginning of the list for the new block, so
    1775             :     /// it would normally become ordered according to the bunch.
    1776             :                                                                                 ONLY_IF_DEBUG( template <class LTS_TYPE> )
    1777         404 :     succ_iter_t move_out_slice_to_new_block(                                    ONLY_IF_DEBUG( const bisim_partitioner_dnj<LTS_TYPE>& partitioner, )
    1778             :                            succ_iter_t out_slice_end,
    1779             :                            block_t* const old_block,
    1780             :                            const block_bunch_slice_const_iter_t& last_splitter)
    1781         404 :     {                                                                           assert(succ.cbegin() + 1 < out_slice_end);
    1782             :         succ_iter_t const out_slice_begin(
    1783         404 :                                       out_slice_end[-1].begin_or_before_end()); assert(out_slice_begin < out_slice_end);
    1784         404 :                                                                                 assert(out_slice_begin->block_bunch->pred->action_block->succ() ==
    1785             :                                                                                                                                               out_slice_begin);
    1786         404 :         block_bunch_iter_t old_block_bunch_pos(out_slice_end[-1].block_bunch);  assert(old_block_bunch_pos->pred->action_block->succ()->block_bunch ==
    1787             :                                                                                                                                           old_block_bunch_pos);
    1788             :         block_bunch_slice_iter_t old_block_bunch_slice(
    1789         404 :                                                  old_block_bunch_pos->slice());
    1790         404 :         if(&*last_splitter == &*old_block_bunch_slice)  return out_slice_begin;
    1791             : 
    1792             :         {
    1793             :             block_bunch_iter_t after_new_block_bunch_pos(
    1794         183 :                                                    old_block_bunch_slice->end);
    1795         183 :             block_bunch_slice_iter_t new_block_bunch_slice;                     ONLY_IF_DEBUG( unsigned max_counter; )
    1796             :             {
    1797             :                 state_info_iter_t const source(
    1798         183 :                                             old_block_bunch_pos->pred->source); assert(out_slice_end <= source->succ_inert.begin);
    1799         183 :                                                                                 assert(source->pos->st == source);
    1800         183 :                 block_t* new_block(source->block);                              assert(source == out_slice_begin->block_bunch->pred->source);
    1801         634 :                 if (after_new_block_bunch_pos >= block_bunch_inert_begin ||
    1802         175 :                  (new_block_bunch_slice=after_new_block_bunch_pos->slice(),
    1803         175 :                   new_block!=after_new_block_bunch_pos->pred->source->block ||
    1804         101 :                   old_block_bunch_slice->bunch() !=
    1805             :                                                new_block_bunch_slice->bunch()))
    1806             :                 {
    1807             :                     // the new block_bunch-slice is not suitable; create a new
    1808             :                     // one and insert it into the correct list.
    1809         140 :                     if (old_block_bunch_slice->is_stable())
    1810             :                     {
    1811             :                         // In most cases, but not always, the source is a
    1812             :                         // bottom state.
    1813          42 :                         new_block->stable_block_bunch.emplace_front(
    1814             :                                          old_block_bunch_slice->end,
    1815             :                                          old_block_bunch_slice->bunch(), true);
    1816          42 :                         new_block_bunch_slice =
    1817          42 :                                          new_block->stable_block_bunch.begin();
    1818             :                     }
    1819             :                     else
    1820             :                     {
    1821          98 :                         new_block_bunch_slice = unstable_block_bunch.emplace(
    1822             :                                         std::next(old_block_bunch_slice),
    1823             :                                         old_block_bunch_slice->end,
    1824             :                                         old_block_bunch_slice->bunch(), false);
    1825         140 :                     }                                                           ONLY_IF_DEBUG( new_block_bunch_slice->work_counter =
    1826             :                                                                                                                          old_block_bunch_slice->work_counter; )
    1827         183 :                 }                                                               ONLY_IF_DEBUG( max_counter = bisim_gjkw::check_complexity::log_n -
    1828             :                                                                                                       bisim_gjkw::check_complexity::ilog2(new_block->size()); )
    1829             :             }
    1830             :             // move all transitions in this out-slice to the new block_bunch
    1831         225 :             do
    1832             :             {
    1833         204 :                 --out_slice_end;
    1834         204 :                 --after_new_block_bunch_pos;                                    assert(old_block_bunch_pos->slice() == old_block_bunch_slice);
    1835         204 :                 after_new_block_bunch_pos->slice.change(new_block_bunch_slice);
    1836         204 :                 std::swap(old_block_bunch_pos->pred,
    1837             :                                               after_new_block_bunch_pos->pred);
    1838         204 :                 old_block_bunch_pos->pred->action_block->succ()->block_bunch =
    1839         204 :                                                            old_block_bunch_pos; assert(out_slice_end == after_new_block_bunch_pos->pred->action_block->succ());
    1840         204 :                 out_slice_end->block_bunch = after_new_block_bunch_pos;         mCRL2complexity(out_slice_end->block_bunch->pred, add_work(bisim_gjkw::
    1841             :                                                                                      check_complexity::move_out_slice_to_new_block, max_counter), partitioner);
    1842             :             }
    1843         204 :             while (out_slice_begin < out_slice_end &&
    1844          21 :                   (old_block_bunch_pos = out_slice_end[-1].block_bunch, true));
    1845         183 :             old_block_bunch_slice->end = after_new_block_bunch_pos;
    1846             :         }
    1847         183 :         if (old_block_bunch_slice->empty())
    1848             :         {
    1849          32 :             if (old_block_bunch_slice->is_stable())
    1850             :             {
    1851             :                 // If the new block is red, then the old (blue) block loses
    1852             :                 // exactly one stable block_bunch-slice, namely the one we just
    1853             :                 // stabilised for (last_splitter).  We could perhaps optimize
    1854             :                 // this by moving that slice as a whole to the new block --
    1855             :                 // perhaps later.
    1856             :                 //
    1857             :                 // If the new block is blue, then the old (red) block loses no
    1858             :                 // stable block_bunch-slices if it contains any bottom state.
    1859             :                 // If it doesn't contain any bottom state, it will definitely
    1860             :                 // keep last_splitter, but nothing else can be guaranteed.
    1861             :                 //
    1862             :                 // So old_block_bunch_slice may be deleted, in particular if
    1863             :                 // the new block is blue, but not exclusively.
    1864          11 :                 old_block->stable_block_bunch.erase(old_block_bunch_slice);
    1865             :             }
    1866             :             else
    1867             :             {
    1868          21 :                 unstable_block_bunch.erase(old_block_bunch_slice);
    1869             :             }
    1870             :         }
    1871         183 :         return out_slice_begin;
    1872             :     }
    1873             : 
    1874             : 
    1875             :     /// \brief handle one transition after a block has been split
    1876             :     /// \details The main task of this method is to move the transition to the
    1877             :     /// correct place in the action_block slice.
    1878             :     ///
    1879             :     /// This function handles phase 1.  Because the new action_block-slice
    1880             :     /// cannot be adapted completely until all transitions into the new block
    1881             :     /// have been handled through phase 1, the next function handles them again
    1882             :     /// in phase 2.
    1883         453 :     void first_move_transition_to_new_action_block(
    1884             :                                                   const pred_iter_t& pred_iter)
    1885             :     {
    1886             :         action_block_iter_t const old_action_block_pos(
    1887         453 :                                                       pred_iter->action_block); assert(old_action_block_pos->succ()->block_bunch->pred == pred_iter);
    1888             :         action_block_iter_t const action_block_slice_begin(
    1889             :                              old_action_block_pos->action_block_slice_begin(    ONLY_IF_DEBUG( action_block, action_block_orig_inert_begin )
    1890         453 :                                                                             )); assert(action_block_slice_begin->succ()->block_bunch->pred->action_block ==
    1891         453 :                                                                                                                                      action_block_slice_begin);
    1892             :         action_block_iter_t const new_action_block_pos(
    1893         453 :                               action_block_slice_begin->begin_or_before_end()); assert(action_block_slice_begin==new_action_block_pos->begin_or_before_end());
    1894         453 :                                                                                 assert(new_action_block_pos->succ()->block_bunch->pred->action_block ==
    1895         453 :         /* move the transition to the end of the action_block-slice          */                                                          new_action_block_pos);
    1896         453 :         if (old_action_block_pos < new_action_block_pos)
    1897             :         {
    1898         252 :             succ_iter_t temp(new_action_block_pos->succ());
    1899         252 :             new_action_block_pos->succ.change(old_action_block_pos->succ());
    1900         252 :             old_action_block_pos->succ.change(temp);
    1901         252 :             temp->block_bunch->pred->action_block = old_action_block_pos;       assert(pred_iter == new_action_block_pos->succ()->block_bunch->pred);
    1902         252 :             pred_iter->action_block = new_action_block_pos;
    1903             : 
    1904             :         // adapt the old action_block-slice immediately
    1905         252 :             action_block_slice_begin->begin_or_before_end.change(
    1906         504 :                                                      new_action_block_pos - 1);
    1907             :         }
    1908             :         else
    1909         201 :         {                                                                       assert(old_action_block_pos == new_action_block_pos);
    1910         201 :             if (action_block_slice_begin < new_action_block_pos)
    1911             :             {
    1912             :                 // The old action_block-slice is not empty, so we have to adapt
    1913             :                 // the pointer at the beginning.  (If it is empty, it may
    1914             :                 // happen that `new_action_block_pos - 1` is an illegal value.)
    1915          90 :                 action_block_slice_begin->begin_or_before_end.change(
    1916         180 :                                                      new_action_block_pos - 1);
    1917             :             }
    1918             :         }
    1919         453 :                                                                                 assert(pred_iter == new_action_block_pos->succ()->block_bunch->pred);
    1920             :         // adapt the new action_block-slice, as far as is possible now
    1921             :             // make the begin_or_before_end pointers of the first and last
    1922             :             // transition in the slice correct immediately.  The other
    1923             :             // begin_or_before_end pointers need to be corrected after all
    1924             :             // transitions in the new bunch have been positioned correctly.
    1925        1790 :         if (new_action_block_pos + 1 >= action_block_inert_begin ||
    1926         754 :             new_action_block_pos[1].succ.is_null() ||
    1927         323 :             new_action_block_pos[1].succ()->bunch() !=
    1928        1964 :                                        new_action_block_pos->succ()->bunch() ||
    1929         282 :             new_action_block_pos[1].succ()->block_bunch->pred->target->block !=
    1930         282 :                                                       pred_iter->target->block)
    1931             :         {
    1932             :             // This is the first transition that moves to this new
    1933             :             // action_block-slice.
    1934         248 :             new_action_block_pos->begin_or_before_end.change(
    1935         248 :                                                          new_action_block_pos);
    1936             :         }
    1937             :         else
    1938             :         {
    1939             :             action_block_iter_t const action_block_slice_before_end(
    1940         205 :                                 new_action_block_pos[1].begin_or_before_end()); assert(new_action_block_pos < action_block_slice_before_end);
    1941         205 :                                                                                 assert(action_block_slice_before_end->succ()->block_bunch->pred->action_block==
    1942         205 :                                                                                                                                 action_block_slice_before_end);
    1943         205 :                                                                                 assert(new_action_block_pos + 1 ==
    1944         205 :                                                                                                          action_block_slice_before_end->begin_or_before_end());
    1945         205 :             action_block_slice_before_end->begin_or_before_end.change(
    1946         205 :                                                          new_action_block_pos); assert(action_block_slice_before_end->succ()->block_bunch->
    1947         205 :                                                                                                               pred->target->block == pred_iter->target->block);
    1948         205 :             new_action_block_pos->begin_or_before_end.change(
    1949         205 :                                                 action_block_slice_before_end); assert(action_block_slice_before_end < action_block_inert_begin);
    1950             :         }
    1951         453 :     }
    1952             : 
    1953             : 
    1954             :     /// \brief handle one transition after a block has been split, phase 2
    1955             :     /// \details Because the new action_block-slice cannot be adapted
    1956             :     /// completely until all transitions into the new block have been handled
    1957             :     /// through phase 1 see the previous function), this function handles them
    1958             :     /// again in phase 2.
    1959         453 :     void second_move_transition_to_new_action_block(
    1960             :                                                   const pred_iter_t& pred_iter)
    1961             :     {
    1962             :         action_block_iter_t const new_action_block_pos(
    1963         453 :                                                       pred_iter->action_block); assert(new_action_block_pos->succ()->block_bunch->pred == pred_iter);
    1964             :         action_block_iter_t const old_begin_or_before_end(
    1965         453 :                                   new_action_block_pos->begin_or_before_end()); assert(old_begin_or_before_end->succ()->block_bunch->pred->action_block ==
    1966         453 :                                                                                                                                       old_begin_or_before_end);
    1967             :         {
    1968             :             action_block_iter_t const new_begin_or_before_end(
    1969         453 :                                old_begin_or_before_end->begin_or_before_end()); assert(new_begin_or_before_end->succ()->block_bunch->pred->action_block ==
    1970         453 :                                                                                                                                       new_begin_or_before_end);
    1971         453 :             if (new_begin_or_before_end < new_action_block_pos)
    1972          94 :             {                                                                   assert(old_begin_or_before_end ==
    1973          94 :                                                                                                                new_begin_or_before_end->begin_or_before_end());
    1974          94 :                 new_action_block_pos->begin_or_before_end.change(
    1975          94 :                                                       new_begin_or_before_end); assert(new_action_block_pos <= old_begin_or_before_end);
    1976         299 :                 return;
    1977         359 :             }                                                                   assert(new_begin_or_before_end == new_action_block_pos);
    1978         359 :             if (old_begin_or_before_end < new_action_block_pos)  return;
    1979             :         }
    1980             : 
    1981             :         // this is the first transition in the new action_block-slice.
    1982             :         // Check whether the bunch it belongs to has become nontrivial.
    1983         496 :         bunch_t* bunch(new_action_block_pos->succ()->bunch());
    1984         248 :         if (!bunch->is_trivial())  return;                                      assert(old_begin_or_before_end + 1 == bunch->end);
    1985          74 :         if (bunch->begin < new_action_block_pos)
    1986             :         {
    1987          30 :             make_nontrivial(bunch);
    1988             :         }
    1989             :     }
    1990             : 
    1991             : 
    1992             :     /// \brief adapt data structures for a transition that has become non-inert
    1993             :     /// \details If the action_block-slice and the block_bunch-slice that
    1994             :     /// precede the inert transitions in the respective arrays fit, the
    1995             :     /// transition is added to these arrays instead of creating a new one.
    1996             :     /// This only works if:
    1997             :     /// - the action_block-slice has the same target block and the same action
    1998             :     ///   as old_pred_pos
    1999             :     /// - the block_bunch-slice has the same source block as old_pred_pos
    2000             :     /// - the bunch must contain the action_block-slice.
    2001             :     /// If only the last two conditions are fulfilled, we can start a new
    2002             :     /// action_block-slice in the same bunch.  (It would be best for this if
    2003             :     /// the red subblock's block_bunch-slice would be the new one, because that
    2004             :     /// would generally allow to add the new non-inert transitions to the last
    2005             :     /// splitter.)
    2006             :     ///
    2007             :     /// The state is only marked if is becomes a new bottom state.  Otherwise,
    2008             :     /// the marking/unmarking of the state is unchanged.
    2009             :     /// \param         old_pred_pos the transition that needs to be adapted.
    2010             :     ///                             Note that this parameter is passed by value
    2011             :     ///                             -- otherwise, as this parameter is not only
    2012             :     ///                             read at the beginning, it may happen that
    2013             :     ///                             it is read after the transition has partly
    2014             :     ///                             already been changed.
    2015             :     /// \param[in,out] new_noninert_block_bunch_ptr the bunch where new
    2016             :     ///                             non-inert transitions have to be stored.
    2017             :     ///                             If no such bunch has yet been created, it
    2018             :     ///                             is nullptr; in that case, make_noninert()
    2019             :     ///                             creates a new bunch.
    2020             :     /// \returns true iff the state became a new bottom state
    2021          77 :     bool make_noninert(pred_iter_t const old_pred_pos, iterator_or_null<
    2022             :                  block_bunch_slice_iter_t>* const new_noninert_block_bunch_ptr)
    2023             :     {
    2024          77 :         state_info_iter_t const source(old_pred_pos->source);                   assert(source->pos->st == source);
    2025          77 :         state_info_iter_t const target(old_pred_pos->target);                   assert(target->pos->st == target);
    2026             : 
    2027          77 :         action_block_iter_t new_action_block_pos(action_block_inert_begin++);   assert(new_action_block_pos->succ()->block_bunch->pred->action_block ==
    2028          77 :                                                                                                                                          new_action_block_pos);
    2029          77 :         succ_iter_t const new_succ_pos(source->succ_inert.begin++);             assert(new_succ_pos->block_bunch->pred->action_block->succ() == new_succ_pos);
    2030             :         block_bunch_iter_t const new_block_bunch_pos(
    2031          77 :                                                     block_bunch_inert_begin++); assert(new_block_bunch_pos->pred->action_block->succ()->block_bunch ==
    2032          77 :                                                                                                                                           new_block_bunch_pos);
    2033             :         {
    2034             :             action_block_iter_t const old_action_block_pos(
    2035          77 :                                                    old_pred_pos->action_block);
    2036             : 
    2037          77 :             succ_iter_t const old_succ_pos(old_action_block_pos->succ());
    2038             :             block_bunch_iter_t const old_block_bunch_pos(
    2039          77 :                                                     old_succ_pos->block_bunch); assert(old_pred_pos == old_block_bunch_pos->pred);
    2040          77 :             pred_iter_t const new_pred_pos(target->pred_inert.begin++);         assert(new_pred_pos->action_block->succ()->block_bunch->pred == new_pred_pos);
    2041             : 
    2042          77 :             /* adapt action_block                                            */ assert(new_action_block_pos->begin_or_before_end.is_null());
    2043          77 :             if (new_action_block_pos < old_action_block_pos)
    2044          56 :             {                                                                   assert(old_action_block_pos->begin_or_before_end.is_null());
    2045          56 :                 old_action_block_pos->succ.change(
    2046         112 :                                                  new_action_block_pos->succ()); assert(old_action_block_pos->succ()->block_bunch->pred->action_block ==
    2047          56 :                                                                                                                                          new_action_block_pos);
    2048          56 :                 old_action_block_pos->succ()->block_bunch->pred->action_block =
    2049          56 :                                                           old_action_block_pos;
    2050          21 :             }                                                                   else  assert(new_action_block_pos == old_action_block_pos);
    2051          77 :             new_action_block_pos->succ.change(new_succ_pos);
    2052             :             // new_action_block_pos->begin_or_before_end.set(...); -- see below
    2053             : 
    2054          77 :             /* adapt succ                                                    */ assert(new_succ_pos->begin_or_before_end.is_null());
    2055          77 :             if (new_succ_pos < old_succ_pos)
    2056           5 :             {                                                                   assert(old_succ_pos->begin_or_before_end.is_null());
    2057           5 :                 old_succ_pos->block_bunch = new_succ_pos->block_bunch;          assert(old_succ_pos->block_bunch->pred->action_block->succ() == new_succ_pos);
    2058           5 :                 old_succ_pos->block_bunch->pred->action_block->succ.change(
    2059           5 :                                                                  old_succ_pos);
    2060          72 :             }                                                                   else  assert(new_succ_pos == old_succ_pos);
    2061          77 :             new_succ_pos->block_bunch = new_block_bunch_pos;
    2062             :             // new_succ_pos->begin_or_before_end.set(...); -- see below
    2063             : 
    2064          77 :             /* adapt block_bunch                                             */ assert(new_block_bunch_pos->slice.is_null());
    2065          77 :             if (new_block_bunch_pos < old_block_bunch_pos)
    2066          56 :             {                                                                   assert(old_block_bunch_pos->slice.is_null());
    2067          56 :                 old_block_bunch_pos->pred = new_block_bunch_pos->pred;          assert(old_block_bunch_pos->pred->action_block->succ()->block_bunch ==
    2068          56 :                                                                                                                                           new_block_bunch_pos);
    2069          56 :                 old_block_bunch_pos->pred->action_block->succ()->block_bunch =
    2070          56 :                                                            old_block_bunch_pos;
    2071          21 :             }                                                                   else  assert(new_block_bunch_pos == old_block_bunch_pos);
    2072          77 :             new_block_bunch_pos->pred = new_pred_pos;
    2073             :             // new_block_bunch_pos->slice = ...; -- see below
    2074             : 
    2075             :             // adapt pred
    2076          77 :             if (new_pred_pos < old_pred_pos)
    2077             :             {
    2078             :                 // We need std::swap here to swap the whole content, including
    2079             :                 // work counters in case we measure the work.
    2080           9 :                 std::swap(*old_pred_pos, *new_pred_pos);                        assert(old_pred_pos->action_block->succ()->block_bunch->pred == new_pred_pos);
    2081           9 :                 old_pred_pos->action_block->succ()->block_bunch->pred =
    2082           9 :                                                                   old_pred_pos;
    2083          68 :             }                                                                   else  assert(new_pred_pos == old_pred_pos);
    2084          77 :             new_pred_pos->action_block = new_action_block_pos;
    2085             :         }
    2086             : 
    2087             :         // make the state a bottom state if necessary
    2088          77 :         block_t* const source_block(source->block);                             assert(source_block->nonbottom_begin <= source->pos);
    2089          77 :         bool became_bottom(false);                                              assert(succ.cend()[-1].block_bunch->pred->source != source);
    2090          77 :         if (source != source->succ_inert.begin->block_bunch->pred->source)
    2091             :         {
    2092             :             // ++number_of_new_bottom_states;
    2093             :             // make the state a marked bottom state
    2094          62 :             if (source->pos >= source_block->marked_nonbottom_begin)
    2095             :             {
    2096           0 :                 std::swap(*source->pos,
    2097           0 :                                       *source_block->marked_nonbottom_begin++);
    2098          62 :             }                                                                   assert(source->pos < source->block->marked_nonbottom_begin);
    2099          62 :             std::swap(*source->pos, *source_block->nonbottom_begin++);
    2100          62 :             became_bottom = true;
    2101             :         }
    2102             : 
    2103             :         bunch_t* new_noninert_bunch;
    2104          77 :         if (!new_noninert_block_bunch_ptr->is_null())
    2105             :         {
    2106             :             // There is already some new non-inert transition from this block.
    2107             :             // So we can reuse this block_bunch and its bunch.
    2108             :             // (However, it may be the case that the current transition goes to
    2109             :             // another block; in the latter case, we have to create a new
    2110             :             // action_block-slice.)
    2111             : 
    2112             :             // extend the bunch
    2113          76 :             new_noninert_bunch = (*new_noninert_block_bunch_ptr)()->bunch();    assert(new_action_block_pos == new_noninert_bunch->end ||
    2114             :                                                                                                         (new_action_block_pos[-1].succ.is_null() &&
    2115          94 :                                                                                                          new_action_block_pos - 1 == new_noninert_bunch->end));
    2116          33 :             new_noninert_bunch->end = action_block_inert_begin;
    2117          33 :                                                                                 assert((*new_noninert_block_bunch_ptr)()->is_stable());
    2118          33 :             /* extend the block_bunch-slice                                  */ assert((*new_noninert_block_bunch_ptr)()->end == new_block_bunch_pos);
    2119          33 :             (*new_noninert_block_bunch_ptr)()->end = block_bunch_inert_begin;
    2120          33 :             new_block_bunch_pos->slice.set((*new_noninert_block_bunch_ptr)());
    2121             : 
    2122          33 :             /* adapt the action_block-slice                                  */ assert(new_noninert_bunch->begin < new_action_block_pos);
    2123          61 :             if (!new_action_block_pos[-1].succ.is_null() && target->block ==
    2124          28 :              new_action_block_pos[-1].succ()->block_bunch->pred->target->block)
    2125             :             {
    2126             :                 // the action_block-slice is suitable: extend it
    2127             :                 action_block_iter_t const action_block_slice_begin(
    2128          23 :                                new_action_block_pos[-1].begin_or_before_end()); assert(new_action_block_pos - 1 ==
    2129          23 :                                                                                                               action_block_slice_begin->begin_or_before_end());
    2130          23 :                                                                                 assert(action_block_slice_begin->succ()->block_bunch->pred->action_block ==
    2131          23 :                                                                                                                                      action_block_slice_begin);
    2132          23 :                 action_block_slice_begin->begin_or_before_end.change(
    2133          23 :                                                          new_action_block_pos);
    2134          23 :                 new_action_block_pos->begin_or_before_end.set(
    2135          23 :                                                      action_block_slice_begin);
    2136             :             }
    2137             :             else
    2138             :             {
    2139             :                 // create a new action_block-slice
    2140          10 :                 new_action_block_pos->begin_or_before_end.set(
    2141          10 :                                                          new_action_block_pos);
    2142          10 :                 if (new_noninert_bunch->is_trivial())
    2143             :                 {                                                               // Only during initialisation, it may happen that we add new non-inert
    2144           8 :                     make_nontrivial(new_noninert_bunch);                        // transitions to a nontrivial bunch:
    2145           2 :                 }                                                               else assert(action_block.cbegin() == new_noninert_bunch->begin);
    2146             :             }
    2147             : 
    2148          33 :             /* adapt the out-slice                                           */ assert(source != succ.cbegin()->block_bunch->pred->source);
    2149          61 :             if (source == new_succ_pos[-1].block_bunch->pred->source &&
    2150          28 :                                 new_succ_pos[-1].bunch() == new_noninert_bunch)
    2151             :             {
    2152             :                 // the out-slice is suitable: extend it.
    2153             :                 succ_iter_t out_slice_begin(
    2154          13 :                                        new_succ_pos[-1].begin_or_before_end()); assert(new_succ_pos - 1 == out_slice_begin->begin_or_before_end());
    2155          13 :                 out_slice_begin->begin_or_before_end.change(new_succ_pos);      assert(out_slice_begin->block_bunch->pred->action_block->succ() ==
    2156          13 :                                                                                                                                               out_slice_begin);
    2157          13 :                 new_succ_pos->begin_or_before_end.set(out_slice_begin);
    2158          13 :                 return became_bottom;
    2159             :             }
    2160             :         }
    2161             :         else
    2162             :         {
    2163             :             // create a new bunch for noninert transitions
    2164             :             new_noninert_bunch = new bunch_t(new_action_block_pos,
    2165             :                    action_block_inert_begin,
    2166          44 :                    new_action_block_pos - action_block.end() + TRANS_TYPE_MAX);
    2167             : 
    2168             :             // create a new block_bunch-slice
    2169             :             // (While it's technically unstable, we immediately stabilise for
    2170             :             // it afterwards.  So we already insert it in the list of stable
    2171             :             // slices.)
    2172             :             block_bunch_slice_iter_t new_noninert_block_bunch(source_block->
    2173          88 :              stable_block_bunch.emplace(source_block->stable_block_bunch.end(),
    2174         132 :                            block_bunch_inert_begin, new_noninert_bunch, true));
    2175          44 :             new_block_bunch_pos->slice.set(new_noninert_block_bunch);
    2176          44 :             new_noninert_block_bunch_ptr->set(new_noninert_block_bunch);
    2177             : 
    2178             :             // create a new action_block-slice
    2179          44 :             new_action_block_pos->begin_or_before_end.set(
    2180          44 :                                                          new_action_block_pos);
    2181         249 :         }                                                                       assert(succ.cbegin() + 1 == new_succ_pos ||
    2182             :                                                                                                 new_succ_pos[-1].block_bunch->pred->source < source ||
    2183         192 :         /* create a new out-slice                                            */                               *new_succ_pos[-1].bunch() < *new_noninert_bunch);
    2184          64 :         new_succ_pos->begin_or_before_end.set(new_succ_pos);
    2185          64 :         return became_bottom;
    2186             :     }
    2187             : 
    2188             : 
    2189             :   public:
    2190             :     /// \brief Split all data structures after a new block has been created
    2191             :     /// \details This function splits the block_bunch- and action_block-slices
    2192             :     /// to reflect that some transitions now start or end in the new block.
    2193             :     /// They can no longer be in the same slice as the transitions that start
    2194             :     /// or end in the old block, respectively.  It also marks the transitions
    2195             :     /// that have become non-inert as such and finds new bottom states.
    2196             :     ///
    2197             :     /// Its time complexity is O(1 + |in(new_block)| + |out(new_block)|).
    2198             :     /// \param new_block       the new block
    2199             :     /// \param old_block       the old block (from which new_block was split
    2200             :     ///                        off)
    2201             :     /// \param use_splitter_for_new_noninert_block_bunch  indicates to which
    2202             :     ///                        block_bunch-slice new non-inert transitions
    2203             :     ///                        should be added:  if this parameter is null,
    2204             :     ///                        a new slice is created;  if it is not null,
    2205             :     ///                        new non-inert transitions are added to this
    2206             :     ///                        block_bunch-slice (which must be in the correct
    2207             :     ///                        position to allow this).
    2208             :     /// \param last_splitter   the splitter that caused new_block and old_block
    2209             :     ///                        to separate from each other
    2210             :     /// \param new_block_mode  indicates whether the new block is blue or red
    2211             :                                                                                 ONLY_IF_DEBUG( template<class LTS_TYPE> )
    2212         208 :     void adapt_transitions_for_new_block(
    2213             :                   block_t* const new_block,
    2214             :                   block_t* const old_block,                                     ONLY_IF_DEBUG( const bisim_partitioner_dnj<LTS_TYPE>& partitioner, )
    2215             :                   bool use_splitter_for_new_noninert_block_bunch,
    2216             :                   const block_bunch_slice_iter_t& last_splitter,
    2217             :                   enum new_block_mode_t const new_block_mode)
    2218         208 :     {                                                                           assert(last_splitter->is_stable());
    2219             :         // We begin with a bottom state so the new block gets a sorted list of
    2220             :         // stable block_bunch-slices.
    2221             :         {
    2222         208 :             permutation_iter_t s_iter(new_block->begin);                        assert(s_iter < new_block->end);
    2223         393 :             do
    2224             :             {
    2225         393 :                 state_info_iter_t const s(s_iter->st);                          assert(new_block == s->block);
    2226         393 :                                                                                 assert(s->pos == s_iter);
    2227             :                 /*  -  -  -  -  -  adapt part_tr.block_bunch  -  -  -  -  -  */
    2228         393 :                                                                                 assert(s != succ.cbegin()->block_bunch->pred->source);
    2229             :         // Line 2.29: for all outgoing non-inert transitions of the new block
    2230             :         //            do
    2231        1594 :                 for (succ_iter_t succ_iter(s->succ_inert.begin);
    2232         797 :                                 s == succ_iter[-1].block_bunch->pred->source; )
    2233             :                 {
    2234             :                     // Line 2.30: Create a new block bunch-slice if necessary
    2235             :                     // and
    2236             :                     // Line 2.31: Move the transition to the new
    2237             :                     //            block_bunch-slice
    2238         404 :                     succ_iter = move_out_slice_to_new_block(                    ONLY_IF_DEBUG( partitioner, )
    2239         404 :                                           succ_iter, old_block, last_splitter); assert(succ_iter->block_bunch->pred->action_block->succ() == succ_iter);
    2240             :         // Line 2.32: end for                                                   // add_work_to_out_slice(succ_iter, ...) -- subsumed in the call below
    2241             :                 }
    2242             : 
    2243             :                 /* -  -  -  -  -  adapt part_tr.action_block  -  -  -  -  - */
    2244         393 :                                                                                 assert(s != pred.cbegin()->target);
    2245             :         // Line 2.33: for all incoming non-inert transitions of the new block
    2246             :         //            do
    2247        1692 :                 for (pred_iter_t pred_iter(s->pred_inert.begin);
    2248         846 :                                                   s == (--pred_iter)->target; )
    2249         453 :                 {                                                               assert(pred.cbegin() + 1 <= pred_iter);
    2250         453 :                     /* Line 2.34: Create a new action block-slice            */ assert(pred_iter->action_block->succ()->block_bunch->pred == pred_iter);
    2251             :                     //            if necessary
    2252             :                     // and
    2253             :                     // Line 2.35: Move the transition to the new
    2254             :                     //            action_block-slice
    2255         453 :                     first_move_transition_to_new_action_block(pred_iter);       // mCRL2complexity(pred_iter, ...) -- subsumed in the call below
    2256             :         // Line 2.36: end for
    2257             :                 }                                                               // mCRL2complexity(s, ...) -- subsumed in the call at the end
    2258             :             }
    2259         393 :             while (++s_iter < new_block->end);
    2260             :         }
    2261         208 :         if (new_block_is_red == new_block_mode)
    2262         135 :         {                                                                       assert(last_splitter->source_block() == new_block);
    2263             :             // The last_splitter slice moves completely from the old to the new
    2264             :             // block.  We move it as a whole to the new block_bunch list.
    2265         270 :             new_block->stable_block_bunch.splice(
    2266         135 :                     new_block->stable_block_bunch.begin(),
    2267             :                                  old_block->stable_block_bunch, last_splitter);
    2268          73 :         }                                                                       else assert(last_splitter->source_block() == old_block);
    2269             : 
    2270             :         // We cannot join the loop above with the one below because transitions
    2271             :         // in the action_block-slices need to be handled in two phases.
    2272             : 
    2273             :         // Line 2.33: for all incoming non-inert transitions of the new block
    2274             :         //            do
    2275             :         {
    2276         208 :             permutation_iter_t s_iter(new_block->begin);                        assert(s_iter < new_block->end);
    2277         393 :             do
    2278             :             {
    2279         393 :                 state_info_iter_t const s(s_iter->st);                          assert(s->pos == s_iter);  assert(s != pred.cbegin()->target);
    2280        1692 :                 for (pred_iter_t pred_iter(s->pred_inert.begin);
    2281         846 :                                                   s == (--pred_iter)->target; )
    2282         453 :                 {                                                               assert(pred.cbegin() + 1 <= pred_iter);
    2283         453 :                     /* Line 2.34: Create a new action block-slice            */ assert(pred_iter->action_block->succ()->block_bunch->pred == pred_iter);
    2284             :                     //            if necessary
    2285             :                     // and
    2286             :                     // Line 2.35: Move the transition to the new
    2287             :                     //            action_block-slice
    2288         453 :                     second_move_transition_to_new_action_block(pred_iter);      // mCRL2complexity(pred_iter, ...) -- subsumed in the call below
    2289             :         // Line 2.36: end for
    2290             :                 }                                                               // mCRL2complexity(s, ...) -- subsumed in the call at the end
    2291             :             }
    2292         393 :             while (++s_iter < new_block->end);
    2293             :         }
    2294         208 :                                                                                 assert(0 == new_block->marked_size());  assert(0==old_block->marked_size());
    2295         208 :         /* -  -  -  -  -  - find new non-inert transitions -  -  -  -  -  - */  assert(block_bunch.end() - block_bunch_inert_begin ==
    2296             :                                                                                                                 action_block.end() - action_block_inert_begin);
    2297         208 :         if (block_bunch_inert_begin < block_bunch.end())
    2298             :         {
    2299         198 :             iterator_or_null<block_bunch_slice_iter_t>new_noninert_block_bunch;
    2300          99 :             if (use_splitter_for_new_noninert_block_bunch)
    2301             :             {
    2302          19 :                 new_noninert_block_bunch.set(last_splitter);
    2303             :             }
    2304             :             // Line 2.37: if the new block is blue then
    2305          99 :             if (new_block_is_blue == new_block_mode)
    2306          38 :             {                                                                   assert(old_block == new_block->end->st->block);
    2307             :                 // Line 2.38: for all incoming inert transitions t --tau--> s
    2308          38 :                 /*                                       of the new block do */ assert(new_block->end < partitioner.part_st.permutation.cend());
    2309          38 :                 permutation_iter_t target_iter(new_block->begin);               assert(target_iter < new_block->end);
    2310          61 :                 do
    2311             :                 {
    2312          61 :                     state_info_iter_t const s(target_iter->st);                 assert(s->pos == target_iter);
    2313             :                     // check all incoming inert transitions of s, whether they
    2314          61 :                     /* still start in new_block                              */ assert(s != pred.cend()[-1].target);
    2315         192 :                     for (pred_iter_t pred_iter(s->pred_inert.begin);
    2316          96 :                                            s == pred_iter->target; ++pred_iter)
    2317          35 :                     {                                                           assert(pred_iter < pred.cend() - 1);
    2318          35 :                                                                                 assert(pred_iter->action_block->succ()->block_bunch->pred == pred_iter);
    2319          35 :                         state_info_iter_t const t(pred_iter->source);           assert(t->pos->st == t);
    2320             :                         // Line 2.39: if t is in the red subblock then ...
    2321          35 :                         if (new_block != t->block)
    2322          27 :                         {                                                       assert(old_block == t->block);
    2323             :                             // Line 2.39: ... Make t --tau--> s non-inert ...
    2324          27 :                             if (!make_noninert(pred_iter,
    2325             :                                                     &new_noninert_block_bunch))
    2326             :                                        // make_noninert() may modify *pred_iter
    2327             :                             {
    2328             :                                 // Line 2.39: ... and Mark t
    2329           4 :                                 old_block->mark_nonbottom(t->pos);
    2330             :                             }
    2331             :                         }                                                       // mCRL2complexity(old value of *pred_iter, ...) -- overapproximated by the
    2332             :                 // Line 2.40: end for                                           // call below
    2333             :                     }                                                           // mCRL2complexity(s, ...) -- subsumed in the call at the end
    2334             :                 }
    2335          99 :                 while (++target_iter < new_block->end);                         assert(0 < old_block->bottom_size());
    2336             :             // Line 2.41: else
    2337             :             }
    2338             :             else
    2339          61 :             {                                                                   assert(new_block_is_red == new_block_mode);
    2340             :                 // Line 2.42: for all outgoing inert transitions s --tau--> t
    2341             :                 //                                          of the new block do
    2342          61 :                     /* We have to be careful because make_noninert may make a*/ assert(partitioner.part_st.permutation.cbegin() < new_block->begin);
    2343          61 :                     /* state move either forward (to the marked states) or   */ assert(old_block == new_block->begin[-1].st->block);
    2344          61 :                     /* back (to the bottom states).                          */ assert(0 < old_block->bottom_size());
    2345         336 :                 for(permutation_iter_t source_iter(new_block->nonbottom_begin);
    2346         168 :                              source_iter < new_block->marked_nonbottom_begin; )
    2347             :                 {
    2348         107 :                     state_info_iter_t const s(source_iter->st);                 assert(s->pos == source_iter);
    2349             :                     // check all outgoing inert transitions of s, whether they
    2350         107 :                     /* still end in new_block.                               */ assert(succ.cend()[-1].block_bunch->pred->source != s);
    2351         107 :                     succ_iter_t succ_iter(s->succ_inert.begin);                 assert(succ_iter < succ.cend() - 1);
    2352         107 :                     bool dont_mark(true);                                       assert(s == succ_iter->block_bunch->pred->source);
    2353         122 :                     do
    2354         122 :                     {                                                           assert(succ_iter->block_bunch->pred->action_block->succ() == succ_iter);
    2355             :                         // 2.43: if t is in the blue subblock then ...
    2356         122 :                         if (new_block !=
    2357             :                                    succ_iter->block_bunch->pred->target->block)
    2358          50 :                         {                                                       assert(old_block == succ_iter->block_bunch->pred->target->block);
    2359             :                             // Line 2.43: Make s --tau--> t non-inert ...
    2360          50 :                             dont_mark = make_noninert(
    2361             :                                                   succ_iter->block_bunch->pred,
    2362             :                                                     &new_noninert_block_bunch);
    2363             :                         }                                                        // mCRL2complexity(succ_iter->block_bunch->pred, ...) -- overapproximated by
    2364             :                 // Line 2.44: end for                                            // the call below
    2365             :                     }
    2366         122 :                     while (s == (++succ_iter)->block_bunch->pred->source);
    2367             :                     // Line 2.43: ... and Mark s
    2368         107 :                     if (dont_mark)  ++source_iter;
    2369             :                     else
    2370          10 :                     {                                                           assert(s->pos == source_iter);
    2371          10 :                         new_block->mark_nonbottom(source_iter);
    2372         107 :                     }                                                           assert(new_block->nonbottom_begin <= source_iter);
    2373             :                                                                                 // mCRL2complexity(s, ...) -- overapproximated by the call at the end
    2374             :                 }
    2375             :             // Line 2.45: end if
    2376             :             }
    2377         109 :         }                                                                       else  assert(block_bunch_inert_begin == block_bunch.end());
    2378         208 :                                                                                 mCRL2complexity(new_block, add_work(bisim_gjkw::check_complexity::
    2379             :                                                                                     adapt_transitions_for_new_block, bisim_gjkw::check_complexity::log_n -
    2380             :                                                                                                     bisim_gjkw::check_complexity::ilog2(new_block->size())),
    2381             :                                                                                                                               partitioner.part_st.permutation);
    2382         208 :     }
    2383             :                                                                                 #ifndef NDEBUG
    2384             :                                                                                     /// \brief print all transitions
    2385             :                                                                                     /// \details Transitions are printed organised into bunches.
    2386             :                                                                                     template <class LTS_TYPE>
    2387         329 :                                                                                     void print_trans(const bisim_partitioner_dnj<LTS_TYPE>& partitioner) const
    2388             :                                                                                     {
    2389         658 :                                                                                         if (!mCRL2logEnabled(log::debug, "bisim_dnj"))  return;
    2390             :                                                                                         // for all bunches
    2391           0 :                                                                                         action_block_const_iter_t action_block_iter(action_block.cbegin());
    2392           0 :                                                                                         do
    2393             :                                                                                         {
    2394           0 :                                                                                             if (action_block_iter >= action_block.cend())
    2395             :                                                                                             {
    2396           0 :                                                                                                 mCRL2log(log::debug, "bisim_dnj") << "No transitions.\n";
    2397           0 :                                                                                                 return;
    2398             :                                                                                             }
    2399           0 :                                                                                         } while (action_block_iter->succ.is_null() &&
    2400           0 :                                                                                                    (assert(action_block_iter->begin_or_before_end.is_null()),
    2401             :                                                                                                     ++action_block_iter, true));
    2402           0 :                                                                                         do
    2403             :                                                                                         {
    2404           0 :                                                                                             action_block_const_iter_t bunch_end;
    2405           0 :                                                                                             action_block_const_iter_t action_block_slice_end;
    2406           0 :                                                                                             if (action_block_iter->succ()->block_bunch->slice.is_null())
    2407           0 :                                                                                             {   assert(action_block_iter == action_block_inert_begin);
    2408           0 :                                                                                                 mCRL2log(log::debug, "bisim_dnj") <<"Inert transition slice [";
    2409           0 :                                                                                                 action_block_slice_end = bunch_end = action_block.cend();
    2410             :                                                                                             }
    2411             :                                                                                             else
    2412             :                                                                                             {
    2413           0 :                                                                                                 const bunch_t* const bunch(action_block_iter->succ()->bunch());
    2414           0 :                                                                                                 mCRL2log(log::debug, "bisim_dnj") << bunch->debug_id_short(
    2415             :                                                                                                                    partitioner) << ":\n\taction_block-slice [";
    2416           0 :                                                                                                 assert(bunch->begin == action_block_iter);
    2417           0 :                                                                                                 bunch_end = bunch->end;
    2418           0 :                                                                                                 assert(bunch_end <= action_block_inert_begin);
    2419           0 :                                                                                                 action_block_slice_end =
    2420           0 :                                                                                                                   action_block_iter->begin_or_before_end() + 1;
    2421             :                                                                                             }
    2422           0 :                                                                                             assert(action_block_slice_end <= bunch_end);
    2423             :                                                                                             // for all action_block-slices in bunch
    2424           0 :                                                                                             for (;;)
    2425             :                                                                                             {
    2426           0 :                                                                                                 mCRL2log(log::debug,"bisim_dnj") << (action_block_iter -
    2427           0 :                                                                                                                                   action_block.cbegin()) << ","
    2428           0 :                                                                                                    << (action_block_slice_end-action_block.cbegin()) << "):\n";
    2429             :                                                                                                 // for all transitions in the action_block-slice
    2430           0 :                                                                                                 assert(action_block_iter < action_block_slice_end);
    2431           0 :                                                                                                 do
    2432             :                                                                                                 {
    2433           0 :                                                                                                     mCRL2log(log::debug, "bisim_dnj") << "\t\t"
    2434           0 :                                                                                                             << action_block_iter->succ()->block_bunch->
    2435             :                                                                                                                            pred->debug_id(partitioner) << '\n';
    2436             :                                                                                                 }
    2437           0 :                                                                                                 while (++action_block_iter < action_block_slice_end);
    2438             :                                                                                                 // go to next action_block-slice in the same bunch
    2439           0 :                                                                                                 while (action_block_iter < bunch_end &&
    2440           0 :                                                                                                                              action_block_iter->succ.is_null())
    2441             :                                                                                                 {
    2442           0 :                                                                                                     assert(action_block_iter->begin_or_before_end.is_null());
    2443           0 :                                                                                                     ++action_block_iter;
    2444           0 :                                                                                                     assert(action_block_iter < bunch_end);
    2445             :                                                                                                 }
    2446           0 :                                                                                                 if (action_block_iter >= bunch_end)  break;
    2447           0 :                                                                                                 action_block_slice_end =
    2448           0 :                                                                                                                   action_block_iter->begin_or_before_end() + 1;
    2449           0 :                                                                                                 mCRL2log(log::debug, "bisim_dnj") << "\taction_block-slice [";
    2450             :                                                                                             }
    2451             :                                                                                             // go to next bunch
    2452           0 :                                                                                             assert(action_block_iter == bunch_end);
    2453           0 :                                                                                             while(action_block_iter < action_block.cend() &&
    2454           0 :                                                                                                                              action_block_iter->succ.is_null())
    2455             :                                                                                             {
    2456           0 :                                                                                                 assert(action_block_iter->begin_or_before_end.is_null());
    2457           0 :                                                                                                 ++action_block_iter;
    2458             :                                                                                             }
    2459             :                                                                                         }
    2460           0 :                                                                                         while (action_block_iter < action_block.cend());
    2461             :                                                                                     }
    2462             :                                                                                 #endif
    2463             : };
    2464             : 
    2465             : /// \brief split off a single action_block-slice from the bunch
    2466             : /// \details The function splits the current bunch after
    2467             : /// its first action_block-slice or before its last
    2468             : /// action_block-slice, whichever is smaller.  It creates
    2469             : /// a new bunch for the split-off slice and returns a pointer to the
    2470             : /// new bunch.  The caller has to adapt the block_bunch-slices.
    2471         226 : inline bunch_t* bunch_t::split_off_small_action_block_slice(
    2472             :                                                          part_trans_t& part_tr)
    2473         226 : {                                                                               assert(begin < end);  assert(!begin->succ.is_null());
    2474         226 :     action_block_iter_t first_slice_end(begin->begin_or_before_end() + 1);      assert(!end[-1].succ.is_null());
    2475         226 :     action_block_iter_t last_slice_begin(end[-1].begin_or_before_end());        assert(begin < first_slice_end);  assert(first_slice_end <= last_slice_begin);
    2476         226 :     bunch_t* new_bunch;                                                         assert(last_slice_begin < end);  assert(!first_slice_end[-1].succ.is_null());
    2477         226 :     /* Line 1.11: Select a small action_block-slice in splitter_bunch        */ assert(!last_slice_begin->succ.is_null());
    2478             :     //            i.e. |new_bunch| <= 1/2*|splitter_bunch|
    2479             :         // It doesn't matter very much how ties are resolved here:
    2480         226 :     if (first_slice_end - begin > end - last_slice_begin)
    2481             :     {
    2482             :         // Line 1.12: Create a new bunch new_bunch that consists of the
    2483             :         //            selected action_block-slice
    2484             :         new_bunch = new bunch_t(last_slice_begin, end,
    2485          78 :                      sort_key_and_label.sort_key + (last_slice_begin - begin));
    2486          78 :         end = last_slice_begin;
    2487         106 :         while (end[-1].succ.is_null())
    2488             :         {
    2489          14 :             --end;                                                              assert(first_slice_end <= end);  assert(end->begin_or_before_end.is_null());
    2490          78 :         }                                                                       assert(!end[-1].begin_or_before_end.is_null());
    2491          78 :         if (first_slice_end == end)  part_tr.make_trivial(this);
    2492             :     }
    2493             :     else
    2494             :     {
    2495             :         // Line 1.12: Create a new bunch new_bunch that consists of the
    2496             :         //            selected action_block-slice
    2497             :         new_bunch = new bunch_t(begin, first_slice_end,
    2498         148 :                         sort_key_and_label.sort_key + (end - first_slice_end));
    2499         148 :         begin = first_slice_end;
    2500         288 :         while (begin->succ.is_null())
    2501          70 :         {                                                                       assert(begin->begin_or_before_end.is_null());
    2502          70 :             ++begin;                                                            assert(begin <= last_slice_begin);
    2503         148 :         }                                                                       assert(!begin->begin_or_before_end.is_null());
    2504         148 :         if (begin == last_slice_begin)  part_tr.make_trivial(this);
    2505         226 :     }                                                                           ONLY_IF_DEBUG( new_bunch->work_counter = work_counter; )
    2506         226 :     return new_bunch;
    2507             : }
    2508             : ///@} (end of group part_trans)
    2509             : 
    2510             : 
    2511             : 
    2512             : 
    2513             : 
    2514             : /* ************************************************************************* */
    2515             : /*                                                                           */
    2516             : /*                            A L G O R I T H M S                            */
    2517             : /*                                                                           */
    2518             : /* ************************************************************************* */
    2519             : 
    2520             : 
    2521             : 
    2522             : 
    2523             : 
    2524             : /// \defgroup part_refine
    2525             : /// \brief classes to calculate the stutter equivalence quotient of a LTS
    2526             : ///@{
    2527             : 
    2528             : 
    2529             : 
    2530             : /*=============================================================================
    2531             : =                                 main class                                  =
    2532             : =============================================================================*/
    2533             : 
    2534             : 
    2535             : 
    2536             : 
    2537             : 
    2538             : enum refine_mode_t { extend_from_marked_states,
    2539             :                      extend_from_marked_states_for_init_and_postprocess,
    2540             :                      extend_from_splitter,
    2541             :                      extend_from_bottom_state_markings_and_splitter };
    2542             : 
    2543             : 
    2544             : /// \brief Internal functional to compare new bottom states
    2545             : /// \details The functions in this class are used to sort and search
    2546             : /// through the new bottom states.  For efficiency, they are ordered
    2547             : /// according to their current out-slice (containing transitions to a
    2548             : /// specific bunch).  That means that new bottom states can quickly be
    2549             : /// separated into those that can reach that bunch and those that cannot.
    2550             : static struct {
    2551             :     /// \brief Comparison operator for the current out-slice of new bottom
    2552             :     /// states
    2553             :     /// \details This variant can be used for std::lower_bound, to compare
    2554             :     /// a current out-slice pointer with a bunch directly.
    2555          31 :     bool operator()(const permutation_entry& p1, const bunch_t* p2) const
    2556             :     {                                                                           // assert(succ.cbegin()->block_bunch->pred->source != p1.st);
    2557          31 :         return p1.st->current_out_slice.begin[-1].block_bunch->pred->source !=
    2558          62 :                                                                        p1.st ||
    2559          62 :                              *p1.st->current_out_slice.begin[-1].bunch() < *p2;
    2560             :     }
    2561             : 
    2562             :     /// \brief Comparison operator for the current out-slice of new bottom
    2563             :     /// states
    2564             :     /// \details This variant can be used for std::sort, to compare the
    2565             :     /// current out-slices of two states.
    2566          30 :     bool operator()(const permutation_entry& p1,
    2567             :                                              const permutation_entry& p2) const
    2568             :     {                                                                           // assert(succ.cbegin()->block_bunch->pred->source != p2.st);
    2569          30 :         return p2.st->current_out_slice.begin[-1].block_bunch->pred->source ==
    2570          60 :                                                                        p2.st &&
    2571          60 :                     operator()(p1, p2.st->current_out_slice.begin[-1].bunch());
    2572             :     }
    2573             : } before_current_out_slice_less;
    2574             : 
    2575             : 
    2576             : /// \class bisim_partitioner_dnj
    2577             : /// \brief implements the main algorithm for the branching bisimulation
    2578             : /// quotient
    2579             : template <class LTS_TYPE>
    2580          52 : class bisim_partitioner_dnj
    2581             : {
    2582             :   private:
    2583             :     /// \brief automaton that is being reduced
    2584             :     LTS_TYPE& aut;
    2585             :                                                                                 ONLY_IF_DEBUG( public: )
    2586             :     /// \brief partition of the state space into blocks
    2587             :     part_state_t part_st;
    2588             : 
    2589             :     /// \brief partitions of the transitions (with bunches and
    2590             :     /// action_block-slices)
    2591             :     part_trans_t part_tr;
    2592             :   private:
    2593             :     /// \brief action label slices
    2594             :     /// \details In part_tr.action_block, no information about the action label
    2595             :     /// is actually stored with the transitions, to save memory.  Entry l of
    2596             :     /// this array contains a pointer to the first entry in
    2597             :     /// part_tr.action_block with label l.
    2598             :     ///
    2599             :     /// During initialisation, entry l of this array contains a counter to
    2600             :     /// indicate how many non-inert transitions with action label l have been
    2601             :     /// found.
    2602             :     bisim_gjkw::fixed_vector<iterator_or_counter<action_block_iter_t> >
    2603             :                                                                   action_label;
    2604             : 
    2605             :     /// \brief true iff branching (not strong) bisimulation has been requested
    2606             :     bool const branching;
    2607             : 
    2608             :     /// \brief true iff divergence-preserving branching bisimulation has been
    2609             :     /// requested
    2610             :     /// \details Note that this field must be false if strong bisimulation has
    2611             :     /// been requested.  There is no such thing as divergence-preserving strong
    2612             :     /// bisimulation.
    2613             :     bool const preserve_divergence;
    2614             :                                                                                 #ifndef NDEBUG
    2615             :                                                                                     friend class pred_entry;
    2616             :                                                                                     friend class bunch_t;
    2617             :                                                                                 #endif
    2618             :   public:
    2619             :     /// \brief constructor
    2620             :     /// \details The constructor constructs the data structures and immediately
    2621             :     /// calculates the partition corresponding with the bisimulation quotient.
    2622             :     /// It destroys the transitions on the LTS (to save memory) but does not
    2623             :     /// adapt the LTS to represent the quotient's transitions.
    2624             :     /// \param new_aut                 LTS that needs to be reduced
    2625             :     /// \param new_branching           If true branching bisimulation is used,
    2626             :     ///                                otherwise strong bisimulation is
    2627             :     ///                                applied.
    2628             :     /// \param new_preserve_divergence If true and branching is true, preserve
    2629             :     ///                                tau loops on states.
    2630          52 :     bisim_partitioner_dnj(LTS_TYPE& new_aut, bool new_branching = false,
    2631             :                                           bool new_preserve_divergence = false)
    2632             :       : aut(new_aut),
    2633             :         part_st(new_aut.num_states()),
    2634             :         part_tr(new_aut.num_transitions(), new_aut.num_action_labels(),
    2635          52 :                                                  part_st.state_info.end() - 1),
    2636             :         action_label(new_aut.num_action_labels()),
    2637             :         branching(new_branching),
    2638         104 :         preserve_divergence(new_preserve_divergence)
    2639          52 :     {                                                                           assert(branching || !preserve_divergence);
    2640          52 :       create_initial_partition();                                               ONLY_IF_DEBUG( part_tr.action_block_orig_inert_begin =
    2641             :                                                                                                                             part_tr.action_block_inert_begin; )
    2642          52 :       refine_partition_until_it_becomes_stable();
    2643          52 :     }
    2644             : 
    2645             : 
    2646             :     /// \brief Calculate the number of equivalence classes
    2647             :     /// \details The number of equivalence classes (which is valid after the
    2648             :     /// partition has been constructed) is equal to the number of states in the
    2649             :     /// bisimulation quotient.
    2650          50 :     state_type num_eq_classes() const
    2651             :     {
    2652          50 :         return part_st.nr_of_blocks;
    2653             :     }
    2654             : 
    2655             : 
    2656             :     /// \brief Get the equivalence class of a state
    2657             :     /// \details After running the minimisation algorithm, this function
    2658             :     /// produces the number of the equivalence class of a state.  This number
    2659             :     /// is the same as the number of the state in the minimised LTS to which
    2660             :     /// the original state is mapped.
    2661             :     /// \param s state whose equivalence class needs to be found
    2662             :     /// \returns sequence number of the equivalence class of state s
    2663          50 :     state_type get_eq_class(state_type s) const
    2664             :     {
    2665          50 :         return part_st.block(s)->seqnr;
    2666             :     }
    2667             : 
    2668             : 
    2669             :     /// \brief Adapt the LTS after minimisation
    2670             :     /// \details After the efficient branching bisimulation minimisation, the
    2671             :     /// information about the quotient LTS is only stored in the partition data
    2672             :     /// structure of the partitioner object.  This function exports the
    2673             :     /// information back to the LTS by adapting its states and transitions:  it
    2674             :     /// updates the number of states and adds those transitions that are
    2675             :     /// mandated by the partition data structure.  If desired, it also creates
    2676             :     /// a vector containing an arbritrary (example) original state per
    2677             :     /// equivalence class.
    2678             :     ///
    2679             :     /// The main parameter and return value are implicit with this function: a
    2680             :     /// reference to the LTS was stored in the object by the constructor.
    2681             :     /// \param[out] arbitrary_state_per_block    If this pointer is != nullptr,
    2682             :     ///                                the function fills the vector with, per
    2683             :     ///                                equivalence class, the number of an
    2684             :     ///                                arbitrary original state in the class.
    2685          50 :     void finalize_minimized_LTS(std::vector<std::size_t>* const
    2686             :                                                      arbitrary_state_per_block)
    2687             :     {
    2688          50 :         if (nullptr != arbitrary_state_per_block)
    2689             :         {
    2690           0 :             arbitrary_state_per_block->resize(num_eq_classes());
    2691             :                                                                                 #ifndef NDEBUG
    2692           0 :                                                                                     arbitrary_state_per_block->assign(num_eq_classes(), (state_type) -1);
    2693             :                                                                                 #endif
    2694             :             // for all blocks
    2695           0 :             permutation_const_iter_t s_iter(part_st.permutation.cbegin());
    2696           0 :             do
    2697             :             {
    2698           0 :                 const block_t* const B(s_iter->st->block);                      assert(0 <= B->seqnr);  assert(B->seqnr < arbitrary_state_per_block->size());
    2699           0 :                                                                                 assert((state_type) -1 == (*arbitrary_state_per_block)[B->seqnr]);
    2700           0 :                 (*arbitrary_state_per_block)[B->seqnr] =
    2701           0 :                                       s_iter->st - part_st.state_info.cbegin();
    2702           0 :                 s_iter = B->end;
    2703             :             }
    2704           0 :             while (s_iter < part_st.permutation.cend());
    2705             :         }
    2706             : 
    2707             :         // The labels have already been stored in sort_key_and_label.label by
    2708             :         // refine_partition_until_it_becomes_stable().
    2709             : 
    2710             :         // for all blocks
    2711             :         {
    2712          50 :             permutation_const_iter_t s_iter(part_st.permutation.cbegin());
    2713         496 :             do
    2714             :             {
    2715         248 :                 const block_t* const B(s_iter->st->block);
    2716             :                 // for all block_bunch-slices of the block
    2717         612 :                 for (const block_bunch_slice_t& block_bunch :
    2718             :                                                          B->stable_block_bunch)
    2719         364 :                 {                                                               assert(block_bunch.is_stable());  assert(!block_bunch.empty());
    2720         364 :                     pred_const_iter_t const pred(block_bunch.end[-1].pred);     assert(pred->source->block == B);
    2721         364 :                     /* add a transition from the source block to the goal    */ assert(pred->action_block->succ()->block_bunch->pred == pred);
    2722         364 :                     /* block with the indicated label.                       */ assert(&*pred->action_block->succ()->block_bunch->slice() == &block_bunch);
    2723             :                     label_type label(
    2724         364 :                                 block_bunch.bunch()->sort_key_and_label.label); assert(0 <= label);  assert(label < action_label.size());
    2725         364 :                     aut.add_transition(transition(B->seqnr, label,
    2726             :                                                   pred->target->block->seqnr));
    2727             :                 }
    2728         248 :                 s_iter = B->end;
    2729             :             }
    2730         496 :             while (s_iter < part_st.permutation.cend());
    2731             :         }
    2732             : 
    2733             :         // Merge the states, by setting the state labels of each state to the
    2734             :         // concatenation of the state labels of its equivalence class.
    2735             : 
    2736          50 :         if (aut.has_state_info())   /* If there are no state labels
    2737             :                                                     this step can be ignored */
    2738             :         {
    2739             :             /* Create a vector for the new labels */
    2740             :             bisim_gjkw::fixed_vector<typename LTS_TYPE::state_label_t>
    2741           0 :                                                   new_labels(num_eq_classes());
    2742             : 
    2743           0 :             state_type i(aut.num_states());                                     assert(0 < i);
    2744           0 :             do
    2745             :             {
    2746           0 :                 --i;
    2747           0 :                 const state_type new_index(get_eq_class(i));
    2748           0 :                 new_labels[new_index]=aut.state_label(i)+new_labels[new_index];
    2749             :             }
    2750             :             while (0 < i);
    2751             : 
    2752           0 :             aut.set_num_states(num_eq_classes());
    2753           0 :             i = 0;                                                              assert(i < num_eq_classes());
    2754           0 :             do
    2755             :             {
    2756           0 :                 aut.set_state_label(i, new_labels[i]);
    2757             :             }
    2758           0 :             while (++i < num_eq_classes());
    2759             :         }
    2760             :         else
    2761             :         {
    2762          50 :             aut.set_num_states(num_eq_classes());
    2763             :         }
    2764             : 
    2765          50 :         aut.set_initial_state(get_eq_class(aut.initial_state()));
    2766          50 :     }
    2767             : 
    2768             : 
    2769             :     /// \brief Check whether two states are in the same equivalence class.
    2770             :     /// \param s first state that needs to be compared.
    2771             :     /// \param t second state that needs to be compared.
    2772             :     /// \returns true iff the two states are in the same equivalence class.
    2773           2 :     bool in_same_class(state_type s, state_type t) const
    2774             :     {
    2775           2 :         return part_st.block(s) == part_st.block(t);
    2776             :     }
    2777             :   private:
    2778             : 
    2779             :     /*--------------------------- main algorithm ----------------------------*/
    2780             : 
    2781             :     /// \brief Create a partition satisfying the main invariant
    2782             :     /// \details Before the actual bisimulation minimisation can start, this
    2783             :     /// function needs to be called to create a partition that satisfies the
    2784             :     /// main invariant of the efficient O(m log n) branching bisimulation
    2785             :     /// minimisation.
    2786             :     ///
    2787             :     /// It puts all non-inert transitions into a single bunch, containing one
    2788             :     /// action_block-slice for each action label.  It creates a single block
    2789             :     /// (or possibly two, if there are states that never will do any visible
    2790             :     /// action).  As a side effect, it deletes all transitions from the LTS
    2791             :     /// that is stored with the partitioner;  information about the transitions
    2792             :     /// is kept in data structures that are suitable for the efficient
    2793             :     /// algorithm.
    2794             :     ///
    2795             :     /// For divergence-preserving branching bisimulation, we only need to treat
    2796             :     /// tau-self-loops as non-inert transitions.  In other texts, this is
    2797             :     /// sometimes described as temporarily renaming the tau-self-loops to
    2798             :     /// self-loops with a special label.  However, as there are no other
    2799             :     /// non-inert tau transitions, we can simply put them in their own
    2800             :     /// action_block-slice, separate from the inert tau transitions.  (It would
    2801             :     /// be an error to mix the inert transitions with the self-loops in the
    2802             :     /// same slice.)
    2803          52 :     void create_initial_partition()
    2804             :     {
    2805          52 :         mCRL2log(log::verbose, "bisim_dnj") << "Strictly O(m log n) "
    2806           0 :              << (branching ? (preserve_divergence
    2807             :                                            ? "divergence-preserving branching "
    2808             :                                            : "branching ")
    2809             :                            : "")
    2810           0 :              << "bisimulation partitioner created for " << part_st.state_size()
    2811           0 :              << " states and " << aut.num_transitions() << " transitions\n";
    2812             : 
    2813             :         // create one block for all states
    2814             : 
    2815          52 :         block_t* B(new block_t(part_st.permutation.begin(),
    2816          52 :                            part_st.permutation.end(), part_st.nr_of_blocks++));
    2817             : 
    2818             :         // Iterate over the transitions to count how to order them in
    2819             :         // part_trans_t
    2820             : 
    2821             :         // counters for the non-inert outgoing and incoming transitions per
    2822             :         // state are provided in part_st.state_info.  These counters have been
    2823             :         // initialised to zero in the constructor of part_state_t.
    2824             :         // counters for the non-inert transition per label are stored in
    2825             :         // action_label.
    2826          52 :                                                                                 assert(action_label.size() == aut.num_action_labels());
    2827             :         // counter for the total number of inert transitions:
    2828          52 :         trans_type inert_transitions(0);
    2829         652 :         for (const transition& t: aut.get_transitions())
    2830             :         {
    2831         942 :             if (branching&&aut.is_tau(aut.apply_hidden_label_map(t.label()))&&  ((
    2832         184 :                                                             t.from() != t.to())   || (assert(preserve_divergence), false)))
    2833             :             {
    2834             :                 // The transition is inert.
    2835         158 :                 ++part_st.state_info[t.from()].succ_inert.count;
    2836         158 :                 ++inert_transitions;
    2837             : 
    2838             :                 // The source state should become non-bottom:
    2839         158 :                 if (part_st.state_info[t.from()].pos < B->nonbottom_begin)
    2840             :                 {
    2841         140 :                     std::swap(*part_st.state_info[t.from()].pos,
    2842             :                                                         *--B->nonbottom_begin);
    2843             :                     // we do not yet update the marked_bottom_begin pointer
    2844             :                 }
    2845             :             }
    2846             :             else
    2847             :             {
    2848             :                 // The transition is non-inert.  (It may be a self-loop).
    2849         442 :                 ++part_st.state_info[t.from()].current_out_slice.count;
    2850             : 
    2851         442 :                 ++action_label[aut.apply_hidden_label_map(t.label())].count;
    2852             :             }
    2853         600 :             ++part_st.state_info[t.to()].pred_inert.count;
    2854             :         }
    2855             :         // Now we update the marked_bottom_begin pointer:
    2856          52 :         B->marked_bottom_begin = B->nonbottom_begin;
    2857             : 
    2858             :         // set the pointers to transition slices in the state info entries
    2859             : 
    2860             :         // We set them all to the end of the respective slice here.  Then, with
    2861             :         // every transition, the pointer will be reduced by one, so that after
    2862             :         // placing all transitions it will point to the beginning of the slice.
    2863             : 
    2864          52 :         pred_iter_t next_pred_begin(part_tr.pred.begin() + 1);
    2865          52 :         succ_iter_t next_succ_begin(part_tr.succ.begin() + 1);
    2866          52 :         state_info_iter_t state_iter(part_st.state_info.begin());               assert(state_iter < part_st.state_info.end() - 1);
    2867         918 :         do
    2868             :         {
    2869         459 :             state_iter->block = B;
    2870             : 
    2871         459 :             state_iter->not_.used_pred = next_pred_begin;
    2872         459 :             if (0 == state_iter->pred_inert.count)
    2873             :             {
    2874             :                 // This state has no incoming transitions.
    2875             :                 // so we can convert this state's not_ pointer to not_.blue.
    2876             :                 // (Actually, it would probably be more efficient to do this
    2877             :                 // in a separate loop, as the conversion is mostly trivial,
    2878             :                 // but the compiler cannot optimize away the whole loop because
    2879             :                 // it does not detect guaranteed termination.)
    2880          43 :                 state_iter->not_.convert_to_succ_iter_t();
    2881             :             }
    2882         459 :             next_pred_begin += state_iter->pred_inert.count;
    2883         459 :             state_iter->pred_inert.convert_to_iterator(next_pred_begin);
    2884             : 
    2885             :                 // create slice descriptors in part_tr.succ for each state with
    2886             :                 // outgoing transitions.
    2887         459 :             state_iter->current_out_slice.convert_to_iterator(next_succ_begin +
    2888             :                                           state_iter->current_out_slice.count);
    2889         459 :             if (next_succ_begin < state_iter->current_out_slice.begin)
    2890             :             {
    2891         322 :                 next_succ_begin->begin_or_before_end.set(
    2892         322 :                                       state_iter->current_out_slice.begin - 1);
    2893         322 :                 succ_iter_t out_slice_begin(next_succ_begin);
    2894         562 :                 while (++next_succ_begin < state_iter->current_out_slice.begin)
    2895             :                 {
    2896         120 :                     next_succ_begin->begin_or_before_end.set(out_slice_begin);  // mCRL2complexity(next_succ_begin->block_bunch->pred, ...) -- subsumed in the
    2897             :                 }                                                               // call below
    2898             : 
    2899             :                 // Line 1.3: Mark all states with a visible transition
    2900         322 :                 B->mark(state_iter->pos);
    2901             :             }
    2902         459 :             state_iter->succ_inert.convert_to_iterator(next_succ_begin +
    2903             :                                                  state_iter->succ_inert.count);
    2904             :                                                                                 #ifndef NDEBUG
    2905         775 :                                                                                     while (next_succ_begin < state_iter->succ_inert.begin)
    2906         158 :                                                                                     {   assert(next_succ_begin->begin_or_before_end.is_null());
    2907         158 :                                                                                         ++next_succ_begin;
    2908             :                                                                                     }
    2909             :                                                                                 #endif
    2910         459 :             next_succ_begin = state_iter->succ_inert.begin;                     // mCRL2complexity(*state_iter, ...) -- subsumed in the call at the end
    2911             :         }
    2912         918 :         while (++state_iter < part_st.state_info.end() - 1);
    2913             : 
    2914             :         // Line 1.4: Organise the visible transitions in action block-slices
    2915             :         //           and one block bunch-slice
    2916             : 
    2917             :         // create a single bunch containing all non-inert transitions
    2918             : 
    2919          52 :         part_tr.action_block_inert_begin =
    2920         104 :                                 part_tr.action_block.end() - inert_transitions;
    2921          52 :         part_tr.block_bunch_inert_begin =
    2922         104 :                                  part_tr.block_bunch.end() - inert_transitions;
    2923             : 
    2924          52 :         bunch_t* bunch(nullptr);
    2925             : 
    2926             :         // create a single block_bunch entry for all non-inert transitions
    2927          52 :         if (part_tr.action_block.begin() < part_tr.action_block_inert_begin)
    2928             :         {
    2929         102 :             bunch = new bunch_t(part_tr.action_block.begin(),
    2930             :                                  part_tr.action_block_inert_begin,
    2931          51 :                                  TRANS_TYPE_MAX - part_tr.action_block.size());
    2932          51 :             B->stable_block_bunch.emplace_front(
    2933             :                                  part_tr.block_bunch_inert_begin, bunch, true);
    2934             :         }
    2935             : 
    2936             :         // create slice descriptors in part_tr.action_block for each label
    2937             : 
    2938             :         // The action_block array shall have the tau transitions at the end:
    2939             :         // first the non-inert tau transitions (during initialisation, that are
    2940             :         // only the tau self-loops), then the tau transitions that have become
    2941             :         // non-inert and finally the inert transitions.
    2942             :         // Transitions with other labels are placed from beginning to end.
    2943             :         // Every such transition block except the last one ends with a dummy
    2944          52 :         /* entry.  If there are transition labels without transitions,       */ assert(part_tr.action_block.size() ==
    2945             :         /* multiple dummy entries will be placed side-by-side.               */                               aut.num_transitions() + action_label.size() - 1);
    2946             :         action_block_iter_t next_action_label_begin(
    2947          52 :                                                  part_tr.action_block.begin());
    2948          52 :         label_type num_labels_with_transitions(0);
    2949          52 :         trans_type const n_square(part_st.state_size() * part_st.state_size()); ONLY_IF_DEBUG( trans_type max_transitions = n_square; )
    2950          52 :         label_type label(action_label.size());                                  assert(0 < label);
    2951         597 :         do
    2952             :         {
    2953         161 :             --label;
    2954         161 :             if (0 < action_label[label].count)
    2955             :             {
    2956         130 :                 if (++num_labels_with_transitions == 2)
    2957             :                 {
    2958             :                     // This is the second action_block-slice, so the bunch is
    2959             :                     // not yet marked as nontrivial but it should be.
    2960          36 :                     part_tr.make_nontrivial(bunch);
    2961             :                 }
    2962         130 :                 if (n_square < action_label[label].count)
    2963             :                 {
    2964           0 :                     mCRL2log(log::warning) << "There are "
    2965           0 :                         << action_label[label].count << ' '
    2966           0 :                         << pp(aut.action_label(label)) << "-transitions.  "
    2967           0 :                         "This is more than n^2 (= " << n_square << "). It is "
    2968             :                         "not guaranteed that branching bisimulation "
    2969           0 :                         "minimisation runs in time O(m log n).\n";              ONLY_IF_DEBUG(  if (max_transitions < action_label[label].count)
    2970             :                                                                                                     {   max_transitions = action_label[label].count;   }  )
    2971             :                 }
    2972             :                 // initialise begin_or_before_end pointers for this
    2973             :                 // action_block-slice
    2974         130 :                 action_label[label].convert_to_iterator(
    2975         130 :                           next_action_label_begin + action_label[label].count);
    2976         130 :                 next_action_label_begin->begin_or_before_end.set(
    2977         130 :                                                 action_label[label].begin - 1);
    2978             :                 action_block_iter_t action_block_slice_begin(
    2979         130 :                                                       next_action_label_begin);
    2980         754 :                 while (++next_action_label_begin < action_label[label].begin)
    2981             :                 {
    2982         312 :                     next_action_label_begin->begin_or_before_end.set(
    2983             :                                                      action_block_slice_begin); // mCRL2complexity(next_action_label_begin->succ()->block_bunch->pred, ...) --
    2984             :                 }                                                               // subsumed in the call at the end
    2985             :             }
    2986             :             else
    2987             :             {
    2988          31 :                 action_label[label].convert_to_iterator(
    2989             :                                                       next_action_label_begin);
    2990          31 :                 if (0 != label && aut.num_transitions() < action_label.size())
    2991             :                 {
    2992           0 :                     mCRL2log(log::warning) << "Action label "
    2993           0 :                         << pp(aut.action_label(label)) << " has no "
    2994             :                         "transitions, and the number of action labels exceeds "
    2995             :                         "the number of transitions. It is not guaranteed that "
    2996             :                         "branching bisimulation minimisation runs in time "
    2997             :                         "O(m log n).\n";
    2998             :                 }
    2999             :             }
    3000             :         }
    3001         109 :         while (0 < label && (/* insert a dummy entry                         */ assert(next_action_label_begin < part_tr.action_block_inert_begin),
    3002         109 :                                                                                 assert(next_action_label_begin->succ.is_null()),
    3003         109 :                                                                                 assert(next_action_label_begin->begin_or_before_end.is_null()),
    3004          52 :                                              ++next_action_label_begin, true)); assert(next_action_label_begin == part_tr.action_block_inert_begin);
    3005             : 
    3006          52 :         /* distribute the transitions over the data structures               */ ONLY_IF_DEBUG( bisim_gjkw::check_complexity::init(2 * max_transitions); )
    3007             : 
    3008          52 :         block_bunch_iter_t next_block_bunch(part_tr.block_bunch.begin() + 1);   assert(next_block_bunch == part_tr.block_bunch.cbegin() + 1);
    3009         652 :         for (const transition& t: aut.get_transitions())
    3010         600 :         {                                                                       assert(part_st.state_info[t.from()].block == B);
    3011         600 :             succ_iter_t succ_pos;
    3012         600 :             block_bunch_iter_t block_bunch_pos;
    3013         600 :             pred_iter_t pred_pos;
    3014         600 :             action_block_iter_t action_block_pos;
    3015             : 
    3016         942 :             if (branching&&aut.is_tau(aut.apply_hidden_label_map(t.label()))&&  ((
    3017         184 :                                                             t.from() != t.to())   || (assert(preserve_divergence), false)))
    3018             :             {
    3019             :                 // It is a (normal) inert transition: place near the end of the
    3020             :                 // respective pred/succ slices, just before the other inert
    3021             :                 // transitions.
    3022         158 :                 succ_pos = --part_st.state_info[t.from()].succ_inert.begin;     assert(succ_pos->begin_or_before_end.is_null());
    3023         158 :                 block_bunch_pos = part_tr.block_bunch.end()-inert_transitions;  assert(block_bunch_pos >= part_tr.block_bunch_inert_begin);
    3024         158 :                 pred_pos = --part_st.state_info[t.to()].pred_inert.begin;       assert(block_bunch_pos->slice.is_null());
    3025         158 :                 action_block_pos=part_tr.action_block.end()-inert_transitions;  assert(action_block_pos >= part_tr.action_block_inert_begin);
    3026         158 :                 --inert_transitions;                                            assert(action_block_pos->begin_or_before_end.is_null());
    3027             :             }
    3028             :             else
    3029             :             {
    3030             :                 // It is a non-inert transition (possibly a self-loop): place
    3031             :                 // at the end of the respective succ slice and at the beginning
    3032             :                 // of the respective pred slice.
    3033         442 :                 succ_pos =
    3034         442 :                         --part_st.state_info[t.from()].current_out_slice.begin; assert(succ_pos->begin_or_before_end() <= succ_pos ||
    3035             :                                                                                            succ_pos->begin_or_before_end()->begin_or_before_end() == succ_pos);
    3036         442 :                 block_bunch_pos = next_block_bunch++;                           assert(block_bunch_pos < part_tr.block_bunch_inert_begin);
    3037         442 :                 pred_pos = part_st.state_info[t.to()].not_.used_pred++;
    3038         442 :                 action_block_pos =
    3039         884 :                    --action_label[aut.apply_hidden_label_map(t.label())].begin; assert(action_block_pos->begin_or_before_end() <= action_block_pos ||
    3040             :                                                                                                 action_block_pos->begin_or_before_end()->
    3041             :                                                                                                                     begin_or_before_end() == action_block_pos);
    3042         442 :                 block_bunch_pos->slice.set(B->stable_block_bunch.begin());      assert(action_block_pos < part_tr.action_block_inert_begin);
    3043             :             }
    3044         600 :             succ_pos->block_bunch = block_bunch_pos;
    3045         600 :             block_bunch_pos->pred = pred_pos;
    3046         600 :             pred_pos->action_block = action_block_pos;
    3047         600 :             pred_pos->source = part_st.state_info.begin() + t.from();
    3048         600 :             pred_pos->target = part_st.state_info.begin() + t.to();
    3049         600 :             action_block_pos->succ.set(succ_pos);
    3050             : 
    3051         600 :             if (part_st.state_info[t.to()].not_.used_pred >=
    3052             :                                    part_st.state_info[t.to()].pred_inert.begin)
    3053             :             {
    3054         416 :                 /* the last transition to this target state has been handled,*/ assert(part_st.state_info[t.to()].not_.used_pred ==
    3055             :                 /* so we can convert this state's not_ pointer to not_.blue. */                                   part_st.state_info[t.to()].pred_inert.begin);
    3056             :                 // (Actually, it would probably be more efficient to do this
    3057             :                 // in a separate loop, as the conversion is mostly trivial,
    3058             :                 // but the compiler cannot optimize away the whole loop because
    3059             :                 // it does not detect guaranteed termination.)
    3060         416 :                 part_st.state_info[t.to()].not_.convert_to_succ_iter_t();
    3061             :             }                                                                   // mCRL2complexity(pred_pos, ...) -- subsumed in the call at the end
    3062          52 :         }                                                                       assert(0 == inert_transitions);
    3063          52 :         /* delete transitions already -- they are no longer needed.  We will */ assert(next_block_bunch == part_tr.block_bunch_inert_begin);
    3064             :         // add new transitions at the end of minimisation.
    3065          52 :         aut.clear_transitions();
    3066             : 
    3067          52 :         if (nullptr != bunch)
    3068          51 :         {                                                                       assert(!bunch->begin->succ.is_null());
    3069         111 :             while (bunch->end[-1].succ.is_null())
    3070             :             {
    3071          30 :                 --bunch->end;                                                   assert(bunch->begin < bunch->end);
    3072             :             }
    3073             :         }
    3074          52 :                                                                                 mCRL2complexity(B, add_work(bisim_gjkw::check_complexity::
    3075             :         /* Line 1.5: if there are marked states then                         */                            create_initial_partition, 1U), part_st.permutation);
    3076          52 :         if (0 < B->marked_size())
    3077          51 :         {                                                                       ONLY_IF_DEBUG( part_st.print_part();  part_tr.print_trans(*this); )
    3078             :             // Line 1.6: refine(all states, all visible transitions,
    3079             :             //                  extend from marked states)
    3080          51 :             B = refine(B,
    3081          51 :                     /* splitter block_bunch */ B->stable_block_bunch.begin(),
    3082             :                            extend_from_marked_states_for_init_and_postprocess);
    3083             :             // Line 1.7: Unmark all states
    3084             :                 // We can ignore possible new non-inert transitions, as every
    3085             :                 // red bottom state already has a transition in bunch.
    3086          51 :             B->marked_nonbottom_begin = B->end;
    3087          51 :             B->marked_bottom_begin = B->nonbottom_begin;
    3088             :         // Line 1.8: end if
    3089             :         }
    3090          52 :     }
    3091             :                                                                                 #ifndef NDEBUG
    3092             :                                                                                     /// \brief assert that the data structure is consistent and stable
    3093             :                                                                                     /// \details The data structure is tested against a large number of
    3094             :                                                                                     /// assertions to ensure that everything is consistent, e. g. pointers that
    3095             :                                                                                     /// should point to successors of state s actually point to a transition
    3096             :                                                                                     /// that starts in s.
    3097             :                                                                                     ///
    3098             :                                                                                     /// Additionally, it is asserted that the partition is stable. i. e. every
    3099             :                                                                                     /// bottom state in every block can reach exactly every bunch in the list
    3100             :                                                                                     /// of bunches that should be reachable from it, and every nonbottom state
    3101             :                                                                                     /// can reach a subset of them.
    3102         278 :                                                                                     void assert_stability() const
    3103             :                                                                                     {
    3104         278 :                                                                                         part_st.assert_consistency(branching);
    3105             : 
    3106         278 :                                                                                         assert(part_tr.succ.size() == part_tr.block_bunch.size() + 1);
    3107         278 :                                                                                         assert(part_tr.pred.size() == part_tr.block_bunch.size() + 1);
    3108         278 :                                                                                         assert(part_tr.action_block.size() ==
    3109             :                                                                                                          part_tr.block_bunch.size() + action_label.size() - 2);
    3110         278 :                                                                                         if (part_tr.block_bunch.empty())  return;
    3111             : 
    3112         278 :                                                                                         assert(part_tr.unstable_block_bunch.empty());
    3113             :                                                                                         /* for (const block_bunch_slice_t& block_bunch :
    3114             :                                                                                                                                   part_tr.unstable_block_bunch)
    3115             :                                                                                         {
    3116             :                                                                                             assert(!block_bunch.is_stable());
    3117             :                                                                                         } */
    3118             : 
    3119             :                                                                                         // for all blocks
    3120         278 :                                                                                         permutation_const_iter_t perm_iter(part_st.permutation.cbegin());
    3121         278 :                                                                                         assert(perm_iter < part_st.permutation.cend());
    3122        4796 :                                                                                         do
    3123             :                                                                                         {
    3124        2398 :                                                                                             const block_t* const block(perm_iter->st->block);
    3125             :                                                                                             unsigned const max_block(bisim_gjkw::check_complexity::log_n -
    3126        2398 :                                                                                                            bisim_gjkw::check_complexity::ilog2(block->size()));
    3127             :                                                                                             // iterators have no predefined hash, so we store pointers:
    3128             :                                                                                             std::unordered_set<const block_bunch_slice_t*>
    3129        4796 :                                                                                                                                          block_bunch_check_set;
    3130        2398 :                                                                                             block_bunch_check_set.reserve(block->stable_block_bunch.size());
    3131             : 
    3132             :                                                                                             // for all stable block_bunch-slices of the block
    3133        6051 :                                                                                             for (const block_bunch_slice_t& block_bunch :
    3134             :                                                                                                                                      block->stable_block_bunch)
    3135             :                                                                                             {
    3136        3653 :                                                                                                 assert(block_bunch.source_block() == block);
    3137        3653 :                                                                                                 assert(block_bunch.is_stable());
    3138        3653 :                                                                                                 block_bunch_check_set.insert(&block_bunch);
    3139        3653 :                                                                                                 mCRL2complexity(&block_bunch, no_temporary_work(
    3140             :                                                                                                          block_bunch.bunch()->max_work_counter(*this)), *this);
    3141             :                                                                                             }
    3142             : 
    3143             :                                                                                             // for all states in the block
    3144        6492 :                                                                                             do
    3145             :                                                                                             {
    3146        6492 :                                                                                                 state_info_const_iter_t const state(perm_iter->st);
    3147        6492 :                                                                                                 succ_const_iter_t out_slice_end(state->succ_inert.begin);
    3148        6492 :                                                                                                 trans_type block_bunch_count(0);
    3149             :                                                                                                 // for all out-slices of the state
    3150        6492 :                                                                                                 assert(state !=
    3151             :                                                                                                              part_tr.succ.cbegin()->block_bunch->pred->source);
    3152        6492 :                                                                                                 if (state == out_slice_end[-1].block_bunch->pred->source)
    3153             :                                                                                                 {
    3154             :                                                                                                     const bunch_t* bunch;
    3155       12546 :                                                                                                     do
    3156             :                                                                                                     {
    3157             :                                                                                                         block_bunch_slice_const_iter_t block_bunch_slice(
    3158        7425 :                                                                                                                        out_slice_end[-1].block_bunch->slice());
    3159        7425 :                                                                                                         bunch = block_bunch_slice->bunch();
    3160        7425 :                                                                                                         assert(block == block_bunch_slice->source_block());
    3161        7425 :                                                                                                         if (block_bunch_slice->is_stable())
    3162             :                                                                                                         {
    3163        7425 :                                                                                                             assert(1 == block_bunch_check_set.count(
    3164             :                                                                                                                                          &*block_bunch_slice));
    3165        7425 :                                                                                                             ++block_bunch_count;
    3166             :                                                                                                         }
    3167           0 :                                                                                                         else  assert(0); // i. e. all block_bunch-slices should
    3168             :                                                                                                                          // be stable
    3169             :                                                                                                         unsigned const max_bunch(
    3170        7425 :                                                                                                                                bunch->max_work_counter(*this));
    3171             :                                                                                                         succ_const_iter_t const out_slice_begin(
    3172        7425 :                                                                                                                       out_slice_end[-1].begin_or_before_end());
    3173        7425 :                                                                                                         assert(out_slice_begin < out_slice_end);
    3174        7425 :                                                                                                         assert(out_slice_begin->begin_or_before_end() + 1 ==
    3175             :                                                                                                                                                 out_slice_end);
    3176             : 
    3177             :                                                                                                         // for all transitions in the out-slice
    3178       11629 :                                                                                                         do
    3179             :                                                                                                         {
    3180        8476 :                                                                                                             --out_slice_end;
    3181        8476 :                                                                                                             assert(bunch->begin <=
    3182             :                                                                                                                out_slice_end->block_bunch->pred->action_block);
    3183        8476 :                                                                                                             assert(out_slice_end->block_bunch->pred->
    3184             :                                                                                                                                     action_block < bunch->end);
    3185        8476 :                                                                                                             assert(block_bunch_slice ==
    3186             :                                                                                                                           out_slice_end->block_bunch->slice());
    3187        8476 :                                                                                                             if (out_slice_end->block_bunch + 1 !=
    3188             :                                                                                                                                         block_bunch_slice->end)
    3189             :                                                                                                             {
    3190        4823 :                                                                                                                 assert(out_slice_end->block_bunch + 1 <
    3191             :                                                                                                                                        block_bunch_slice->end);
    3192        4823 :                                                                                                                 assert(block_bunch_slice ==
    3193             :                                                                                                                         out_slice_end->block_bunch[1].slice());
    3194             :                                                                                                             }
    3195        8476 :                                                                                                             mCRL2complexity(out_slice_end->block_bunch->pred,
    3196             :                                                                                                                 no_temporary_work(max_block, bisim_gjkw::
    3197             :                                                                                                                     check_complexity::log_n - bisim_gjkw::
    3198             :                                                                                                                     check_complexity::ilog2(out_slice_end->
    3199             :                                                                                                                     block_bunch->pred->target->block->size()),
    3200             :                                                                                                                     max_bunch,
    3201             :                                                                                                                     perm_iter < block->nonbottom_begin),*this);
    3202             :                                                                                                         }
    3203        8476 :                                                                                                         while (out_slice_begin < out_slice_end &&
    3204        1051 :                                                                                                            (assert(out_slice_begin ==
    3205             :                                                                                                                       out_slice_end->begin_or_before_end()),
    3206        1051 :                                                                                                             assert(out_slice_end !=
    3207             :                                                                                                                             state->current_out_slice.begin),
    3208             :                                                                                                                                                         true));
    3209             :                                                                                                     }
    3210        7425 :                                                                                                     while (state==out_slice_end[-1].block_bunch->pred->source&&
    3211        3414 :                                                                                                         (assert(out_slice_end[-1].bunch()->sort_key_and_label.
    3212             :                                                                                                                 sort_key <= bunch->end - bunch->begin +
    3213             :                                                                                                                    bunch->sort_key_and_label.sort_key), true));
    3214             :                                                                                                 }
    3215        6492 :                                                                                                 assert(out_slice_end <= state->current_out_slice.begin);
    3216        6492 :                                                                                                 if (perm_iter < block->nonbottom_begin)
    3217             :                                                                                                 {
    3218        5353 :                                                                                                     assert(block_bunch_check_set.size() == block_bunch_count);
    3219             :                                                                                                 }
    3220             :                                                                                             }
    3221        6492 :                                                                                             while (++perm_iter < block->end);
    3222             :                                                                                         }
    3223        4796 :                                                                                         while (perm_iter < part_st.permutation.cend());
    3224             : 
    3225         278 :                                                                                         assert(part_tr.action_block.cbegin() <=
    3226             :                                                                                                                              part_tr.action_block_inert_begin);
    3227         278 :                                                                                         assert(part_tr.block_bunch.cbegin() < part_tr.block_bunch_inert_begin);
    3228         278 :                                                                                         if (branching)
    3229             :                                                                                         {
    3230         137 :                                                                                             assert(part_tr.action_block_inert_begin <=
    3231             :                                                                                                                                    part_tr.action_block.end());
    3232         137 :                                                                                             assert(part_tr.block_bunch_inert_begin <=
    3233             :                                                                                                                                     part_tr.block_bunch.end());
    3234         137 :                                                                                             assert(part_tr.block_bunch.end()-part_tr.block_bunch_inert_begin ==
    3235             :                                                                                                 part_tr.action_block.end() - part_tr.action_block_inert_begin);
    3236             : 
    3237             :                                                                                             // for all inert transitions
    3238        3925 :                                                                                             for (action_block_const_iter_t action_block(
    3239         137 :                                                                                                                              part_tr.action_block_inert_begin);
    3240        2708 :                                                                                                     action_block < part_tr.action_block.cend(); ++action_block)
    3241             :                                                                                             {
    3242        1217 :                                                                                                 assert(action_block->begin_or_before_end.is_null());
    3243        1217 :                                                                                                 succ_const_iter_t const succ_iter(action_block->succ());
    3244        1217 :                                                                                                 assert(succ_iter->block_bunch->slice.is_null());
    3245             :                                                                                                 pred_const_iter_t const pred_iter(
    3246        1217 :                                                                                                                                  succ_iter->block_bunch->pred);
    3247        1217 :                                                                                                 assert(action_block == pred_iter->action_block);
    3248        1217 :                                                                                                 assert(part_tr.block_bunch_inert_begin <=
    3249             :                                                                                                                                        succ_iter->block_bunch);
    3250        1217 :                                                                                                 assert(pred_iter->source != pred_iter->target);
    3251        1217 :                                                                                                 assert(pred_iter->source->block == pred_iter->target->block);
    3252        1217 :                                                                                                 assert(pred_iter->source->succ_inert.begin <= succ_iter);
    3253        1217 :                                                                                                 assert(pred_iter->source->succ_inert.begin == succ_iter ||
    3254             :                                                                                                    succ_iter[-1].block_bunch->pred->source==pred_iter->source);
    3255        1217 :                                                                                                 assert(pred_iter->target->pred_inert.begin <= pred_iter);
    3256        1217 :                                                                                                 assert(pred_iter->target->pred_inert.begin == pred_iter ||
    3257             :                                                                                                                     pred_iter[-1].target == pred_iter->target);
    3258             :                                                                                                 unsigned const max_block(bisim_gjkw::check_complexity::log_n -
    3259        1217 :                                                                                                                     bisim_gjkw::check_complexity::ilog2(
    3260        2434 :                                                                                                                             pred_iter->target->block->size()));
    3261        1217 :                                                                                                 mCRL2complexity(pred_iter, no_temporary_work(max_block,
    3262             :                                                                                                                                  max_block, 0U, false), *this);
    3263             :                                                                                             }
    3264             :                                                                                         }
    3265             :                                                                                         else
    3266             :                                                                                         {
    3267         141 :                                                                                             assert(!preserve_divergence);
    3268         141 :                                                                                             assert(part_tr.action_block_inert_begin ==
    3269             :                                                                                                                                    part_tr.action_block.end());
    3270         141 :                                                                                             assert(part_tr.block_bunch_inert_begin==part_tr.block_bunch.end());
    3271             :                                                                                         }
    3272             :                                                                                         action_block_const_iter_t action_slice_end(
    3273         278 :                                                                                                                              part_tr.action_block_inert_begin);
    3274             :                                                                                         // for all action labels and bunches
    3275         278 :                                                                                         label_type label(0);
    3276         278 :                                                                                         assert(label < action_label.size());
    3277         278 :                                                                                         const bunch_t* previous_bunch(nullptr);
    3278        3709 :                                                                                         do
    3279             :                                                                                         {
    3280        1329 :                                                                                             assert(part_tr.action_block.cbegin() <= action_label[label].begin);
    3281        1329 :                                                                                             assert(action_label[label].begin <= action_slice_end);
    3282        1329 :                                                                                             assert(action_slice_end <= part_tr.action_block_inert_begin);
    3283             :                                                                                             // for all action_block slices
    3284        8839 :                                                                                             for (action_block_const_iter_t action_block_slice_end(
    3285        1329 :                                                                                                                                             action_slice_end);
    3286        5084 :                                                                                                           action_label[label].begin < action_block_slice_end; )
    3287             :                                                                                             {
    3288             :                                                                                                 action_block_const_iter_t const action_block_slice_begin(
    3289        3755 :                                                                                                              action_block_slice_end[-1].begin_or_before_end());
    3290        3755 :                                                                                                 assert(action_block_slice_begin < action_block_slice_end);
    3291        3755 :                                                                                                 assert(action_block_slice_end <= action_slice_end);
    3292        3755 :                                                                                                 const block_t* const target_block(action_block_slice_begin->
    3293        3755 :                                                                                                                      succ()->block_bunch->pred->target->block);
    3294        3755 :                                                                                                 const bunch_t* const bunch(action_block_slice_begin->
    3295        3755 :                                                                                                                                               succ()->bunch());
    3296        3755 :                                                                                                 if (previous_bunch != bunch)
    3297             :                                                                                                 {
    3298        2747 :                                                                                                     assert(nullptr == previous_bunch);
    3299        2747 :                                                                                                     previous_bunch = bunch;
    3300        2747 :                                                                                                     assert(bunch->end == action_block_slice_end);
    3301        2747 :                                                                                                     assert(TRANS_TYPE_MAX - part_tr.action_block.size() <=
    3302             :                                                                                                                            bunch->sort_key_and_label.sort_key);
    3303        2747 :                                                                                                     if (bunch->begin == action_block_slice_begin)
    3304             :                                                                                                     {
    3305             :                                                                                                         // Perhaps this does not always hold; sometimes, an
    3306             :                                                                                                         // action_block slice disappears but the bunch cannot
    3307             :                                                                                                         // be made trivial.
    3308        2496 :                                                                                                         assert(bunch->is_trivial());
    3309             :                                                                                                     }
    3310         251 :                                                                                                     else  assert(!bunch->is_trivial());
    3311        2747 :                                                                                                     mCRL2complexity(bunch, no_temporary_work(
    3312             :                                                                                                                        bunch->max_work_counter(*this)), *this);
    3313             :                                                                                                 }
    3314        3755 :                                                                                                 if(bunch->begin == action_block_slice_begin)
    3315             :                                                                                                 {
    3316        2747 :                                                                                                     previous_bunch = nullptr;
    3317             :                                                                                                 }
    3318        1008 :                                                                                                 else  assert(bunch->begin < action_block_slice_begin);
    3319             : 
    3320        3755 :                                                                                                 assert(action_block_slice_begin->begin_or_before_end() + 1 ==
    3321             :                                                                                                                                        action_block_slice_end);
    3322             :                                                                                                 // for all transitions in the action_block slice
    3323        3755 :                                                                                                 action_block_const_iter_t action_block(action_block_slice_end);
    3324       17918 :                                                                                                 do
    3325             :                                                                                                 {
    3326        8476 :                                                                                                     --action_block;
    3327        8476 :                                                                                                     succ_const_iter_t const succ_iter(action_block->succ());
    3328             :                                                                                                     pred_const_iter_t const pred_iter(
    3329        8476 :                                                                                                                                  succ_iter->block_bunch->pred);
    3330        8476 :                                                                                                     assert(action_block == pred_iter->action_block);
    3331        8476 :                                                                                                     assert(succ_iter->block_bunch <
    3332             :                                                                                                                               part_tr.block_bunch_inert_begin);
    3333        8476 :                                                                                                     assert(!branching || !aut.is_tau(label) ||
    3334             :                                                                                                         pred_iter->source->block != pred_iter->target->block ||
    3335             :                                                                                                                      (preserve_divergence &&
    3336             :                                                                                                                       pred_iter->source == pred_iter->target));
    3337        8476 :                                                                                                     assert(succ_iter < pred_iter->source->succ_inert.begin);
    3338        8476 :                                                                                                     assert(succ_iter+1==pred_iter->source->succ_inert.begin ||
    3339             :                                                                                                                 succ_iter[1].block_bunch->pred->source ==
    3340             :                                                                                                                                             pred_iter->source);
    3341        8476 :                                                                                                     assert(pred_iter < pred_iter->target->pred_inert.begin);
    3342        8476 :                                                                                                     assert(pred_iter+1==pred_iter->target->pred_inert.begin ||
    3343             :                                                                                                                      pred_iter[1].target == pred_iter->target);
    3344        8476 :                                                                                                     assert(target_block == pred_iter->target->block);
    3345        8476 :                                                                                                     assert(bunch == succ_iter->bunch());
    3346             :                                                                                                 }
    3347        8476 :                                                                                                 while (action_block_slice_begin < action_block &&
    3348             :                                                                                                    (// some properties only need to be checked for states that
    3349             :                                                                                                     // are not the first one:
    3350        4721 :                                                                                                     assert(action_block->begin_or_before_end() ==
    3351             :                                                                                                                              action_block_slice_begin), true));
    3352        3755 :                                                                                                 action_block_slice_end = action_block_slice_begin;
    3353             :                                                                                             }
    3354        1329 :                                                                                             if (action_slice_end < part_tr.action_block_inert_begin)
    3355             :                                                                                             {
    3356             :                                                                                                 // there is a dummy transition between action labels
    3357        1051 :                                                                                                 assert(action_slice_end->succ.is_null());
    3358        1051 :                                                                                                 assert(action_slice_end->begin_or_before_end.is_null());
    3359             :                                                                                             }
    3360             :                                                                                         }
    3361        1329 :                                                                                         while (++label < action_label.size() &&
    3362        1051 :                                                                                                  (action_slice_end = action_label[label - 1].begin - 1, true));
    3363         278 :                                                                                         assert(nullptr == previous_bunch);
    3364             :                                                                                     }
    3365             :                                                                                 #endif
    3366             :     /// \brief Run (branching) bisimulation minimisation in time O(m log n)
    3367             :     /// \details This function assumes that the partitioner object stores a LTS
    3368             :     /// with a partition satisfying the invariant:
    3369             :     ///
    3370             :     /// If a state contains a transition in a bunch, then every bottom state in
    3371             :     /// the same block contains a transition in that bunch.
    3372             :     ///
    3373             :     /// The function runs the efficient O(m log n) algorithm for branching
    3374             :     /// bisimulation minimisation on the LTS that has been stored in the
    3375             :     /// partitioner:  As long as there are nontrivial bunches, it selects one,
    3376             :     /// subdivides it into two bunches and then stabilises the partition for
    3377             :     /// these bunches.  As a result, the partition stored in the partitioner
    3378             :     /// will become stable.
    3379             :     ///
    3380             :     /// Parameters and return value are implicit with this function:  the LTS,
    3381             :     /// the partition and the flags of the bisimulation algorithm are all
    3382             :     /// stored in the partitioner object.
    3383         278 :     void refine_partition_until_it_becomes_stable()
    3384             :     {
    3385             :         // Line 1.9: while there is a non-trivial bunch do
    3386         226 :         for (;;)
    3387             :         {                                                                       // mCRL2complexity(...) -- this loop will be ascribed to (the transitions in)
    3388             :                                                                                 // the new bunch below.
    3389         278 :             /*----------------------- find a splitter -----------------------*/ ONLY_IF_DEBUG( part_st.print_part();  part_tr.print_trans(*this);
    3390             :                                                                                                                                           assert_stability(); )
    3391             :             // Line 1.10: Select a non-trivial splitter bunch splitter_bunch
    3392         278 :             bunch_t* const splitter_bunch(part_tr.get_some_nontrivial());
    3393         278 :             if (nullptr == splitter_bunch)  break;
    3394             :             // Line 1.11: Select a small action_block-slice in splitter_bunch
    3395             :             // and
    3396         226 :             /* Line 1.12: Create a new bunch new_bunch that consists of the  */ ONLY_IF_DEBUG( mCRL2log(log::debug, "bisim_dnj") << "Refining "
    3397             :             /*            selected action_block-slice                        */                                   << splitter_bunch->debug_id(*this) << '\n'; )
    3398             :             bunch_t* const new_bunch(
    3399         226 :                   splitter_bunch->split_off_small_action_block_slice(part_tr));
    3400             :                                                                                 #ifndef NDEBUG
    3401         226 :             /*--------------- find predecessors of new_bunch ----------------*/     mCRL2log(log::debug, "bisim_dnj") << "Splitting off "
    3402           0 :                                                                                                                          << new_bunch->debug_id(*this) << '\n';
    3403         226 :             /* Line 1.13: for all transitions s --> t in new_bunch do        */     unsigned const max_splitter_counter(new_bunch->max_work_counter(*this));
    3404             :                                                                                 #endif
    3405             :             {
    3406         226 :                 action_block_iter_t splitter_iter(new_bunch->begin);            assert(splitter_iter < new_bunch->end);
    3407         378 :                 do
    3408         378 :                 {                                                               assert(splitter_iter->succ()->block_bunch->pred->action_block==splitter_iter);
    3409             :                     state_info_iter_t const source(
    3410         378 :                              splitter_iter->succ()->block_bunch->pred->source);
    3411             :                     // Line 1.14: Mark s
    3412             :                     bool const first_transition_of_state(
    3413         378 :                                              source->block->mark(source->pos));
    3414             :                     // Line 1.15: Set the current out-slice pointer of s to a
    3415             :                     //            transition in splitter_bunch (preferably not
    3416             :                     //            s --> t itself)
    3417             :                     // Line 1.17: Register that s --> t is now part of
    3418             :                     //            new_bunch
    3419         378 :                     part_tr.first_move_transition_to_new_bunch(splitter_iter,
    3420             :                                                     first_transition_of_state); // mCRL2complexity(splitter_iter->succ()->block_bunch->pred, ...) -- subsumed
    3421             :             // Line 1.19: end for                                               // in the call below
    3422             :                 }
    3423         378 :                 while (++splitter_iter < new_bunch->end);
    3424             :             }
    3425             : 
    3426             :             // We cannot join the loop above with the loop below!
    3427             : 
    3428             :             // Line 1.13: for all transitions s --> t in new_bunch do
    3429             :             {
    3430         226 :                 action_block_iter_t splitter_iter = new_bunch->begin;           assert(splitter_iter < new_bunch->end);
    3431         378 :                 do
    3432             :                 {
    3433             :                     // Line 1.16: Add the block_bunch-slice of splitter_bunch
    3434             :                     //            where s --> t was in to the list of unstable
    3435             :                     //            block_bunch-slices
    3436             :                     // Line 1.17: Register that s --> t is now part of
    3437             :                     //            new_bunch
    3438             :                     // Line 1.18: Add the block_bunch-slice of new_bunch where
    3439             :                     //            s --> t is now in to the list of unstable
    3440             :                     //            block_bunch-slices
    3441         378 :                     part_tr.second_move_transition_to_new_bunch(                ONLY_IF_DEBUG( *this, )
    3442             :                                                      splitter_iter, new_bunch); // mCRL2complexity(splitter_iter->succ()->block_bunch->pred, ...) -- subsumed
    3443             :             // Line 1.19: end for                                               // in the call below
    3444             :                 }
    3445         378 :                 while (++splitter_iter < new_bunch->end);
    3446         226 :             }                                                                   mCRL2complexity(new_bunch, add_work(bisim_gjkw::check_complexity::
    3447             :                                                                                                            refine_partition_until_it_becomes_stable__find_pred,
    3448             :             /*----------------- stabilise the partition again ---------------*/                                                  max_splitter_counter), *this);
    3449             : 
    3450             :             // Line 1.20: while the list of unstable block_bunch-slices is not
    3451             :             //                  empty do
    3452         438 :             while (!part_tr.unstable_block_bunch.empty())
    3453             :             {                                                                   // The work in this iteration is ascribed to some transition in the
    3454             :                 // Line 1.21: splitter := the first unstable block bunch-slice  // splitter block_bunch-slice.  Therefore, we increase the counter of that
    3455             :                     // The first element of the unstable block_bunch-slices     // block_bunch-slice.  This is allowed because we started with a small
    3456             :                     // list should be a small splitter of a block that is       // splitter.
    3457             :                     // marked accordingly.                                      //
    3458             :                 block_bunch_slice_iter_t splitter(                              // We have to call mCRL2complexity here because splitter may be split up later.
    3459         162 :                                          part_tr.unstable_block_bunch.begin()); mCRL2complexity(splitter, add_work(bisim_gjkw::check_complexity::
    3460             :                                                                                                          refine_partition_until_it_becomes_stable__stabilize,
    3461             :                                                                                                                                  max_splitter_counter), *this);
    3462         162 :                 block_t* refine_block(splitter->source_block());                assert(!splitter->is_stable());  assert(splitter->bunch() == new_bunch);
    3463         162 :                 /* Line 1.22: Remove splitter from the list of unstable      */ assert(!splitter->empty());
    3464         162 :                 /*            block_bunch-slices                             */ assert(1 < refine_block->size());  assert(0 < refine_block->marked_size());
    3465         324 :                 refine_block->stable_block_bunch.splice(
    3466         162 :                     refine_block->stable_block_bunch.end(),
    3467             :                                        part_tr.unstable_block_bunch, splitter);
    3468         162 :                 splitter->make_stable();                                        // test whether the next splitter actually belongs to this block:
    3469         162 :                 /* Line 1.23: (red_block, blue_block) := refine(source block */ assert(*part_tr.unstable_block_bunch.front().bunch() < *splitter->bunch());
    3470         162 :                 /*         of splitter, splitter, extend from marked states) */ assert(part_tr.unstable_block_bunch.front().source_block() == refine_block);
    3471             :                 {
    3472         162 :                     permutation_iter_t refine_block_begin(refine_block->begin); assert(refine_block_begin->st->pos == refine_block_begin);
    3473             :                     // reuse variable refine_block here to point to the red
    3474             :                     // subblock:
    3475         162 :                     refine_block = refine(refine_block, splitter,
    3476             :                                                     extend_from_marked_states);
    3477             :                     // Line 1.24: Mark unstable block bunch-slices of
    3478             :                     //            blue_block as stable
    3479         162 :                     if (refine_block_begin < refine_block->begin)
    3480             :                     {
    3481             :                         block_t* const blue_block(
    3482         141 :                                                 refine_block_begin->st->block); assert(blue_block->end == refine_block->begin);
    3483             :                         block_bunch_slice_iter_t blue_splitter(
    3484         141 :                                          part_tr.unstable_block_bunch.begin()); assert(0 == blue_block->marked_size());
    3485         486 :                         if (part_tr.unstable_block_bunch.end()!=blue_splitter&&
    3486         141 :                         (blue_splitter->source_block() == blue_block ||
    3487         183 :                          (++blue_splitter!=part_tr.unstable_block_bunch.end()&&
    3488          21 :                                  blue_splitter->source_block() == blue_block)))
    3489         141 :                         {                                                       assert(!blue_splitter->is_stable());
    3490         141 :                             /* The next ``unstable'' block_bunch is the blue */ assert(blue_splitter->bunch() == splitter_bunch);
    3491             :                             // subblock's slice.  Actually that is already
    3492             :                             // stable.
    3493         282 :                             blue_block->stable_block_bunch.splice(
    3494         141 :                                 blue_block->stable_block_bunch.end(),
    3495             :                                   part_tr.unstable_block_bunch, blue_splitter);
    3496         141 :                             blue_splitter->make_stable();
    3497             :                         }
    3498             :                     }
    3499             :                 }
    3500             :                 // Line 1.25: if red_block has marked states (i. e. it has new
    3501             :                 //               non-inert transitions) then
    3502         162 :                 if (0 < refine_block->marked_size())
    3503             :                 {
    3504             :                     // Line 1.26: red_block := postprocess(red_block)
    3505          17 :                     refine_block = postprocess_new_noninert(refine_block,
    3506             :                                                                      splitter);
    3507             :                     // Line 1.27: if red block == {} then
    3508             :                     //                Continue this loop, i. e. go to Line 1.19
    3509          65 :                     if (nullptr == refine_block)  continue;
    3510             :                 // Line 1.28: end if
    3511             :                 }
    3512             :                 // Line 1.29: splitter := the first (remaining) unstable
    3513             :                 //                        block_bunch-slice
    3514             :                     // Now the first element of the unstable block_bunch-slices
    3515             :                     // list should be a large splitter of red_block, and it
    3516             :                     // should be handled using the current_out_slice pointers.
    3517         151 :                 splitter = part_tr.unstable_block_bunch.begin();
    3518         151 :                 if (part_tr.unstable_block_bunch.end() == splitter)  break;     assert(!splitter->is_stable());
    3519             :                 // Line 1.30: if red_block == source block of splitter then
    3520          95 :                 if (refine_block == splitter->source_block())
    3521          94 :                 {                                                               assert(splitter->bunch() == splitter_bunch);
    3522             :                     // Line 1.31: Remove splitter from the list of unstable
    3523             :                     //            block_bunch-slices
    3524         188 :                     refine_block->stable_block_bunch.splice(
    3525          94 :                             refine_block->stable_block_bunch.end(),
    3526             :                                        part_tr.unstable_block_bunch, splitter);
    3527          94 :                     splitter->make_stable();
    3528             : 
    3529             :                     // Line 1.32: (red_block, ) := refine(red_block, splitter,
    3530             :                     //                                    extend from splitter)
    3531          94 :                     if (1 >= refine_block->size())  continue;
    3532          57 :                     refine_block = refine(refine_block, splitter,
    3533             :                                                          extend_from_splitter   ONLY_IF_DEBUG( , new_bunch )
    3534             :                                                                              );
    3535             :                     // Line 1.33: if red_block has marked states (i. e. it has
    3536             :                     //               new non-inert transitions) then
    3537          57 :                     if (0 < refine_block->marked_size())
    3538             :                     {
    3539             :                         // Line 1.34: postprocess(red_block)
    3540          22 :                         postprocess_new_noninert(refine_block, splitter);
    3541             :                     // Line 1.35: end if
    3542             :                     }
    3543             :                 // Line 1.36: end if
    3544             :                 }
    3545             :             // Line 1.37: end while
    3546             :             }
    3547             :         // Line 1.38: end while
    3548             :         }
    3549             : 
    3550             :         // store the labels with the action_block-slices
    3551             :         // As every action_block-slice is a (trivial) bunch at the same time,
    3552             :         // we can reuse the field sort_key_and_label.label (instead of
    3553             :         // sort_key_and_label.sort_key) to store the label.
    3554             :         action_block_const_iter_t action_block_iter_end(
    3555          52 :                                              part_tr.action_block_inert_begin);
    3556          52 :         label_type label(0);                                                    assert(label < action_label.size());
    3557         431 :         do
    3558             :         {
    3559         803 :             for (action_block_iter_t action_block_iter(
    3560         161 :                                                    action_label[label].begin);
    3561             :               action_block_iter < action_block_iter_end;
    3562         321 :               action_block_iter = action_block_iter->begin_or_before_end() + 1)
    3563         321 :             {                                                                   assert(action_block_iter->succ()->block_bunch->pred->action_block ==
    3564             :                                                                                                                                             action_block_iter);
    3565         321 :                 action_block_iter->succ()->bunch()->sort_key_and_label.label =
    3566         321 :                                                                          label; assert(action_block_iter <= action_block_iter->begin_or_before_end());
    3567             :             }
    3568             :         }
    3569         161 :         while (++label < action_label.size() &&
    3570         109 :             (action_block_iter_end = action_label[label - 1].begin - 1, true));
    3571          52 :     }
    3572             : 
    3573             :     /*----------------- Refine -- Algorithm 3 of [GJKW 2017] ----------------*/
    3574             : 
    3575             :     /// \brief Split a block according to a splitter
    3576             :     /// \details The function splits `refine_block` into the red part (states
    3577             :     /// with a transition in `splitter`) and the blue part (states without a
    3578             :     /// transition in `splitter`).  Depending on `mode`, the states are primed
    3579             :     /// as follows:
    3580             :     ///
    3581             :     /// - If `mode == extend_from_marked_states`, then all states with a
    3582             :     ///   transition must have been marked already.
    3583             :     /// - If `mode == extend_from_marked_states_for_init_and_postprocess`,
    3584             :     ///   states are marked as above.  The only difference is the handling of
    3585             :     ///   new non-inert transitions.
    3586             :     /// - If `mode == extend_from_splitter`, then no states must be marked;
    3587             :     ///   the initial states with a transition in `splitter` are searched by
    3588             :     ///   `refine()` itself.
    3589             :     /// - If `mode == extend_from_bottom_state_markings_and_splitter`, then
    3590             :     ///   bottom states with a transition must have been marked already, but
    3591             :     ///   there may be non-bottom states that also have a transition, which are
    3592             :     ///   searched by `refine()`.
    3593             :     ///
    3594             :     /// The  function  will  also  adapt  all  data  structures  and  determine
    3595             :     /// which  transitions  have  changed  from  inert  to  non-inert.   States
    3596             :     /// with  a  new  non-inert  transition  will  be  marked  upon  returning.
    3597             :     /// Normally,  the  new  non-inert  transitions  are  moved  to  a  new
    3598             :     /// bunch,  which  will  be  specially  created.   However,  if  `mode ==
    3599             :     /// extend_from_marked_states_for_init_and_postprocess`, then the new
    3600             :     /// non-inert transitions will be added to `splitter` (which must hold
    3601             :     /// transitions that have just become non-inert before this call to
    3602             :     /// `refine()`).  If the resulting block contains marked states, the caller
    3603             :     /// has to call `postprocess_new_noninert()` to stabilise the block because
    3604             :     /// the new bunch may make the block unstable.
    3605             :     /// \param refine_block  block that needs to be refined
    3606             :     /// \param splitter      transition set that makes the block unstable
    3607             :     /// \param mode          indicates how to find states with a transition in
    3608             :     ///                      `splitter`, as described above
    3609             :     /// \returns (a pointer to) the red subblock.  It is an error to call the
    3610             :     /// function with settings that lead to an empty red subblock.  (An empty
    3611             :     /// blue subblock is ok.)
    3612         285 :     block_t* refine(block_t* const refine_block,
    3613             :         const block_bunch_slice_iter_t& splitter, enum refine_mode_t const mode ONLY_IF_DEBUG( , const bunch_t* const new_bunch = nullptr )
    3614             :                                                                               )
    3615         285 :     {                                                                           assert(refine_block == splitter->source_block());
    3616             :                                                                                 #ifndef NDEBUG
    3617         285 :                                                                                     mCRL2log(log::debug, "bisim_dnj") << "refine("
    3618           0 :                                                                                         << refine_block->debug_id(part_st.permutation)
    3619           0 :                                                                                         << ',' << splitter->debug_id(*this)
    3620           0 :                                                                                         << (extend_from_marked_states_for_init_and_postprocess == mode
    3621             :                                                                                            ? ",extend_from_marked_states_for_init_and_postprocess,"
    3622             :                                                                                            : (extend_from_marked_states == mode
    3623             :                                                                                              ? ",extend_from_marked_states,"
    3624             :                                                                                              : (extend_from_bottom_state_markings_and_splitter == mode
    3625             :                                                                                                ? ",extend_from_bottom_state_markings_and_splitter,"
    3626             :                                                                                                : (extend_from_splitter == mode
    3627             :                                                                                                  ? ",extend_from_splitter,"
    3628             :                                                                                                  : ",UNKNOWN MODE,"))))
    3629           0 :                                                                                         << (nullptr == new_bunch ? std::string("nullptr")
    3630             :                                                                                                                         : new_bunch->debug_id(*this)) << ")\n";
    3631             :                                                                                 #endif
    3632             : 
    3633         285 :                                                                                 assert(1 < refine_block->size());
    3634         285 :                                                                                 assert(0 < refine_block->marked_size() ||
    3635             :                                                                                             extend_from_splitter == mode ||
    3636             :                                                                                             extend_from_bottom_state_markings_and_splitter == mode);
    3637         285 :         block_t* red_block;                                                     assert(0 == refine_block->marked_size() || extend_from_splitter != mode);
    3638         285 :                                                                                 assert((nullptr == new_bunch) == (extend_from_splitter != mode));
    3639             :         COROUTINES_SECTION
    3640             :             // shared variables of both coroutines
    3641             :             permutation_iter_t notblue_initialised_end(
    3642         285 :                                                 refine_block->nonbottom_begin);
    3643         285 :             permutation_iter_t blue_nonbottom_end(notblue_initialised_end);
    3644             : 
    3645             :             // Line 2.2: need_slow_test := (mode not in {extend from marked
    3646             :             //                            states, extend from marked states for
    3647             :             //                              initialisation and postprocessing})
    3648             :             bool need_slow_test(extend_from_marked_states != mode &&
    3649         285 :                    extend_from_marked_states_for_init_and_postprocess != mode);
    3650             : 
    3651             :             // variable declarations of the blue coroutine
    3652         285 :             permutation_iter_t blue_visited_end;
    3653         285 :             pred_iter_t blue_pred_iter;
    3654         285 :             state_info_iter_t blue_t;
    3655         285 :             succ_const_iter_t blue_end;
    3656             : 
    3657             :             // variable declarations of the red coroutine
    3658             :             union R
    3659             :             {
    3660             :                 block_bunch_iter_t fromred;
    3661             :                 permutation_iter_t block;
    3662             : 
    3663             :                 // Because the union has nontrivial members, constructor and
    3664             :                 // destructor are required:
    3665         285 :                 R(bool need_slow_test)
    3666             :                 {
    3667         285 :                     if (need_slow_test)  new (&fromred) block_bunch_iter_t();
    3668         220 :                     else                 new (&block) permutation_iter_t();
    3669         285 :                 }
    3670             : 
    3671          37 :                 void convert_to_permutation_iter_t()
    3672             :                 {
    3673             :                     fromred.~block_bunch_iter_t();
    3674          37 :                     new (&block) permutation_iter_t();
    3675          37 :                 }
    3676             : 
    3677         285 :                 ~R()
    3678             :                 {
    3679             :                     // The caller should ensure that
    3680             :                     // convert_to_permutation_iter_t() has been called before
    3681             :                     // the destructor.  In practice, we use need_slow_test to
    3682             :                     // decide this: if need_slow_test == false, the class is
    3683             :                     // already converted to permutation_iter_t.
    3684             :                     block.~permutation_iter_t();
    3685         285 :                 }
    3686         570 :             } red_visited_begin(need_slow_test);
    3687             : 
    3688         285 :             pred_iter_t red_pred_iter;
    3689             : 
    3690         285 :             COROUTINE_LABELS(   (REFINE_RED_PREDECESSOR_HANDLED)
    3691             :                                 (REFINE_BLUE_PREDECESSOR_HANDLED)
    3692             :                                 (REFINE_RED_STATE_HANDLED)
    3693             :                                 (REFINE_BLUE_STATE_HANDLED)
    3694             :                                 (REFINE_BLUE_TESTING)
    3695             :                                 (REFINE_RED_COLLECT_FROMRED)
    3696             :                                 (REFINE_BLUE_COLLECT_BOTTOM))
    3697             : 
    3698             :             /*---------------------- find blue states -----------------------*/
    3699             : 
    3700             :             COROUTINE
    3701             :                 // Line 2.4l: if mode = extend_from_splitter then
    3702         285 :                 if (extend_from_splitter == mode)
    3703             :                 {
    3704             :                     // we have to decide which unmarked bottom states are blue.
    3705             :                     // So we walk over all of them and check whether they have
    3706             :                     // a transition to the bunch of FromRed or not.
    3707          57 :                     blue_visited_end = refine_block->begin;
    3708             : 
    3709             :                     /*  -  -  -  -  collect blue bottom states  -  -  -  -  */
    3710             : 
    3711             :                     // Line 2.5l: for all non-red bottom states s do
    3712             :                         // We use the variable blue_visited_end in this loop
    3713             :                         // to indicate the boundary between blue states (those
    3714             :                         // in the interval [refine_block->begin,
    3715             :                         // blue_visited_end) ) and Test states (those in
    3716             :                         // [blue_visited_end,refine_block->marked_bottom_begin)
    3717             :                         // ).
    3718         126 :                     COROUTINE_WHILE (REFINE_BLUE_COLLECT_BOTTOM,
    3719             :                         blue_visited_end < refine_block->marked_bottom_begin &&
    3720             :                                                                 need_slow_test)
    3721             :                     {
    3722          70 :                         state_info_iter_t s(blue_visited_end->st);              assert(s->pos == blue_visited_end);
    3723          70 :                         /* Line 2.6l: if s has a transition in splitter then */ ONLY_IF_DEBUG(succ_const_iter_t in_small_splitter(s->current_out_slice.begin);)
    3724          70 :                         if (s->surely_has_transition_in(                        ONLY_IF_DEBUG( part_tr.succ, )
    3725             :                                                         splitter->bunch()))
    3726             :                         {
    3727             :                             // Line 2.7l: Make s a red state
    3728          39 :                             std::swap(*blue_visited_end,
    3729             :                                          *--refine_block->marked_bottom_begin);
    3730          78 :                             if (refine_block->size() / 2 <
    3731          39 :                                                    refine_block->marked_size())
    3732             :                             {
    3733           5 :                                 ABORT_OTHER_COROUTINE();
    3734          39 :                             }                                                   ONLY_IF_DEBUG( in_small_splitter=in_small_splitter->begin_or_before_end()+1; )
    3735          39 :                         /* Line 2.8l: else                                   */ assert(s->current_out_slice.begin < in_small_splitter);
    3736             :                         }
    3737             :                         else
    3738          31 :                         {                                                       assert(s->surely_has_no_transition_in(part_tr.succ, splitter->bunch()));
    3739             :                             // Line 2.9l: Make s a blue state
    3740          31 :                             ++blue_visited_end;
    3741          62 :                             if (refine_block->size() / 2 < (state_type)
    3742          31 :                                       (blue_visited_end - refine_block->begin))
    3743             :                             {
    3744           1 :                                 ABORT_THIS_COROUTINE();
    3745             :                             }
    3746             :                         // Line 2.10l: end if                                   // refine() has been called from Line 1.30.  We should ascribe the
    3747             :                         }                                                       // work to the transition in the small splitter.
    3748             :                                                                                 #ifndef NDEBUG
    3749          69 :                                                                                     assert(in_small_splitter->block_bunch->pred->action_block->succ() ==
    3750             :                                                                                                                                             in_small_splitter);
    3751          69 :                                                                                     assert(in_small_splitter < s->succ_inert.begin);
    3752          69 :                                                                                     assert(in_small_splitter->bunch() == new_bunch);
    3753          69 :                                                                                     succ_entry::add_work_to_out_slice(*this, in_small_splitter, bisim_gjkw::
    3754             :                     /* Line 2.11l: end for                                   */               check_complexity::refine_blue__handle_transition_in_FromRed, 1U);
    3755             :                                                                                 #endif
    3756             :                     }
    3757             :                     END_COROUTINE_WHILE;
    3758             :                 // Line 2.12l: end if
    3759             :                 }
    3760             :                 // Blue := Blue union Test
    3761             :                     // done implicitly: we now regard all unmarked bottom
    3762             :                     // states as blue, i. e. the whole interval
    3763             :                     // [refine_block->bottom_begin,
    3764             :                     // refine_block->marked_bottom_begin).
    3765         272 :                 if(refine_block->size()/2<refine_block->unmarked_bottom_size())
    3766             :                 {
    3767          72 :                     ABORT_THIS_COROUTINE();
    3768             :                 }
    3769         200 :                 if (0 == refine_block->unmarked_bottom_size())
    3770             :                 {
    3771             :                     // all bottom states are red, so there cannot be any blue
    3772             :                     // states.  Unmark all states, as there are no transitions
    3773             :                     // that have become non-inert.
    3774          77 :                     refine_block->marked_nonbottom_begin = refine_block->end;
    3775          77 :                     refine_block->marked_bottom_begin =
    3776             :                                                  refine_block->nonbottom_begin;
    3777          77 :                     red_block = refine_block;                                   ONLY_IF_DEBUG( finalise_blue_is_smaller(nullptr,red_block, new_bunch, *this); )
    3778          77 :                     TERMINATE_COROUTINE_SUCCESSFULLY();
    3779             :                 }
    3780             : 
    3781             :                  /*  -  -  -  -  -  -  visit blue states  -  -  -  -  -  -  */
    3782             : 
    3783         123 :                 if (blue_nonbottom_end < refine_block->marked_nonbottom_begin)
    3784             :                 {
    3785             :                     // Line 2.13l: for all blue states s do
    3786          72 :                     blue_visited_end = refine_block->begin;
    3787         195 :                     COROUTINE_DO_WHILE (REFINE_BLUE_STATE_HANDLED,
    3788             :                                          blue_visited_end < blue_nonbottom_end)
    3789             :                     {
    3790             :                         // Line 2.14l: for all inert transitions t--tau-->s do
    3791         155 :                         blue_pred_iter=blue_visited_end->st->pred_inert.begin;  assert(part_tr.pred.cbegin()->target != blue_visited_end->st);
    3792         282 :                         COROUTINE_FOR(REFINE_BLUE_PREDECESSOR_HANDLED, (void)0,
    3793             :                               blue_pred_iter->target == blue_visited_end->st,
    3794             :                                                               ++blue_pred_iter)
    3795             :                         {
    3796         147 :                             blue_t = blue_pred_iter->source;                    assert(refine_block->nonbottom_begin <= blue_t->pos);
    3797         147 :                             /* Line 2.15l: if t is red then  Skip state t    */ assert(blue_t->pos < refine_block->end);
    3798         147 :                             if (refine_block->marked_nonbottom_begin <=
    3799             :                                                                    blue_t->pos)
    3800             :                             {
    3801          25 :                                 goto continuation;
    3802             :                             }
    3803         122 :                             if (notblue_initialised_end <= blue_t->pos)
    3804             :                             {
    3805         122 :                                 blue_t->not_.blue = blue_t->succ_inert.begin;
    3806         122 :                                 std::swap(*blue_t->pos,
    3807             :                                                    *notblue_initialised_end++);
    3808         122 :                             }                                                   assert(blue_t != part_tr.succ.cend()[-1].block_bunch->pred->source);
    3809             :                             // Line 2.16l: notblue [t] := notblue [t] − 1
    3810         122 :                             ++blue_t->not_.blue;
    3811             :                             // Line 2.17l: if notblue[t] > 0 then  Skip state t
    3812         122 :                             if (blue_t ==
    3813             :                                   blue_t->not_.blue->block_bunch->pred->source)
    3814             :                             {
    3815           3 :                                 goto continuation;
    3816             :                             }
    3817             :                             // Line 2.18l: if need_slow_test then
    3818         119 :                             if (need_slow_test)
    3819             :                             {
    3820          11 :                                 if(blue_t->surely_has_transition_in(            ONLY_IF_DEBUG( part_tr.succ, )
    3821             :                                                             splitter->bunch()))
    3822             :                                 {
    3823           1 :                                     goto continuation;
    3824             :                                 }
    3825          10 :                                 if (!blue_t->surely_has_no_transition_in(       ONLY_IF_DEBUG( part_tr.succ, )
    3826             :                                                             splitter->bunch()))
    3827           3 :                                 {                                               assert(blue_t != part_tr.succ.cbegin()->block_bunch->pred->source);
    3828             :                                     // Line 2.19l: for all non-inert
    3829             :                                     //             t --alpha--> u do
    3830           3 :                                     blue_end = blue_t->succ_inert.begin;        assert(part_tr.succ.cbegin() + 1 < blue_end);
    3831           3 :                                                                                 assert(blue_t == blue_end[-1].block_bunch->pred->source);
    3832           3 :                                     COROUTINE_DO_WHILE (REFINE_BLUE_TESTING,
    3833             :                                         blue_t ==
    3834             :                                         blue_end[-1].block_bunch->pred->source)
    3835             :                                     {
    3836           3 :                                         blue_end =
    3837           3 :                                             blue_end[-1].begin_or_before_end(); assert(blue_end->block_bunch->pred->source == blue_t);
    3838             :                                         // Line 2.20l: if t --alpha--> u in
    3839             :                                         //             splitter  then  Skip t
    3840             :                                         block_bunch_slice_const_iter_t const
    3841             :                                             block_bunch(
    3842           3 :                                                blue_end->block_bunch->slice());
    3843           3 :                                         if (&*block_bunch == &*splitter)
    3844             :                                         {
    3845           3 :                                             goto continuation;
    3846             :                                                // i. e. break and then continue
    3847             :                                         }
    3848           0 :                                         if (*block_bunch->bunch() <
    3849           0 :                                                             *splitter->bunch())
    3850             :                                         {
    3851           0 :                                             break;
    3852           0 :                                         }                                       ONLY_IF_DEBUG( succ_entry::add_work_to_out_slice(*this, blue_end,
    3853             :                                     /* Line 2.21l: end for                   */                    bisim_gjkw::check_complexity::refine_blue__slow_test, 1U); )
    3854             :                                     }
    3855             :                                     END_COROUTINE_DO_WHILE;
    3856             :                             // Line 2.22l: end if
    3857             :                                 }
    3858         115 :                             }                                                   assert(blue_nonbottom_end <= blue_t->pos);
    3859         115 :                             /* Line 2.23l: Make t a blue state               */ assert(blue_t->pos < notblue_initialised_end);
    3860         115 :                             std::swap(*blue_t->pos, *blue_nonbottom_end++);
    3861         230 :                             if (refine_block->size() / 2 < blue_nonbottom_end -
    3862             :                                     refine_block->nonbottom_begin +
    3863         115 :                                           refine_block->unmarked_bottom_size())
    3864             :                             {
    3865             :                                 // As the blue coroutine is now aborted, the
    3866             :                                 // notblue values are no longer relevant.  The
    3867             :                                 // assignment tells the red coroutine that it
    3868             :                                 // doesn't need to make complicated swaps any
    3869             :                                 // more to keep notblue properly initialized.
    3870          20 :                                 notblue_initialised_end = blue_nonbottom_end;
    3871          20 :                                 ABORT_THIS_COROUTINE();
    3872             :                             }
    3873             :                         // Line 2.24: end for
    3874         127 :                     continuation:                                               mCRL2complexity(blue_pred_iter, add_work(bisim_gjkw::
    3875             :                                                                                    check_complexity::refine_blue__handle_transition_to_blue_state, 1U), *this);
    3876             :                         }
    3877         123 :                         END_COROUTINE_FOR;                                      mCRL2complexity(blue_visited_end->st, add_work(bisim_gjkw::check_complexity::
    3878             :                     /* Line 2.25l: end for                                   */         refine_blue__find_predecessors_of_blue_state, 1U), part_st.state_info);
    3879         123 :                         ++blue_visited_end;
    3880         123 :                         if(refine_block->marked_bottom_begin==blue_visited_end)
    3881             :                         {
    3882          35 :                             blue_visited_end = refine_block->nonbottom_begin;
    3883             :                         }
    3884             :                     }
    3885             :                     END_COROUTINE_DO_WHILE;
    3886             :                 }
    3887             : 
    3888             :                 /* -  -  -  -  -  -  split off blue block  -  -  -  -  -  - */
    3889             : 
    3890             :                 // Line 2.26l: Abort the red coroutine
    3891          73 :                 ABORT_OTHER_COROUTINE();
    3892          73 :                 if (need_slow_test)
    3893             :                 {
    3894           6 :                     red_visited_begin.convert_to_permutation_iter_t();
    3895             :                 }
    3896             :                 // Line 2.27l: Create a new block of the blue states
    3897             :                     // All non-blue states are red.
    3898          73 :                 refine_block->marked_nonbottom_begin = blue_nonbottom_end;
    3899          73 :                 red_block = refine_block;
    3900             :                 block_t* const blue_block(
    3901          73 :                              refine_block->split_off_block(new_block_is_blue,   ONLY_IF_DEBUG( part_st.permutation, )
    3902          73 :                                                       part_st.nr_of_blocks++));
    3903             :                 // Lines 2.29-2.45
    3904          73 :                 part_tr.adapt_transitions_for_new_block(blue_block,
    3905             :                                                                 refine_block,   ONLY_IF_DEBUG( *this, )
    3906             :                    extend_from_marked_states_for_init_and_postprocess == mode,
    3907          73 :                                                   splitter, new_block_is_blue); ONLY_IF_DEBUG(finalise_blue_is_smaller(blue_block,red_block,new_bunch,*this);)
    3908          73 :             END_COROUTINE
    3909             : 
    3910             :             /*----------------------- find red states -----------------------*/
    3911             : 
    3912             :             COROUTINE
    3913         189 :                 if (refine_block->size() / 2 < refine_block->marked_size())
    3914             :                 {
    3915           2 :                     ABORT_THIS_COROUTINE();
    3916             :                 }
    3917             : 
    3918             :                 /* -  -  -  -  -  collect states from FromRed  -  -  -  -  - */
    3919             : 
    3920             :                 // Line 2.4r: if need_slow_test then
    3921         187 :                 if (need_slow_test)
    3922             :                 {
    3923             :                     // Line 2.5r: for all transitions s --> t in splitter do
    3924          62 :                     red_visited_begin.fromred = splitter->end;                  assert(part_tr.block_bunch.cbegin()->slice != splitter);
    3925         140 :                     COROUTINE_DO_WHILE (REFINE_RED_COLLECT_FROMRED,
    3926             :                                red_visited_begin.fromred[-1].slice == splitter)
    3927          97 :                     {                                                           assert(part_tr.block_bunch.cbegin() + 1 < red_visited_begin.fromred);
    3928          97 :                         --red_visited_begin.fromred;
    3929             :                         state_info_iter_t s(
    3930          97 :                                       red_visited_begin.fromred->pred->source); assert(s->block == refine_block);  assert(s->pos->st == s);
    3931             :                         // Line 2.9r: Make s a red state
    3932         146 :                         if (refine_block->nonbottom_begin <= s->pos && (        assert(blue_nonbottom_end <= s->pos),
    3933          49 :                                              s->pos < notblue_initialised_end))
    3934             :                         {
    3935             :                             // The non-bottom state has a transition to a blue
    3936             :                             // state, so notblue is initialised; however, now
    3937             :                             // it is discovered to be red anyway.
    3938           4 :                             std::swap(*s->pos, *--notblue_initialised_end);
    3939             :                         }
    3940         235 :                         if (refine_block->mark(s->pos) &&
    3941         138 :                           refine_block->size()/2 < refine_block->marked_size())
    3942             :                         {
    3943          19 :                             ABORT_THIS_COROUTINE();
    3944          78 :                         }                                                       mCRL2complexity(red_visited_begin.fromred->pred, add_work(bisim_gjkw::
    3945             :                     /* Line 2.10r: end for                                   */    check_complexity::refine_red__handle_transition_from_red_state, 1U), *this);
    3946             :                     }
    3947             :                     END_COROUTINE_DO_WHILE;
    3948             : 
    3949             :                     // Line 2.11r: need_slow_test := false
    3950             :                         // The shared variable need_slow_test is set to false
    3951             :                         // as soon as the transitions in splitter have been
    3952             :                         // completed.
    3953          31 :                     need_slow_test = false;
    3954          31 :                     red_visited_begin.convert_to_permutation_iter_t();
    3955             :                 // Line 2.12r: end if
    3956             :                 }
    3957             : 
    3958         156 :                 /*-  -  -  -  -  -  -  visit red states  -  -  -  -  -  -  -*/  assert(0 != refine_block->marked_size());
    3959             : 
    3960         156 :                 if (blue_nonbottom_end < refine_block->marked_nonbottom_begin)
    3961             :                 {
    3962             :                     // Line 2.13r: for all red states s do
    3963          66 :                     red_visited_begin.block = refine_block->nonbottom_begin;
    3964          66 :                     if (refine_block->marked_bottom_begin ==
    3965             :                                                        red_visited_begin.block)
    3966             :                     {
    3967             :                         // It may happen that all found states are non-bottom
    3968             :                         // states.  (In that case, some of these states will
    3969             :                         // become new bottom states.)
    3970          23 :                         red_visited_begin.block = refine_block->end;
    3971          66 :                     }                                                           assert(refine_block->marked_nonbottom_begin != red_visited_begin.block);
    3972         209 :                     COROUTINE_DO_WHILE(REFINE_RED_STATE_HANDLED, refine_block->
    3973             :                              marked_nonbottom_begin != red_visited_begin.block)
    3974             :                     {
    3975         159 :                         --red_visited_begin.block;                              assert(part_tr.pred.cend()[-1].target != red_visited_begin.block->st);
    3976             :                         // Line 2.14r: for all inert transitions t--tau-->s do
    3977         245 :                         COROUTINE_FOR (REFINE_RED_PREDECESSOR_HANDLED,
    3978             :                             red_pred_iter =
    3979             :                                 red_visited_begin.block->st->pred_inert.begin,
    3980             :                             red_pred_iter->target==red_visited_begin.block->st,
    3981             :                                                                ++red_pred_iter)
    3982             :                         {
    3983         102 :                             state_info_iter_t const t(red_pred_iter->source);   assert(blue_nonbottom_end <= t->pos);
    3984         102 :                             /* Line 2.23r: Make t a red state                */ assert(t->pos->st == t);  assert(t->pos < refine_block->end);
    3985         102 :                             if (t->pos < notblue_initialised_end)
    3986             :                             {
    3987             :                                 // The state has a transition to a blue state,
    3988             :                                 // so notblue is initialised; however, now it
    3989             :                                 // is discovered to be red anyway.
    3990           3 :                                 std::swap(*t->pos, *--notblue_initialised_end);
    3991             :                             }
    3992         270 :                             if (refine_block->mark_nonbottom(t->pos) &&
    3993          84 :                                         refine_block->size() / 2 <
    3994          84 :                                                    refine_block->marked_size())
    3995             :                             {
    3996          16 :                                 ABORT_THIS_COROUTINE();
    3997          86 :                             }                                                   mCRL2complexity(red_pred_iter, add_work(bisim_gjkw::
    3998             :                         /* Line 2.24r: end for                               */      check_complexity::refine_red__handle_transition_to_red_state, 1U), *this);
    3999             :                         }
    4000         143 :                         END_COROUTINE_FOR;                                      mCRL2complexity(red_visited_begin.block->st, add_work(bisim_gjkw::
    4001             :                                                                                                 check_complexity::refine_red__find_predecessors_of_red_state,
    4002             :                     /* Line 2.25r: end for                                   */                                                       1U), part_st.state_info);
    4003         177 :                         if (refine_block->marked_bottom_begin ==
    4004             :                                                      red_visited_begin.block &&
    4005          34 :                          red_visited_begin.block<refine_block->nonbottom_begin)
    4006             :                         {
    4007          33 :                             red_visited_begin.block = refine_block->end;
    4008             :                         }
    4009             :                     }
    4010             :                     END_COROUTINE_DO_WHILE;
    4011             :                 }
    4012             : 
    4013             :                 /*  -  -  -  -  -  -  split off red block  -  -  -  -  -  -  */
    4014             : 
    4015             :                 // Line 2.26r: Abort the blue coroutine
    4016         135 :                 ABORT_OTHER_COROUTINE();
    4017             :                 // Line 2.27r: Create a new block of the red states
    4018             :                     // All non-red states are blue.
    4019         135 :                 red_block = refine_block->split_off_block(new_block_is_red,     ONLY_IF_DEBUG( part_st.permutation, )
    4020             :                                                        part_st.nr_of_blocks++);
    4021             :                 // Lines 2.29-2.45
    4022         135 :                 part_tr.adapt_transitions_for_new_block(red_block,refine_block, ONLY_IF_DEBUG( *this, )
    4023             :                     extend_from_marked_states_for_init_and_postprocess == mode,
    4024         135 :                                                    splitter, new_block_is_red); ONLY_IF_DEBUG( finalise_red_is_smaller(refine_block, red_block, *this); )
    4025         135 :             END_COROUTINE
    4026           0 :         END_COROUTINES_SECTION
    4027         285 :         return red_block;
    4028             :     }
    4029             : 
    4030             :     /*--------- PostprocessNewBottom -- Algorithm 4 of [GJKW 2017] ----------*/
    4031             : 
    4032             :     /// \brief Prepare a block for postprocesing
    4033             :     /// \details When this function starts, it assumes that the states with a
    4034             :     /// new non-inert transition in refine_block are marked.  It is an error if
    4035             :     /// it does not contain any marked states.
    4036             :     ///
    4037             :     /// The function separates the states with new non-inert transitions from
    4038             :     /// those without;  as a result, the red subblock (which contains states
    4039             :     /// with new non-inert transitions) will contain at least one new bottom
    4040             :     /// state (and no old bottom states).  It then sorts the new bottom states
    4041             :     /// according to the first bunch in which they have transitions and marks
    4042             :     /// all block_bunch-slices of refine_block as unstable.
    4043             :     /// \param refine_block   block containing states with new non-inert
    4044             :     ///                       transitions that need to be stabilised
    4045             :     /// \param last_splitter  splitter of the last separation before, i. e. the
    4046             :     ///                       splitter that made these transitions non-inert
    4047             :     ///                       (refine_block should already be stable w. r. t.
    4048             :     ///                       last_splitter).
    4049             :     /// \param first_preparation  If true, then the function also makes sure
    4050             :     ///                           that all unstable block_bunch-slice of
    4051             :     ///                           refine_block are before
    4052             :     ///                           unstable_block_bunch_postprocess_end.
    4053             :     /// \returns the block containing the old bottom states (and every state in
    4054             :     ///          refine_block that cannot reach any new non-inert transition),
    4055             :     ///          i. e. the blue subblock of the separation
    4056          44 :     block_t* prepare_for_postprocessing(block_t* refine_block,
    4057             :                                  block_bunch_slice_const_iter_t last_splitter,
    4058             :                                                         bool first_preparation)
    4059          44 :     {                                                                           assert(refine_block == last_splitter->source_block());
    4060          44 :         block_t* blue_block;                                                    assert(part_tr.block_bunch.cbegin() + 1 < part_tr.block_bunch_inert_begin);
    4061             :         block_bunch_slice_iter_t new_noninert_block_bunch(
    4062          44 :                                   part_tr.block_bunch_inert_begin[-1].slice()); assert(last_splitter->is_stable());
    4063          44 :         /* Line 4.2: if refine block has unmarked bottom states then         */ assert(refine_block == new_noninert_block_bunch->source_block());
    4064          44 :             /* The noninert block_bunch-slice is already stable, so we do not*/ assert(new_noninert_block_bunch->is_stable());
    4065          44 :             /* need to move it to the stable block_bunch-slices.             */ assert(0 < refine_block->marked_size());
    4066          44 :         if (0 < refine_block->unmarked_bottom_size())
    4067             :         {
    4068             :             // Line 4.3: (refine block,result) := refine(refine block, new
    4069             :             //                non-inert transitions, extend from marked states
    4070             :             //                           for initialisation and postprocessing)
    4071           7 :             refine_block = refine(refine_block, new_noninert_block_bunch,
    4072           7 :                            extend_from_marked_states_for_init_and_postprocess); assert(part_st.permutation.cbegin() < refine_block->begin);
    4073           7 :             blue_block = refine_block->begin[-1].st->block;
    4074             :             // If more new noninert transitions are found, we do not need to
    4075             :             // handle them, as every bottom state already has a transition in
    4076             :             // new_noninert_block_bunch->bunch.
    4077           7 :             if (0 < refine_block->marked_bottom_size())
    4078             :             {
    4079             :                 // New non-inert transitions have been found.  In that case, we
    4080             :                 // also have to refine w. r. t. the last splitter.  We set the
    4081             :                 // variable `last_splitter` to new_noninert_block_bunch so it
    4082             :                 // won't disturb in the test below.
    4083           4 :                 last_splitter = new_noninert_block_bunch;
    4084             :             }
    4085             :         // Line 4.4: else
    4086             :         }
    4087             :         else
    4088             :         {
    4089             :             // Line 4.5: result := {}
    4090          37 :             blue_block = nullptr;
    4091             :         // Line 4.6: end if
    4092             :         }
    4093          44 :         refine_block->marked_bottom_begin = refine_block->nonbottom_begin;
    4094          44 :         refine_block->marked_nonbottom_begin = refine_block->end;
    4095             : 
    4096             :         // if this is the first call to prepare_for_postprocessing in the
    4097             :         // beginning of postprocess_new_noninert, then
    4098             :         // unstable_block_bunch_postprocess_end may point to a slice of the red
    4099             :         // subblock; as we stabilise for all subblocks of it during
    4100             :         // postprocessing, we pull it before
    4101             :         // unstable_block_bunch_postprocess_end.
    4102          44 :         if (first_preparation)
    4103             :         {
    4104             :             block_bunch_slice_iter_t red_splitter =
    4105             :                         part_tr.unstable_block_bunch_postprocess_end =
    4106          39 :                                           part_tr.unstable_block_bunch.begin();
    4107             : 
    4108          39 :             if (part_tr.unstable_block_bunch.end() != red_splitter)
    4109             :             {
    4110           8 :                 if (red_splitter->source_block() == refine_block)
    4111             :                 {
    4112           2 :                     ++part_tr.unstable_block_bunch_postprocess_end;
    4113             :                 }
    4114          10 :                 else if (++red_splitter!=part_tr.unstable_block_bunch.end() &&
    4115           4 :                                   red_splitter->source_block() == refine_block)
    4116             :                 {
    4117           2 :                     part_tr.unstable_block_bunch.splice(
    4118             :                         part_tr.unstable_block_bunch_postprocess_end,
    4119             :                                    part_tr.unstable_block_bunch, red_splitter);
    4120             :                 }
    4121             :             }
    4122             :         }
    4123             :                                                                                 #ifndef NDEBUG
    4124             :                                                                                     // assert that the remainder of the unstable block_bunch slice list after
    4125             :                                                                                     // part_tr.unstable_block_bunch_postprocess_end does not contain any
    4126             :                                                                                     // block_bunch slice whose source_block() is refine_block.
    4127         121 :                                                                                     for (block_bunch_slice_const_iter_t block_bunch_iter(
    4128          44 :                                                                                                                part_tr.unstable_block_bunch_postprocess_end);
    4129         110 :                                                                                                       block_bunch_iter != part_tr.unstable_block_bunch.cend();
    4130             :                                                                                                                                             ++block_bunch_iter)
    4131             :                                                                                     {
    4132          11 :                                                                                         assert(block_bunch_iter->source_block() != refine_block);
    4133             :                                                                                     }
    4134             :                                                                                 #endif
    4135          44 :         if (1 >= refine_block->size())  return blue_block;
    4136             : 
    4137             :         // Line 4.7: for all bottom states s in refine_block do
    4138             :         {
    4139          19 :             permutation_iter_t s_iter(refine_block->begin);                     assert(s_iter < refine_block->nonbottom_begin);
    4140          32 :             do
    4141             :             {
    4142          32 :                 state_info_iter_t const s(s_iter->st);                          assert(s->pos == s_iter);
    4143             :                 // Line 4.8: Set the current out-slice pointer of s
    4144             :                 //                                      past its last out-slice
    4145          32 :                 s->current_out_slice.begin = s->succ_inert.begin;               mCRL2complexity(s, add_work(bisim_gjkw::check_complexity::
    4146             :                                                                                                           prepare_for_postprocessing, 1U), part_st.state_info);
    4147             : 
    4148             :         // Line 4.9: end for
    4149             :             }
    4150          32 :             while (++s_iter < refine_block->nonbottom_begin);
    4151             :         }
    4152             : 
    4153             :         // Line 4.10: Sort the bottom states of refine_block according to the
    4154             :         //                  out-slice just before the current out-slice pointer
    4155          19 :         std::sort(refine_block->begin, refine_block->nonbottom_begin,
    4156             :                                                 before_current_out_slice_less);
    4157             :                                                                                 #ifndef NDEBUG
    4158             :                                                                                     {
    4159          19 :         /* Line 4.11: Make all block_bunch-slices of refine_block unstable   */         permutation_const_iter_t s_iter(refine_block->begin);
    4160          64 :             /* However, the bunch of new noninert transitions and the bunch  */         do  assert(s_iter->st->pos == s_iter);
    4161          32 :             /* that was the last splitter do not need to be handled (as long */         while (++s_iter < refine_block->nonbottom_begin);
    4162             :             /* as there are no further new bottom states).                   */     }
    4163             :                                                                                 #endif
    4164         158 :         for (block_bunch_slice_iter_t block_bunch_iter(
    4165          19 :                                    refine_block->stable_block_bunch.begin());
    4166         118 :                   refine_block->stable_block_bunch.end() != block_bunch_iter; )
    4167          40 :         {                                                                       assert(block_bunch_iter->is_stable());
    4168             :             block_bunch_slice_iter_t const next_block_bunch_iter(
    4169          40 :                                                   std::next(block_bunch_iter));
    4170          63 :             if (&*block_bunch_iter != &*last_splitter &&
    4171          23 :                                   block_bunch_iter != new_noninert_block_bunch)
    4172             :             {
    4173           6 :                 part_tr.unstable_block_bunch.splice(
    4174             :                     part_tr.unstable_block_bunch_postprocess_end,
    4175             :                            refine_block->stable_block_bunch, block_bunch_iter);
    4176           6 :                 block_bunch_iter->make_unstable();
    4177             :             }
    4178             :                                                                                 #ifndef NDEBUG
    4179             :                                                                                     // Try to assign this work to a transition from a bottom state in
    4180             :                                                                                     // block_bunch_iter.
    4181             :                                                                                     // If that does not succeed, temporarily assign it to the block_bunch
    4182             :                                                                                     // itself.  Later, we shall find a bottom state to which this work can be
    4183             :                                                                                     // assigned.
    4184          40 :                                                                                     assert(!block_bunch_iter->work_counter.has_temporary_work());
    4185          40 :                                                                                     if (!block_bunch_iter->add_work_to_bottom_transns(bisim_gjkw::
    4186             :                                                                                           check_complexity::prepare_for_postprocessing__make_unstable_a_priori,
    4187             :                                                                                                                                                     1U, *this))
    4188             :                                                                                     {
    4189           3 :                                                                                         mCRL2complexity(block_bunch_iter, add_work(bisim_gjkw::
    4190             :                                                                                               check_complexity::prepare_for_postprocessing__make_unstable_temp,
    4191             :                                                                                                                                                    1U), *this);
    4192           3 :                                                                                         assert(block_bunch_iter->work_counter.has_temporary_work());
    4193             :                                                                                     }
    4194             :                                                                                 #endif
    4195          40 :             block_bunch_iter = next_block_bunch_iter;
    4196             :         }
    4197             :         // Line 4.12: return result {i. e. the part of refine_block
    4198             :         //                                           without new bottom states}
    4199          19 :         return blue_block;
    4200             :     }
    4201             : 
    4202             : 
    4203             :     /// \brief Split a block with new non-inert transitions as needed
    4204             :     /// \details The function splits refine_block by stabilising for all
    4205             :     /// bunches in which it contains transitions.
    4206             :     ///
    4207             :     /// When this function starts, it assumes that the states with a new
    4208             :     /// non-inert transition in refine_block are marked.  It is an error if it
    4209             :     /// does not contain any marked states.
    4210             :     ///
    4211             :     /// The function first separates the states with new non-inert transitions
    4212             :     /// from those without;  as a result, the red subblock (which contains
    4213             :     /// states with new non-inert transitions) will contain at least one new
    4214             :     /// bottom state.  Then it walks through all the bunches that can be
    4215             :     /// reached from this subblock to separate it into smaller, stable
    4216             :     /// subblocks.
    4217             :     /// \param refine_block   block containing states with new non-inert
    4218             :     ///                       transitions that need to be stabilised
    4219             :     /// \param last_splitter  splitter of the last separation before, i. e. the
    4220             :     ///                       splitter that made these transitions non-inert
    4221             :     ///                       (refine_block should already be stable w. r. t.
    4222             :     ///                       last_splitter).
    4223             :     /// \returns the block containing the old bottom states (and every state in
    4224             :     ///          refine_block that cannot reach any new non-inert transition),
    4225             :     ///          i. e. the blue subblock of the first separation above
    4226          39 :     block_t* postprocess_new_noninert(block_t* refine_block,
    4227             :                            const block_bunch_slice_const_iter_t& last_splitter)
    4228             :     {
    4229             : 
    4230             :         /*-------------- collect reachable block_bunch-slices ---------------*/
    4231             : 
    4232             :         // Line 3.2: result := prepare_for_postprocessing(refine_block)
    4233             :         block_t* const result_block(
    4234          39 :                 prepare_for_postprocessing(refine_block, last_splitter, true));
    4235             : 
    4236             :         /*----------- stabilise w. r. t. found block_bunch-slices -----------*/
    4237             : 
    4238             :         // Line 3.3: for all block_bunch-slices splitter
    4239             :         //         that emanate from (a part of) the original block \ result do
    4240          39 :         block_bunch_slice_iter_t splitter;
    4241         120 :         while ((splitter = part_tr.unstable_block_bunch.begin())
    4242         106 :                                != part_tr.unstable_block_bunch_postprocess_end)
    4243          14 :         {                                                                       assert(!splitter->is_stable());
    4244             :             // Line 3.4: refine_block := the source block of splitter
    4245          14 :             refine_block = splitter->source_block();                            assert(0 == refine_block->marked_size());
    4246          14 :                                                                                 assert(refine_block->begin < refine_block->nonbottom_begin);
    4247          14 :             if (1 >= refine_block->size())
    4248             :             {
    4249             :                 // make the splitter stable and do nothing else.
    4250           4 :                 refine_block->stable_block_bunch.splice(
    4251           2 :                             refine_block->stable_block_bunch.end(),
    4252             :                                        part_tr.unstable_block_bunch, splitter);
    4253           2 :                 splitter->make_stable();
    4254             :                                                                                 #ifndef NDEBUG
    4255             :                                                                                     // now splitter must have some transitions that start in bottom states:
    4256           2 :                                                                                     if (splitter->work_counter.has_temporary_work())
    4257             :                                                                                     {
    4258           0 :                                                                                         assert(splitter->add_work_to_bottom_transns(bisim_gjkw::
    4259             :                                                                                            check_complexity::
    4260             :                                                                                            prepare_for_postprocessing__make_unstable_a_posteriori, 1U, *this));
    4261           0 :                                                                                         splitter->work_counter.reset_temporary_work();
    4262             :                                                                                     }
    4263           2 :                                                                                     assert(splitter->add_work_to_bottom_transns(bisim_gjkw::check_complexity::
    4264             :                                                                                                      postprocess_new_noninert__stabilize_a_priori, 1U, *this));
    4265             :                                                                                 #endif
    4266           9 :                 continue;
    4267             :             }
    4268             :             // Line 3.5: splitter' := the block_bunch-slice of the out-slice
    4269             :             //                         just before the current out-slice
    4270             :             //                         of the last bottom state in refine_block
    4271             :             {
    4272             :                 state_info_iter_t last_bottom_state(
    4273          12 :                                          refine_block->nonbottom_begin[-1].st); assert(last_bottom_state != part_tr.succ.cbegin()->block_bunch->pred->source);
    4274             :                 // Line 3.6: if splitter < splitter' then
    4275          88 :                 if (&*last_bottom_state->current_out_slice.begin[-1].
    4276          12 :                             block_bunch->pred->source != &*last_bottom_state ||
    4277           9 :                     *last_bottom_state->current_out_slice.begin[-1].bunch() <
    4278           9 :                                                           *splitter->bunch() ||
    4279             :                     (// Line 3.7: splitter := splitter'
    4280           7 :                      splitter = last_bottom_state->
    4281             :                             current_out_slice.begin[-1].block_bunch->slice(),
    4282           7 :                      !splitter->is_stable() &&
    4283             :                      // Line 3.8: Mark the bottom states
    4284             :                      //                      that have a transition in splitter
    4285           3 :                      (                                                          assert(part_tr.unstable_block_bunch_postprocess_end != splitter),
    4286          21 :                       refine_block->marked_bottom_begin = std::lower_bound(
    4287             :                        refine_block->begin, refine_block->nonbottom_begin-1,
    4288           3 :                           splitter->bunch(), before_current_out_slice_less),    assert(refine_block->marked_bottom_begin->st->
    4289             :                 /* Line 3.9: end if                                          */                      current_out_slice.begin[-1].bunch() == splitter->bunch()),
    4290             :                                                                         true)))
    4291           8 :                 {                                                               assert(refine_block->begin == refine_block->marked_bottom_begin ||
    4292             :                                                                                       refine_block->marked_bottom_begin[-1].st->current_out_slice.begin ==
    4293             :                                                                                                                                    part_tr.succ.cbegin() + 1 ||
    4294             :                                                                                       refine_block->marked_bottom_begin[-1].st->current_out_slice.begin[-1].
    4295             :                                                                                         block_bunch->pred->source < refine_block->marked_bottom_begin[-1].st ||
    4296             :                     /* Line 3.10: Remove splitter from the list              */       *refine_block->marked_bottom_begin[-1].st->current_out_slice.begin[-1].
    4297             :                     /*                        of unstable block_bunch-slices */                                                  bunch() < *splitter->bunch());
    4298          16 :                     refine_block->stable_block_bunch.splice(
    4299           8 :                             refine_block->stable_block_bunch.end(),
    4300             :                                        part_tr.unstable_block_bunch, splitter);
    4301           8 :                     splitter->make_stable();
    4302             :                                                                                 #ifndef NDEBUG
    4303             :                                                                                     bool stabilize_a_priori_succeeded(splitter->add_work_to_bottom_transns(
    4304             :                     /* Line 3.11: (refine_block, _) := refine(refine_block,  */                      bisim_gjkw::check_complexity::
    4305           8 :                     /*                         splitter, extend from bottom  */                      postprocess_new_noninert__stabilize_a_priori, 1U, *this));
    4306             :                     //                          state markings and splitter)
    4307             :                                                                                 #endif
    4308           8 :                     refine_block = refine(refine_block, splitter,
    4309             :                                extend_from_bottom_state_markings_and_splitter);
    4310             :                                                                                 #ifndef NDEBUG
    4311             :                                                                                     // now splitter must have some transitions that start in bottom states:
    4312           8 :                                                                                     if (splitter->work_counter.has_temporary_work())
    4313             :                                                                                     {
    4314           3 :                                                                                         assert(splitter->add_work_to_bottom_transns(bisim_gjkw::
    4315             :                                                                                            check_complexity::
    4316             :                                                                                            prepare_for_postprocessing__make_unstable_a_posteriori, 1U, *this));
    4317           3 :                                                                                         splitter->work_counter.reset_temporary_work();
    4318             :                                                                                     }
    4319             :                                                                                     // account for the work a bit early, so as to avoid trouble if `splitter`
    4320             :                                                                                     // is divided later:
    4321           8 :                                                                                     if (!stabilize_a_priori_succeeded)
    4322             :                                                                                     {
    4323           5 :                                                                                         assert(splitter->add_work_to_bottom_transns(bisim_gjkw::
    4324             :                                                                                                  check_complexity::
    4325             :                     /* Line 3.12: if refine block has marked states          */                  postprocess_new_noninert__stabilize_a_posteriori, 1U, *this));
    4326             :                     /*         (i. e. it has new non-inert transitions) then */     }
    4327             :                                                                                 #endif
    4328           8 :                     if (0 < refine_block->marked_size())
    4329             :                     {
    4330             :                         // Line 3.13: refine_block :=
    4331             :                         //             prepare_for_postprocessing(refine_block)
    4332           5 :                         refine_block = prepare_for_postprocessing(refine_block,
    4333             :                                                               splitter, false);
    4334          10 :                         if (nullptr == refine_block)  continue;
    4335             :                     // Line 3.14: end if
    4336             :                     }
    4337             :                 }
    4338             :                                                                                 #ifndef NDEBUG
    4339             :                                                                                     else
    4340             :                                                                                     {   // If the following assertion does not hold, uncomment the if below.
    4341           4 :                                                                                         assert(!splitter->work_counter.has_temporary_work());
    4342             :                                                                                         // now splitter must have some transitions that start in bottom states:
    4343             :                                                                                         // if (splitter->work_counter.has_temporary_work())
    4344             :                                                                                         // {
    4345             :                                                                                         //     assert(splitter->add_work_to_bottom_transns(bisim_gjkw::
    4346             :                                                                                         //                 check_complexity::
    4347             :                                                                                         //              prepare_for_postprocessing__make_unstable_a_posteriori,
    4348             :                                                                                         //                                                         1U, *this));
    4349             :                                                                                         //     splitter->work_counter.reset_temporary_work();
    4350             :                                                                                         // }
    4351             :                                                                                         // account for the work a bit early, so as to avoid trouble if
    4352             :                                                                                         // `splitter` is divided later:
    4353           4 :                                                                                         assert(splitter->add_work_to_bottom_transns(bisim_gjkw::
    4354             :                                                                                             check_complexity::postprocess_new_noninert__stabilize_a_priori,
    4355             :                                                                                                                                                    1U, *this));
    4356             :                                                                                     }
    4357             :                                                                                 #endif
    4358             :             }
    4359             :             /* Line 3.15: for all bottom states s in refine_block do         */
    4360             :             {
    4361           7 :                 permutation_iter_t s_iter(refine_block->begin);                 assert(s_iter < refine_block->nonbottom_begin);
    4362           9 :                 do
    4363             :                 {
    4364           9 :                     state_info_iter_t const s(s_iter->st);                      assert(s->pos == s_iter);
    4365           9 :                                                                                 assert(part_tr.succ.cbegin() + 1 < s->current_out_slice.begin);
    4366           9 :                                                                                 assert(s == s->current_out_slice.begin[-1].block_bunch->pred->source);
    4367           9 :                     /* Line 3.16: Decrease the current out-slice pointer of  */ assert(s->current_out_slice.begin[-1].begin_or_before_end() <
    4368             :                     /*                           s to the previous out-slice */                                                    s->current_out_slice.begin);
    4369           9 :                     s->current_out_slice.begin =
    4370           9 :                           s->current_out_slice.begin[-1].begin_or_before_end(); ONLY_IF_DEBUG( succ_entry::add_work_to_out_slice(*this,
    4371             :                                                                                            s->current_out_slice.begin,
    4372             :             /* Line 3.17: end for                                            */            bisim_gjkw::check_complexity::postprocess_new_noninert__sort, 1U); )
    4373             :                 }
    4374           9 :                 while (++s_iter < refine_block->nonbottom_begin);
    4375             :             }
    4376             :             // Line 3.18: Sort the bottom states of refine_block according to
    4377             :             //          the out-slice just before the current out-slice pointer
    4378           7 :             std::sort(refine_block->begin, refine_block->nonbottom_begin,
    4379             :                                                 before_current_out_slice_less);
    4380             :                                                                                 #ifndef NDEBUG
    4381           7 :                                                                                     permutation_const_iter_t s_iter(refine_block->begin);
    4382          18 :                                                                                     do  assert(s_iter->st->pos == s_iter);
    4383           9 :                                                                                     while (++s_iter < refine_block->nonbottom_begin);
    4384             :         // Line 3.19: end for                                                       // assert(splitter->add_work_to_bottom_transns(...)) -- see above
    4385             :                                                                                 #endif
    4386             :         }
    4387          39 :         part_tr.unstable_block_bunch_postprocess_end =
    4388          39 :                                             part_tr.unstable_block_bunch.end();
    4389             :         // Line 3.20: return result {i. e. the part of block
    4390             :         //                                           without new bottom states}
    4391          39 :         return result_block;
    4392             :     }
    4393             : };
    4394             : 
    4395             : ///@} (end of group part_refine)
    4396             : 
    4397             : 
    4398             : 
    4399             : 
    4400             : 
    4401             : /* ************************************************************************* */
    4402             : /*                                                                           */
    4403             : /*                       I M P L E M E N T A T I O N S                       */
    4404             : /*                                                                           */
    4405             : /* ************************************************************************* */
    4406             : 
    4407             : 
    4408             : 
    4409             : 
    4410             : 
    4411             : // This section contains implementations of functions that refer to details of
    4412             : // classes defined later, so they could not be defined at the point of
    4413             : // declaration.
    4414             : 
    4415             : /// \brief quick check to find out whether the state has a transition in
    4416             : /// `bunch`
    4417             : /// \details If the current_out_slice pointer happens to be set to the `bunch`
    4418             : /// the function can quickly find out whether the state has a transition in
    4419             : /// `bunch`.
    4420             : /// \param bunch bunch of interest
    4421             : /// \returns true if the state is known to have a transition in `bunch`
    4422             : /// \memberof state_info_entry
    4423          81 : inline bool state_info_entry::surely_has_transition_in(                         ONLY_IF_DEBUG( const bisim_gjkw::fixed_vector<succ_entry>& succ, )
    4424             :                                               const bunch_t* const bunch) const
    4425          81 : {                                                                               assert(current_out_slice.begin <= succ_inert.begin);
    4426         158 :                                                                                 assert(current_out_slice.begin == succ_inert.begin ||
    4427          81 :                                                                                                  this == &*current_out_slice.begin->block_bunch->pred->source);
    4428         235 :                                                                                 assert(current_out_slice.begin == succ_inert.begin ||
    4429             :                                                                                      succ.cbegin() + 1 == current_out_slice.begin ||
    4430             :                                                                                      &*current_out_slice.begin[-1].block_bunch->pred->source < this ||
    4431         166 :                                                                                      *current_out_slice.begin[-1].bunch() < *current_out_slice.begin->bunch());
    4432         158 :     return current_out_slice.begin < succ_inert.begin &&
    4433         158 :                                      bunch == current_out_slice.begin->bunch();
    4434             : }
    4435             : 
    4436             : 
    4437             : /// \brief quick check to find out whether the state has _no_ transition in
    4438             : /// `bunch`
    4439             : /// \details If the current_out_slice pointer happens to be set to the new
    4440             : /// bunch `NewBu` (which is the immediate successor of the most recent splitter
    4441             : /// bunch `bunch`), the function can quickly find out whether the state has a
    4442             : /// transition in `bunch`.
    4443             : /// Note that here, we will need that the dummy transition at the beginning of
    4444             : /// part_tr.pred has a source state iterator that can be dereferenced.
    4445             : /// \param bunch bunch of interest
    4446             : /// \returns true if the state is known to have _no_ transition in `bunch`
    4447             : /// \memberof state_info_entry
    4448          41 : inline bool state_info_entry::surely_has_no_transition_in(                      ONLY_IF_DEBUG( const bisim_gjkw::fixed_vector<succ_entry>& succ, )
    4449             :                                               const bunch_t* const bunch) const
    4450          41 : {                                                                               assert(current_out_slice.begin <= succ_inert.begin);
    4451          78 :                                                                                 assert(current_out_slice.begin == succ_inert.begin ||
    4452          41 :                                                                                                  this == &*current_out_slice.begin->block_bunch->pred->source);
    4453         115 :                                                                                 assert(current_out_slice.begin == succ_inert.begin ||
    4454             :                                                                                      succ.cbegin() + 1 == current_out_slice.begin ||
    4455             :                                                                                      &*current_out_slice.begin[-1].block_bunch->pred->source < this ||
    4456          86 :                                                                                      *current_out_slice.begin[-1].bunch() < *current_out_slice.begin->bunch());
    4457          78 :     return (current_out_slice.begin == succ_inert.begin ||
    4458         117 :                                  *bunch < *current_out_slice.begin->bunch()) &&
    4459          39 :         (&*current_out_slice.begin[-1].block_bunch->pred->source != this ||
    4460          42 :                                 *current_out_slice.begin[-1].bunch() < *bunch);
    4461             : }
    4462             :                                                                                 #ifndef NDEBUG
    4463             :                                                                                     template <class LTS_TYPE>
    4464           0 :                                                                                     inline std::string block_bunch_slice_t::debug_id(
    4465             :                                                                                                       const bisim_partitioner_dnj<LTS_TYPE>& partitioner) const
    4466             :                                                                                     {
    4467             :                                                                                         static struct {
    4468           0 :                                                                                             bool operator()(const block_bunch_entry& p1,
    4469             :                                                                                                                            const block_bunch_slice_t* p2) const
    4470             :                                                                                             {
    4471           0 :                                                                                                 return p1.slice != p2;
    4472             :                                                                                             }
    4473             :                                                                                         } block_bunch_not_equal;
    4474             : 
    4475           0 :                                                                                         assert(partitioner.part_tr.block_bunch.cbegin() + 1 <= end);
    4476           0 :                                                                                         assert(end <= partitioner.part_tr.block_bunch_inert_begin);
    4477           0 :                                                                                         std::string index_string(std::to_string(end -
    4478           0 :                                                                                                                 partitioner.part_tr.block_bunch.cbegin() + 1));
    4479           0 :                                                                                         if (empty())
    4480             :                                                                                         {
    4481             :                                                                                             return "empty block_bunch_slice [" + index_string + "," +
    4482           0 :                                                                                                                                             index_string + ")";
    4483             :                                                                                         }
    4484             :                                                                                         block_bunch_const_iter_t begin(
    4485           0 :                                                                                                                  partitioner.part_tr.block_bunch.cbegin() + 1);
    4486           0 :                                                                                         trans_type bunch_size(bunch()->end - bunch()->begin);
    4487           0 :                                                                                         if ((trans_type) (end - begin) > bunch_size)  begin = end - bunch_size;
    4488           0 :                                                                                         begin = std::lower_bound(begin, block_bunch_const_iter_t(end - 1),
    4489             :                                                                                                                                   this, block_bunch_not_equal);
    4490           0 :                                                                                         assert(begin->slice == this);
    4491           0 :                                                                                         assert(begin == partitioner.part_tr.block_bunch.cbegin() + 1 ||
    4492             :                                                                                                                                       begin[-1].slice != this);
    4493           0 :                                                                                         return "block_bunch-slice [" + std::to_string(begin -
    4494             :                                                                                                                 partitioner.part_tr.block_bunch.cbegin() - 1) +
    4495             :                                                                                                     "," + index_string + ") containing transitions from " +
    4496             :                                                                                                     source_block()->debug_id(partitioner.part_st.permutation) +
    4497           0 :                                                                                                                  " in " + bunch()->debug_id_short(partitioner);
    4498             :                                                                                     }
    4499             : 
    4500             : 
    4501             :                                                                                     template <class LTS_TYPE>
    4502          78 :                                                                                     /* static */ inline void succ_entry::add_work_to_out_slice(
    4503             :                                                                                         const bisim_partitioner_dnj<LTS_TYPE>& partitioner,
    4504             :                                                                                         succ_const_iter_t out_slice_begin, enum bisim_gjkw::check_complexity::
    4505             :                                                                                                               counter_type const ctr, unsigned const max_value)
    4506             :                                                                                     {
    4507             :                                                                                         succ_const_iter_t const out_slice_before_end(
    4508          78 :                                                                                                                        out_slice_begin->begin_or_before_end());
    4509          78 :                                                                                         assert(out_slice_begin <= out_slice_before_end);
    4510          78 :                                                                                         mCRL2complexity(out_slice_begin->block_bunch->pred,
    4511             :                                                                                                                         add_work(ctr, max_value), partitioner);
    4512          78 :                                                                                         while (++out_slice_begin <= out_slice_before_end)
    4513             :                                                                                         {
    4514             :                                                                                             // treat temporary counters specially
    4515           0 :                                                                                             mCRL2complexity(out_slice_begin->block_bunch->pred,
    4516             :                                                                                                             add_work_notemporary(ctr, max_value), partitioner);
    4517             :                                                                                         }
    4518          78 :                                                                                     }
    4519             : 
    4520             :                                                                                     static struct {
    4521       41001 :                                                                                         bool operator()(const iterator_or_counter<action_block_iter_t>& p1,
    4522             :                                                                                                            const action_block_const_iter_t& action_block) const
    4523             :                                                                                         {
    4524       41001 :                                                                                             return p1.begin > action_block;
    4525             :                                                                                         }
    4526             :                                                                                     } action_label_greater;
    4527             : 
    4528             :                                                                                     /// \brief print a transition identification for debugging
    4529             :                                                                                     template <class LTS_TYPE>
    4530           0 :                                                                                     inline std::string pred_entry::debug_id(
    4531             :                                                                                                       const bisim_partitioner_dnj<LTS_TYPE>& partitioner) const
    4532             :                                                                                     {
    4533             :                                                                                         // Search for the action label in partitioner.action_label
    4534           0 :                                                                                         label_type const label(std::lower_bound(
    4535             :                                                                                             partitioner.action_label.cbegin(), partitioner.action_label.cend(),
    4536           0 :                                                                                                                       action_block, action_label_greater) -
    4537           0 :                                                                                                                             partitioner.action_label.cbegin());
    4538           0 :                                                                                         assert(0 <= label && label < partitioner.action_label.size());
    4539           0 :                                                                                         assert(partitioner.action_label[label].begin <= action_block);
    4540           0 :                                                                                         assert(0==label||action_block<partitioner.action_label[label-1].begin);
    4541             :                                                                                         // class lts_lts_t uses a function pp() to transform the action label
    4542             :                                                                                         // to a string.
    4543           0 :                                                                                         return pp(partitioner.aut.action_label(label)) + "-transition " +
    4544           0 :                                                                                                                 debug_id_short(partitioner.part_st.state_info);
    4545             :                                                                                     }
    4546             : 
    4547             :                                                                                     /// \brief calculates the maximal allowed value for work counters
    4548             :                                                                                     /// associated with this bunch
    4549             :                                                                                     /// \details Work counters may only be nonzero if this bunch is a
    4550             :                                                                                     /// single-action bunch, i. e. all its transitions have the same action
    4551             :                                                                                     /// label.  Also, only then the size can be calculated as end - begin.
    4552             :                                                                                     template <class LTS_TYPE>
    4553       14262 :                                                                                     inline int bunch_t::max_work_counter(
    4554             :                                                                                                       const bisim_partitioner_dnj<LTS_TYPE>& partitioner) const
    4555             :                                                                                     {
    4556             :                                                                                         // verify that the bunch only has a single action label.
    4557             :                                                                                         // Search for the action label in partitioner.action_label
    4558       14262 :                                                                                         label_type const label(std::lower_bound(
    4559             :                                                                                             partitioner.action_label.cbegin(), partitioner.action_label.cend(),
    4560       42786 :                                                                                                                                 begin, action_label_greater) -
    4561       14262 :                                                                                                                             partitioner.action_label.cbegin());
    4562       14262 :                                                                                         assert(0 <= label && label < partitioner.action_label.size());
    4563       14262 :                                                                                         assert(partitioner.action_label[label].begin <= begin);
    4564       14262 :                                                                                         assert(0 == label || begin < partitioner.action_label[label-1].begin);
    4565       14262 :                                                                                         if (0 == label || end < partitioner.action_label[label - 1].begin)
    4566             :                                                                                         {
    4567       11326 :                                                                                             assert(bisim_gjkw::check_complexity::ilog2(end - begin) <=
    4568             :                                                                                                                           bisim_gjkw::check_complexity::log_n);
    4569             :                                                                                             return bisim_gjkw::check_complexity::log_n -
    4570       11326 :                                                                                                               bisim_gjkw::check_complexity::ilog2(end - begin);
    4571             :                                                                                         }
    4572        2936 :                                                                                         return 0;
    4573             :                                                                                     }
    4574             : 
    4575             :                                                                                     // \brief moves temporary work counters to normal ones if the blue block is
    4576             :                                                                                     // smaller
    4577             :                                                                                     template <class LTS_TYPE>
    4578         150 :                                                                                     static void finalise_blue_is_smaller(const block_t* const blue_block,
    4579             :                                                                                                 const block_t* const red_block, const bunch_t* const new_bunch,
    4580             :                                                                                                             const bisim_partitioner_dnj<LTS_TYPE>& partitioner)
    4581             :                                                                                     {
    4582          34 :                                                                                         unsigned const max_bunch(nullptr == new_bunch ? 0U
    4583         184 :                                                                                                                    : new_bunch->max_work_counter(partitioner));
    4584         150 :                                                                                         if (nullptr != blue_block)
    4585             :                                                                                         {
    4586             :                                                                                             unsigned const max_blue_block(bisim_gjkw::check_complexity::log_n -
    4587          73 :                                                                                                       bisim_gjkw::check_complexity::ilog2(blue_block->size()));
    4588             :                                                                                             // finalise work counters for the blue states and their transitions
    4589          73 :                                                                                             permutation_const_iter_t s_iter(blue_block->begin);
    4590          73 :                                                                                             assert(s_iter < blue_block->end);
    4591         113 :                                                                                             do
    4592             :                                                                                             {
    4593         113 :                                                                                                 state_info_const_iter_t const s(s_iter->st);
    4594         113 :                                                                                                 mCRL2complexity(s, finalise_work(bisim_gjkw::check_complexity::
    4595             :                                                                                                         refine_blue__find_predecessors_of_blue_state,
    4596             :                                                                                                         bisim_gjkw::check_complexity::
    4597             :                                                                                                         refine__find_predecessors_of_red_or_blue_state,
    4598             :                                                                                                               max_blue_block), partitioner.part_st.state_info);
    4599         113 :                                                                                                 assert(s != partitioner.part_tr.pred.cend()[-1].target);
    4600         242 :                                                                                                 for (pred_const_iter_t pred_iter(s->pred_inert.begin);
    4601         121 :                                                                                                                            s == pred_iter->target; ++pred_iter)
    4602             :                                                                                                 {
    4603           8 :                                                                                                     mCRL2complexity(pred_iter, finalise_work(
    4604             :                                                                                                             bisim_gjkw::check_complexity::
    4605             :                                                                                                             refine_blue__handle_transition_to_blue_state,
    4606             :                                                                                                             bisim_gjkw::check_complexity::
    4607             :                                                                                                             refine__handle_transition_to_red_or_blue_state,
    4608             :                                                                                                                                  max_blue_block), partitioner);
    4609             :                                                                                                 }
    4610             :                                                                                                 // Sometimes, inert transitions become transitions from red to
    4611             :                                                                                                 // blue states; therefore, we also have to walk through the
    4612             :                                                                                                 // noninert predecessors of blue states:
    4613         113 :                                                                                                 assert(s != partitioner.part_tr.pred.cbegin()->target);
    4614         544 :                                                                                                 for (pred_const_iter_t pred_iter(s->pred_inert.begin);
    4615         272 :                                                                                                                                   s == (--pred_iter)->target; )
    4616             :                                                                                                 {
    4617         159 :                                                                                                     mCRL2complexity(pred_iter, finalise_work(
    4618             :                                                                                                             bisim_gjkw::check_complexity::
    4619             :                                                                                                             refine_blue__handle_transition_to_blue_state,
    4620             :                                                                                                             bisim_gjkw::check_complexity::
    4621             :                                                                                                             refine__handle_transition_to_red_or_blue_state,
    4622             :                                                                                                                                  max_blue_block), partitioner);
    4623             :                                                                                                 }
    4624         113 :                                                                                                 assert(s != partitioner.part_tr.succ.cbegin()->
    4625             :                                                                                                                                     block_bunch->pred->source);
    4626         404 :                                                                                                 for (succ_const_iter_t succ_iter(s->succ_inert.begin);
    4627         202 :                                                                                                                s == (--succ_iter)->block_bunch->pred->source; )
    4628             :                                                                                                 {
    4629          89 :                                                                                                     mCRL2complexity(succ_iter->block_bunch->pred,finalise_work(
    4630             :                                                                                                           bisim_gjkw::check_complexity::refine_blue__slow_test,
    4631             :                                                                                                           bisim_gjkw::check_complexity::
    4632             :                                                                                                           refine__handle_transition_from_red_or_blue_state,
    4633             :                                                                                                                                  max_blue_block), partitioner);
    4634          89 :                                                                                                     mCRL2complexity(succ_iter->block_bunch->pred,finalise_work(
    4635             :                                                                                                             bisim_gjkw::check_complexity::
    4636             :                                                                                                             refine_blue__handle_transition_in_FromRed,
    4637             :                                                                                                             bisim_gjkw::check_complexity::
    4638             :                                                                                                             refine__handle_transition_in_FromRed,
    4639             :                                                                                                                                       max_bunch), partitioner);
    4640             :                                                                                                 }
    4641             :                                                                                             }
    4642         113 :                                                                                             while (++s_iter < blue_block->end);
    4643             :                                                                                         }
    4644             :                                                                                         // cancel work counters for the red states and their transitions, and
    4645             :                                                                                         // also account for work done in the blue coroutine on red states
    4646         150 :                                                                                         permutation_const_iter_t s_iter(red_block->begin);
    4647         150 :                                                                                         assert(s_iter < red_block->end);
    4648         715 :                                                                                         do
    4649             :                                                                                         {
    4650         715 :                                                                                             state_info_const_iter_t const s(s_iter->st);
    4651         715 :                                                                                             mCRL2complexity(s, cancel_work(bisim_gjkw::check_complexity::
    4652             :                                                                                                                  refine_red__find_predecessors_of_red_state),
    4653             :                                                                                                                                partitioner.part_st.state_info);
    4654         715 :                                                                                             assert(s != partitioner.part_tr.pred.cend()[-1].target);
    4655        2072 :                                                                                             for (pred_const_iter_t pred_iter(s->pred_inert.begin);
    4656        1036 :                                                                                                                            s == pred_iter->target; ++pred_iter)
    4657             :                                                                                             {
    4658         321 :                                                                                                 mCRL2complexity(pred_iter, cancel_work(
    4659             :                                                                                                      bisim_gjkw::check_complexity::
    4660             :                                                                                                      refine_red__handle_transition_to_red_state), partitioner);
    4661             :                                                                                             }
    4662         715 :                                                                                             assert(s !=
    4663             :                                                                                                  partitioner.part_tr.succ.cbegin()->block_bunch->pred->source);
    4664        3140 :                                                                                             for (succ_const_iter_t succ_iter(s->succ_inert.begin);
    4665        1570 :                                                                                                                s == (--succ_iter)->block_bunch->pred->source; )
    4666             :                                                                                             {
    4667         855 :                                                                                                 mCRL2complexity(succ_iter->block_bunch->pred, cancel_work(
    4668             :                                                                                                    bisim_gjkw::check_complexity::
    4669             :                                                                                                    refine_red__handle_transition_from_red_state), partitioner);
    4670             :                                                                                                 // the following counters measure work done in the blue
    4671             :                                                                                                 // coroutine that found red states.
    4672         855 :                                                                                                 mCRL2complexity(succ_iter->block_bunch->pred, finalise_work(
    4673             :                                                                                                         bisim_gjkw::check_complexity::
    4674             :                                                                                                         refine_blue__handle_transition_in_FromRed,
    4675             :                                                                                                         bisim_gjkw::check_complexity::
    4676             :                                                                                                         refine__handle_transition_in_FromRed,
    4677             :                                                                                                                                       max_bunch), partitioner);
    4678         855 :                                                                                                 mCRL2complexity(succ_iter->block_bunch->pred,finalise_work(
    4679             :                                                                                                         bisim_gjkw::check_complexity::refine_blue__slow_test,
    4680             :                                                                                                         bisim_gjkw::check_complexity::
    4681             :                                                                                                           refine__slow_test_found_red_state, 1U), partitioner);
    4682             :                                                                                             }
    4683             :                                                                                         }
    4684         715 :                                                                                         while (++s_iter < red_block->end);
    4685             : 
    4686         150 :                                                                                         bisim_gjkw::check_complexity::check_temporary_work();
    4687         150 :                                                                                     }
    4688             : 
    4689             :                                                                                     // \brief moves temporary work counters to normal ones if the red block is
    4690             :                                                                                     // smaller
    4691             :                                                                                     template <class LTS_TYPE>
    4692         135 :                                                                                     static void finalise_red_is_smaller(const block_t* const blue_block,
    4693             :                                                                                                             const block_t* const red_block,
    4694             :                                                                                                             const bisim_partitioner_dnj<LTS_TYPE>& partitioner)
    4695             :                                                                                     {
    4696             :                                                                                         unsigned const max_red_block(bisim_gjkw::check_complexity::log_n -
    4697         135 :                                                                                                        bisim_gjkw::check_complexity::ilog2(red_block->size()));
    4698             :                                                                                         // cancel work counters for the blue states and their transitions
    4699         135 :                                                                                         permutation_const_iter_t s_iter(blue_block->begin);
    4700         135 :                                                                                         assert(s_iter < blue_block->end);
    4701        1820 :                                                                                         do
    4702             :                                                                                         {
    4703        1820 :                                                                                             state_info_const_iter_t const s(s_iter->st);
    4704        1820 :                                                                                             mCRL2complexity(s, cancel_work(bisim_gjkw::check_complexity::
    4705             :                                                                                                                refine_blue__find_predecessors_of_blue_state),
    4706             :                                                                                                                                partitioner.part_st.state_info);
    4707        1820 :                                                                                             assert(s != partitioner.part_tr.pred.cend()[-1].target);
    4708        4246 :                                                                                             for (pred_const_iter_t pred_iter(s->pred_inert.begin);
    4709        2123 :                                                                                                                            s == pred_iter->target; ++pred_iter)
    4710             :                                                                                             {
    4711         303 :                                                                                                 mCRL2complexity(pred_iter, cancel_work(
    4712             :                                                                                                    bisim_gjkw::check_complexity::
    4713             :                                                                                                    refine_blue__handle_transition_to_blue_state), partitioner);
    4714             :                                                                                             }
    4715             :                                                                                             // Sometimes, inert transitions become transitions from red to
    4716             :                                                                                             // blue states; therefore, we also have to walk through the
    4717             :                                                                                             // noninert predecessors of blue states:
    4718        1820 :                                                                                             assert(s != partitioner.part_tr.pred.cbegin()->target);
    4719        8044 :                                                                                             for (pred_const_iter_t pred_iter(s->pred_inert.begin);
    4720        4022 :                                                                                                                                   s == (--pred_iter)->target; )
    4721             :                                                                                             {
    4722        2202 :                                                                                                 mCRL2complexity(pred_iter, cancel_work(
    4723             :                                                                                                    bisim_gjkw::check_complexity::
    4724             :                                                                                                    refine_blue__handle_transition_to_blue_state), partitioner);
    4725             :                                                                                             }
    4726        1820 :                                                                                             assert(s !=
    4727             :                                                                                                  partitioner.part_tr.succ.cbegin()->block_bunch->pred->source);
    4728        8216 :                                                                                             for (succ_const_iter_t succ_iter(s->succ_inert.begin);
    4729        4108 :                                                                                                                s == (--succ_iter)->block_bunch->pred->source; )
    4730             :                                                                                             {
    4731        2288 :                                                                                                 mCRL2complexity(succ_iter->block_bunch->pred, cancel_work(
    4732             :                                                                                                       bisim_gjkw::check_complexity::
    4733             :                                                                                                       refine_blue__handle_transition_in_FromRed), partitioner);
    4734        2288 :                                                                                                 mCRL2complexity(succ_iter->block_bunch->pred, cancel_work(
    4735             :                                                                                                         bisim_gjkw::check_complexity::refine_blue__slow_test),
    4736             :                                                                                                                                                   partitioner);
    4737             :                                                                                             }
    4738             :                                                                                         }
    4739        1820 :                                                                                         while (++s_iter < blue_block->end);
    4740             :                                                                                         // finalise work counters for the red states and their transitions
    4741         135 :                                                                                         s_iter = red_block->begin;
    4742         135 :                                                                                         assert(s_iter < red_block->end);
    4743         280 :                                                                                         do
    4744             :                                                                                         {
    4745         280 :                                                                                             state_info_const_iter_t const s(s_iter->st);
    4746         280 :                                                                                             mCRL2complexity(s, finalise_work(bisim_gjkw::check_complexity::
    4747             :                                                                                                     refine_red__find_predecessors_of_red_state,
    4748             :                                                                                                     bisim_gjkw::check_complexity::
    4749             :                                                                                                     refine__find_predecessors_of_red_or_blue_state,
    4750             :                                                                                                                max_red_block), partitioner.part_st.state_info);
    4751         280 :                                                                                             assert(s != partitioner.part_tr.pred.cend()[-1].target);
    4752         704 :                                                                                             for (pred_const_iter_t pred_iter(s->pred_inert.begin);
    4753         352 :                                                                                                                            s == pred_iter->target; ++pred_iter)
    4754             :                                                                                             {
    4755          72 :                                                                                                 mCRL2complexity(pred_iter, finalise_work(
    4756             :                                                                                                         bisim_gjkw::check_complexity::
    4757             :                                                                                                         refine_red__handle_transition_to_red_state,
    4758             :                                                                                                         bisim_gjkw::check_complexity::
    4759             :                                                                                                         refine__handle_transition_to_red_or_blue_state,
    4760             :                                                                                                                                   max_red_block), partitioner);
    4761             :                                                                                             }
    4762         280 :                                                                                             assert(s !=
    4763             :                                                                                                  partitioner.part_tr.succ.cbegin()->block_bunch->pred->source);
    4764        1352 :                                                                                             for (succ_const_iter_t succ_iter(s->succ_inert.begin);
    4765         676 :                                                                                                                s == (--succ_iter)->block_bunch->pred->source; )
    4766             :                                                                                             {
    4767         396 :                                                                                                 mCRL2complexity(succ_iter->block_bunch->pred, finalise_work(
    4768             :                                                                                                         bisim_gjkw::check_complexity::
    4769             :                                                                                                         refine_red__handle_transition_from_red_state,
    4770             :                                                                                                         bisim_gjkw::check_complexity::
    4771             :                                                                                                         refine__handle_transition_from_red_or_blue_state,
    4772             :                                                                                                                                   max_red_block), partitioner);
    4773             :                                                                                                 // the following counter actually is work done in the blue
    4774             :                                                                                                 // coroutine that found red states.
    4775         396 :                                                                                                 mCRL2complexity(succ_iter->block_bunch->pred, cancel_work(
    4776             :                                                                                                       bisim_gjkw::check_complexity::
    4777             :                                                                                                       refine_blue__handle_transition_in_FromRed), partitioner);
    4778         396 :                                                                                                 mCRL2complexity(succ_iter->block_bunch->pred, cancel_work(
    4779             :                                                                                                         bisim_gjkw::check_complexity::refine_blue__slow_test),
    4780             :                                                                                                                                                   partitioner);
    4781             :                                                                                             }
    4782             :                                                                                         }
    4783         280 :                                                                                         while (++s_iter < red_block->end);
    4784         135 :                                                                                         bisim_gjkw::check_complexity::check_temporary_work();
    4785         135 :                                                                                     }
    4786             :                                                                                 #endif
    4787             : } // end namespace bisim_dnj
    4788             : 
    4789             : 
    4790             : 
    4791             : 
    4792             : 
    4793             : /* ************************************************************************* */
    4794             : /*                                                                           */
    4795             : /*                             I N T E R F A C E                             */
    4796             : /*                                                                           */
    4797             : /* ************************************************************************* */
    4798             : 
    4799             : 
    4800             : 
    4801             : 
    4802             : 
    4803             : /// \defgroup part_interface
    4804             : /// \brief nonmember functions serving as interface with the rest of mCRL2
    4805             : /// \details These functions are copied, almost without changes, from
    4806             : /// liblts_bisim_gw.h, which was written by Anton Wijs.
    4807             : ///@{
    4808             : 
    4809             : /// \brief Reduce transition system l with respect to strong or
    4810             : /// (divergence-preserving) branching bisimulation.
    4811             : /// \param[in,out] l                   The transition system that is reduced.
    4812             : /// \param         branching           If true branching bisimulation is
    4813             : ///                                    applied, otherwise strong bisimulation.
    4814             : /// \param         preserve_divergence Indicates whether loops of internal
    4815             : ///                                    actions on states must be preserved. If
    4816             : ///                                    false these are removed. If true these
    4817             : ///                                    are preserved.
    4818             : /// \param[out]    arbitrary_state_per_block    If this pointer is != nullptr,
    4819             : ///                                    the function fills the vector with, per
    4820             : ///                                    equivalence class, the number of an
    4821             : ///                                    arbitrary original state in the class.
    4822             : template <class LTS_TYPE>
    4823          52 : void bisimulation_reduce_dnj(LTS_TYPE& l, bool const branching /* = false */,
    4824             :      bool const preserve_divergence /* = false */,
    4825             :      std::vector<std::size_t>* const arbitrary_state_per_block /* = nullptr */)
    4826             : {
    4827             :     // First, contract tau-SCCs to single states in case of branching
    4828             :     // bisimulation.
    4829          52 :     if (branching)
    4830             :     {
    4831          33 :         scc_reduce(l, preserve_divergence);
    4832             :     }
    4833             : 
    4834             :     // Second, apply the branching bisimulation reduction algorithm. If there
    4835             :     // are no taus, this will automatically yield strong bisimulation.
    4836          52 :     if (1 < l.num_states())
    4837             :     {
    4838             :         bisim_dnj::bisim_partitioner_dnj<LTS_TYPE> bisim_part(l, branching,
    4839         100 :                                                           preserve_divergence);
    4840             : 
    4841             :         // Assign the reduced LTS
    4842          50 :         bisim_part.finalize_minimized_LTS(arbitrary_state_per_block);
    4843             :     }
    4844          52 : }
    4845             : 
    4846             : 
    4847             : /// \brief Checks whether the two initial states of two LTSs are strong or
    4848             : /// branching bisimilar.
    4849             : /// \details This routine uses the O(m log n) branching bisimulation algorithm
    4850             : /// developed in 2018 by David N. Jansen.  It runs in O(m log n) time and uses
    4851             : /// O(n) memory, where n is the number of states and m is the number of
    4852             : /// transitions.
    4853             : ///
    4854             : /// The LTSs l1 and l2 are not usable anymore after this call.
    4855             : /// \param[in,out] l1                  A first transition system.
    4856             : /// \param[in,out] l2                  A second transistion system.
    4857             : /// \param         branching           If true branching bisimulation is used,
    4858             : ///                                    otherwise strong bisimulation is
    4859             : ///                                    applied.
    4860             : /// \param         preserve_divergence If true and branching is true, preserve
    4861             : ///                                    tau loops on states.
    4862             : /// \returns True iff the initial states of the transition systems l1 and l2
    4863             : /// are (divergence-preserving) (branching) bisimilar.
    4864             : template <class LTS_TYPE>
    4865           2 : bool destructive_bisimulation_compare_dnj(LTS_TYPE& l1, LTS_TYPE& l2,
    4866             :                             bool const branching /* = false */,
    4867             :                             bool const preserve_divergence /* = false */,
    4868             :                             bool const generate_counter_examples /* = false */)
    4869             : {
    4870           2 :     if (generate_counter_examples)
    4871             :     {
    4872           0 :         mCRL2log(log::warning) << "The DNJ branching bisimulation "
    4873             :                               "algorithm does not generate counterexamples.\n";
    4874             :     }
    4875           2 :     std::size_t init_l2(l2.initial_state() + l1.num_states());
    4876           2 :     merge(l1, std::move(l2));
    4877           2 :     l2.clear(); // No use for l2 anymore.
    4878             : 
    4879             :     // First, contract tau-SCCs to single states in case of branching
    4880             :     // bisimulation.
    4881           2 :     if (branching)
    4882             :     {
    4883           0 :         scc_partitioner<LTS_TYPE> scc_part(l1);
    4884           0 :         scc_part.replace_transition_system(preserve_divergence);
    4885           0 :         init_l2 = scc_part.get_eq_class(init_l2);
    4886             :     }
    4887             : 
    4888           2 :     if (1 >= l1.num_states())  return true;
    4889             : 
    4890             :     bisim_dnj::bisim_partitioner_dnj<LTS_TYPE> bisim_part(l1, branching,
    4891           4 :                                                           preserve_divergence);
    4892             : 
    4893           2 :     return bisim_part.in_same_class(l1.initial_state(), init_l2);
    4894             : }
    4895             : 
    4896             : 
    4897             : 
    4898             : /*=============================================================================
    4899             : =                       explicit instantiation requests                       =
    4900             : =============================================================================*/
    4901             : 
    4902             : 
    4903             : 
    4904             : template void bisimulation_reduce_dnj(lts_lts_t& l, bool branching, bool
    4905             :      preserve_divergence, std::vector<std::size_t>* arbitrary_state_per_block);
    4906             : template void bisimulation_reduce_dnj(lts_aut_t& l, bool branching, bool
    4907             :      preserve_divergence, std::vector<std::size_t>* arbitrary_state_per_block);
    4908             : template void bisimulation_reduce_dnj(lts_fsm_t& l, bool branching, bool
    4909             :      preserve_divergence, std::vector<std::size_t>* arbitrary_state_per_block);
    4910             : 
    4911             : template bool destructive_bisimulation_compare_dnj(lts_lts_t& l1,lts_lts_t& l2,
    4912             :      bool branching, bool preserve_divergence, bool generate_counter_examples);
    4913             : template bool destructive_bisimulation_compare_dnj(lts_aut_t& l1,lts_aut_t& l2,
    4914             :      bool branching, bool preserve_divergence, bool generate_counter_examples);
    4915             : template bool destructive_bisimulation_compare_dnj(lts_fsm_t& l1,lts_fsm_t& l2,
    4916             :      bool branching, bool preserve_divergence, bool generate_counter_examples);
    4917             : 
    4918             : ///@} (end of group part_interface)
    4919             : 
    4920             : } // end namespace detail
    4921             : } // end namespace lts
    4922          21 : } // end namespace mcrl2

Generated by: LCOV version 1.12