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

Generated by: LCOV version 1.13